Moin Moin hier stelle ich ein paar Routinen rein, mit denen es sich hoffentlich leicht arbeiten lässt. SW AVRStudio4.19 Build 716 HW STK500 Sprache Assembler Die zip enthält Grundlagenquellcode für folgende Peripherie des Atmega8 ADC AnalogComparator EEprom Externe Interrupts UART um rs232 aufzubauen TimerCounter T0-T2 Die origin.asm ist die Hauptdatei mit der ich simuliert und gestest habe. 3 Peripheriegruppen fehlen SPI 2Wire SPM Vielleicht finden sich weitere Leute die es auf andere AVRs mitaufbohren Gruß Chris
Hallo, schön, das du deinen Code mit uns teilst, allerdings ist mir gleich aufgefallen, das du in keiner Funktion auch nur irgend ein Register sicherst/wiederherstellt, was nach meinem Verständnis in grundlegendes Vorgehen beim Programmieren von Funktionen in ASM sein sollte. Was ist der Grund dafür? Gruß Kai
von welchen registern sprichst du denn genau ? weil in den initsätzen ists egal ob ichs sicher oder net und die wichtigen daten sind alle auf dem ram abgelegt und somit sind die register wieder frei wenn das unterprogramm verlassen wird. siehe: .equ ocr2s = $0063 ;für T2 .equ ocra1h = $0064 ;;;;; .equ ocra1l = $0065 ;;;;;;;; für T1 A channel .equ ocrb1h = $0066 ;;;;; .equ ocrb1l = $0067 ;;;;;;;; für T1 B channel .equ icr1xh = $0068 ;;;;; .equ icr1xl = $0069 ;;;;;;;; für T1 ICR .equ hadc = $006a ;adc .equ ladc = $006b ;adc .equ eep_adrh= $006c ;eeprom .equ eep_adrl= $006d ;eeprom z.B.: EEPROM 1. Anwender ermittelt daten sollten dann im temp0 stehen 2. eeprom_write/read temp0>>eeprom/ eeprom>>temp0 3. Adresse (eep_adrh:eep_adrl) vorbereiten für die nächsten daten 4. springe zu 1 und damit liegen die wichtigen sachen auf dem Ram ausser temp0 aber da weiß ich doch nicht was der nutzer wie machen möchte, brauch er nur 1byte oder nbytes und die entsprechende schleife schreiben sollte dann nun auch nicht das problem sein dort könnte man ja denn die Pointer nutzen die der AVR hat siehe routine SRAM.
Hi >.equ ocr2s = $0063 ;für T2 >.equ ocra1h = $0064 ;;;;; >.equ ocra1l = $0065 ;;;;;;;; für T1 A channel >.... Das macht man nicht so. Laß den Assembler sich selbst um die Adressen kümmern. Also:
1 | ocr2s: .byte 1 |
2 | ocra1h: .byte 1 |
3 | ocra1l: .byte 1 |
4 | ... |
Oder z.B.:
1 | ... |
2 | adc_value : .byte 2 |
3 | |
4 | // dann so einlesen: |
5 | |
6 | in temp0,adcl |
7 | sts adc_value,temp0 |
8 | in temp1,adch |
9 | sts adc_value+1,temp1 |
Lies dir mal in der Hilfe zum Assembler AVR Assembler->User's Guide->Directives durch. Bei den Namen der Interruptvektoren würde ich mich an das Datenblatt halten. MfG Spess
chris schrieb: > die > wichtigen daten sind alle auf dem ram abgelegt und somit sind die > register wieder frei wenn das unterprogramm verlassen wird. Ja, das ist klar, aber was ist, wenn der Nutzer z.b. R17 im Hauptprogramm auch benutzt da Daten drin stehen hat und jetzt die Daten von R16 (temp0) in den EEPROM schreiben möchte. Dann ruft er die die Routine EEPROM_write: auf, legt damit die Daten in den EEPROM, verliert dabei aber die Daten, die ursprünglich in R17 gestanden haben, da das Unterprogramm die Daten überschrieben hat und seinen nicht mehr benötigten Wert darin stehen lässt. Hier der Ausschnitt aus deinem Code:
1 | EEPROM_write: |
2 | sbic EECR,EEWE ;** falls eewe im eecr noch gesetzt |
3 | rjmp EEPROM_write ;** spring zu zurück |
4 | lds r18,eep_adrh |
5 | out EEARH, r18 ;highbyte der adr |
6 | lds r17,eep_adrl |
7 | out EEARL, r17 ;lowbyte der adr |
8 | out EEDR,r16 ;zu speichernder wert |
9 | sbi EECR,EEMWE ;sperrt eeprom master write enable |
10 | sbi EECR,EEWE ;setze EEWE um eeprom zu schreiben |
11 | ret |
Schöner und sicherer wäre es, wenn das Unterprogramm die verwendeten Register zu beginn sichern würde und am Ende wiederherstellen. Einfach so:
1 | EEPROM_write: |
2 | push r17 |
3 | in r17, SREG |
4 | push r17 |
5 | push r18 |
6 | |
7 | sbic EECR,EEWE ;** falls eewe im eecr noch gesetzt |
8 | rjmp EEPROM_write ;** spring zu zurück |
9 | lds r18,eep_adrh |
10 | out EEARH, r18 ;highbyte der adr |
11 | lds r17,eep_adrl |
12 | out EEARL, r17 ;lowbyte der adr |
13 | out EEDR,r16 ;zu speichernder wert |
14 | sbi EECR,EEMWE ;sperrt eeprom master write enable |
15 | sbi EECR,EEWE ;setze EEWE um eeprom zu schreiben |
16 | |
17 | pop r18 |
18 | pop r17 |
19 | out SREG, r17 |
20 | pop r17 |
21 | |
22 | ret |
Damit wird keines der Register für das Hauptprogramm verändert, sprich es macht für die Register keinen Unterschied, ob das Unterprogramm aufgerufen wurde, oder nicht. Weiter könnte man auch noch den Parameter über den Stack übergeben, dann müsste er nicht in einem speziellen Register stehen, das der Programmierer kennen muss. Gruß Kai
@ spess53 jo bin mit diesen deklarationen so aufgewachsen und wenn man das im Studio mal durchsimuliert findet man die dinger im ram einfach schneller weil man sich einmal bewusst mit der zuordnung befassen muss. finde ist geschmackssache weil das ziel das gleiche bleibt. @Kai S. (kai1986) ich persönlich progge so das die register verworfen werden können bevor sie in das U-prog eintreten.
Das war chris seine Version ... Das war Kai seine Version .... und jetzt definiert mir bitte mal Grundlagen :
Sieht für mich alles etwas nach: "Ich habe gerade mal was gelernt, nun bin ich Profi und will Forenguru werden" aus. Sorry, aber diese Routinen gibt's 1000mal besser geproggt und/oder stehen in jedem App Note. Code, den die Welt nicht braucht - aber Hauptsache, das Wort "aufbohren" taucht auf. Amen.
Hi >jo bin mit diesen deklarationen so aufgewachsen und wenn man das im >Studio mal durchsimuliert findet man die dinger im ram einfach schneller >weil man sich einmal bewusst mit der zuordnung befassen muss. >finde ist geschmackssache weil das ziel das gleiche bleibt. Hört sich eher nach nach dem Motto :'Warum einfach wenn es umständlich geht' an. Es gibt im Debugger die Watch-Liste. Da brauchst du nur das Label eintragen und der Inhalt wird angezeigt. Ehrlich gesagt, würde ich dein Code keinem Anfänger empfehlen. MfG Spess
Esoteriker schrieb: > Das war chris seine Version ... > Das war Kai seine Version .... Der Dativ isch dem Genetif sei dod! chris schrieb: > ich persönlich progge so das die register verworfen werden können bevor > sie in das U-prog eintreten. Wie soll das aussehen? Wird dann alles auf den Stack gepusht, bevor Du das Unterprogramm aufrust? Wie umständlich. Es hat sich nicht ohne Grund durchgesetzt, alle nötigen Register beim Unterprogramm aufruf zu retten und nach der Abarbeitung diese wieder herzustellen. Ich glaube auch nicht, dass Du bei komplexeren Geschichten den Überblick behalten kannst. Aber das wirst Du sicher noch lernen, wenn Du über die Phase des APP-Notes-Abtippen gekommen bist.
@paul Du solltest besser an suizid denken und mein geni.. geht dich echt nichts an.
@ µC Programmierer lag die banane schon wieder vor dem käfig? >> Sorry, aber diese Routinen gibt's 1000mal besser geproggt und/oder >> stehen in jedem App Note. na siehste also kopierste auch nur 1:1 und bekommst es bestimmt 1000mal besser hin... denn wie will man es auch anders machen sind ja appnotes. @ Paul Also über meine komplexen schaltungen kann nur sagen läuft und läuft und läuft...... der Grund ist eigentlich ganz einfach nach etwas längerer pause hab ich meine projekte mal durchgeschaut und gewisse sachen kommen ja immer wieder vor, somit dachte ich mir schreibste dir mal selber entsprechenden quellcode zu der entsprechenden peripherie (gibs ja auch für hochsprachen) dabei ist das rausgekommen. Das dass alles absolut nicht perfekt ist, ist mir wohl bewusst. @ Esotoriker >> Das war chris seine Version ... >> Das war Kai seine Version .... Esotorikerversion lautet doch gleich? @datenschrott Leider meinen einige sich äussern zu müssen obwohl die baudrate falsch eingestellt ist. Die einzigen die sauber argumentieren sind spess und kai. vielleicht kanns trotzdem einer gebrauchen.
Ein Moderator liest hier mit und lässt den Suizid-Kommentar einfach stehen. Ich bin fassungslos.
Thomas schrieb: > Ein Moderator liest hier mit und lässt den Suizid-Kommentar einfach > stehen. > Ich bin fassungslos. Ich denke, er spricht für sich. Die eigentliche Frage ist: soll sowas in der Codesammlung sein oder nicht? Auf der anderen Seite hat jeder das Recht dazu, hier etwas zu veröffentlichen.
Paul schrieb: > Es hat sich nicht ohne Grund durchgesetzt, alle nötigen Register beim > Unterprogramm aufruf zu retten und nach der Abarbeitung diese wieder > herzustellen. Nö, hat sich nicht durchgesetzt. Man definiert sich einige Scratchpad-Register, die zerstört werden dürfen. C-Compiler wie der AVR-GCC machen das auch. Spart ne Menge Code ein und macht den Code übersichtlicher, als unnötige Push/Pop-Orgien. Auch nimmt man die Scratchpadregister für die Parameterübergabe. Oft braucht der Aufrufer die Argumente nicht mehr nach dem Aufruf, wozu also unnütz wiederherstellen. Z.B. ich übergebe ein Byte an die UART-Senderoutine, danach ist mir das Byte schnuppe.
P.S.: Oder Funktionen liefern Werte, dann muß man Register zerstören. Und dann nimmt man praktischer Weise solche Register, die man als zerstörbar vereinbart hat. Ansonsten müßte der Aufrufer erst umständlich einen Pointer übergeben, wo das Ergebnis hingespeichert werden soll, nur damit ja kein Register seinen Wert ändert.
... zerstörbare Regeister ... Der Begriff gefällt mir :-) Gern nutze ich dieses Verfahren bei meinen Projekten: .def ERGEBNIS = R10 .def NULL = R12 "unzerstörbar" .def EINS = R14 "unzerstörbar" .def VOLL = R15 "unzerstörbar" .def temp = R16 "zerstörbar" .def temp1 = R17 "zerstörbar" .def temp2 = R18 "zerstörbar" .def temp3 = R19 "zerstörbar" .def temp4 = R20 "zerstörbar" .def temp5 = R21 "zerstörbar" .def temp6 = R22 "zerstörbar" .def temp7 = R23 "zerstörbar" .def temp8 = R24 "zerstörbar" .def temp9 = R25 "zerstörbar" Ich persönlich arbeite gern mit dem "Baukastenprinzip", Beispiel : "AUSGABE_ZAHL_5_STELLEN_FORMATIERT_TEMP1_2" "AUSGABE_ZAHL_10_STELLEN_FORMATIERT_TEMP1_4" im Projekt: Beitrag "Spektrumanalyser Frequenzspektrometer Eigenbau bis 1MHz" Die Parameter werden in temp1+temp... übergeben, die Registerinhalte sind natürlich anschließend zerstört. Das "Baukastenprinzip" hat den Vorteil, dass die Routinen (meist ohne große Anpassung)auch für andere Projekte verwendet werden können. Neuerdings schreibe ich gerade bei Ausgangsfunktionen die Registernamen mit dazu. Beispiel: "EEPROM_READ_PLUS_TEMP1", hier sieht man sofort, in welchem Register sich der Output befindet. Erspart das Nachschauen in der Routine. Nachteil des "Baukastenprinzipes": Der Programmcode benötigt mehr Platz und mehr Takte. Bernhard
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.