Hi Allz, arbeite mich seit einigen Wochen in die Hard- und Software rund um den Atmel ein. Nachfolendes Codebeispiel hab ich im Web (http://www.avr-asm-tutorial.net/) gefunden: (Bemerkungen stammen von mir) .include "2313def.inc" .DEF mp = R16 .DEF z1 = R0 rjmp main main: ldi mp,LOW(RAMEND) ;Stack out SPL,mp ;einrichten ;ldi mp,HIGH(RAMEND);haben aber ;out SPH,mp ;8bit ldi mp,0 ;laden 0 in R16 mov z1,mp ;und ab nach R0 -> R0-R15 kann man nicht direkt addressieren ldi mp,0x05 ;Wert 5 out tccr0,mp ;'in Timer schreiben ->Takt / 1024 ldi mp,0b00000010 ;LED an Pin15 als out ddrb,mp ;Ausgang schalten ldi mp, 0x00 ;LED out portb, mp ;ist aus loop: in mp,TCNT0 ;lade in R16 Inhalt von TCNT0 (TimerControl Register 0) cpi mp,0 ;vergleiche ob 0 brne loop ;wenn nicht loope rcall IncZ1 ;ab nach IncZ1 rcall Display ;ab nach Display warte: IN mp,TCNT0 ;lade in R16 Inhalt von TCNT0 (TimerControl Register 0) cpi mp,0 ;vergleiche ob 0 breq warte ;Schleife warte bis Wert 0 hat rjmp loop ;ab nach loop IncZ1: INC z1 ;Wert in Z1 um eins erhöhen ret Display: mov mp,z1 ;Wert von z1 nach mp kopieren com mp ;bitweise invertieren - aus 1 wird 0 ... out portb,mp ;schreiben wir in PortB ret Was ich nicht verstehe ist das Schleifenkonstrukt. Bis zur Subroutine loop ist mir eigentlich alles klar. In Loop wird gewartet bis im TimerControlRegister 0 der Wert 0 erreicht wird. Dann wird Z1 in der Subroutine um 1 erhöht. Frage 1: Warum? Anschliessend wird die LED in der Display Routine ein- bzw. ausgeschaltet. Frage 2: Warum wird in der Display Routine der Inhalt von z1 in mp kopiert? Invertierung und Ausgabe sind wieder klar. So, jetzt läuft das Programm in die warte Routine. Hier wird wieder auf den Timer 0 gewartet, oder? Diesmal halt anders umgesetzt, ich vermute mal zu Lernzwecken um die unterschiedlichen Methoden zu demonstrieren. Anschliessend wieder nach loop springen. Versteh ich das richtig: Nach jeder Änderung in der Display Routine wird 3 X Taktfrequenz/1024 gewartet? Fragen über Fragen, ich hoffe jemand liest sich diesen Roman überhaupt durch. Gruss
Erste Anmerkung: loop ist keine Subroutine, sondern nur ein Sprunglabel. Das BASIC-Äquivalent ist Ziel einer GOTO-Anweisung. IncZ1 und Display sind Subroutinen (die nämlich werden mit rcall aufgerufen) und enden folglich mit ret. Das BASIC-Äquivalent ist das Ziel einer GOSUB-Anweisung.
Hallo, >Was ich nicht verstehe ist das Schleifenkonstrukt. Bis zur Subroutine >loop ist mir eigentlich alles klar. In Loop wird gewartet bis im >TimerControlRegister 0 der Wert 0 erreicht wird. Dann wird Z1 in der >Subroutine um 1 erhöht. Frage 1: Warum? Zweck dieses Programm ist es, die LED blinken zu lassen. Dazu wird Z1 fortwährend hochgezählt ("inkrementiert"): 0, 1, 2, 3 ... 254, 255, 0, 1, 2 ... ohne Ende wiederholt (Sprung von 255 auf 0 klar?). Aus diesem Dauer-Inkrementieren kann man nun leicht ein Blinken (An-Aus-An-Aus...) "ableiten", indem man einfach nur ein einzelnes Bit von Z1 betrachtet: Jedes der acht Bits von Z1 "blinkt" nämlich! Aber nicht alle gleich schnell, sondern jedes Bit eins weiter links blinkt mit der halben Frequenz. In dem Codebeispiel wurde über die Zeilen ldi mp,0b00000010 ;LED an Pin15 als out ddrb,mp ;Ausgang schalten das Bit Nummer 1 ausgewählt (an Pin 1 ist dann die LED angeschlossen). Ersetzen der "0b00000010" durch z. B. "0b01000000" und Umstecken der LED auf Pin 6 würde zu einem 32 mal langsameren Blinken führen (32 klar? Von 1 bis 6 sind 5 Schritte und 2^5 = 32). >Anschliessend wird die LED in >der Display Routine ein- bzw. ausgeschaltet. Korrekt; die LED zeigt den Zustand des Bits Nr. 1 der Variablen Z1 an. >Frage 2: Warum wird in der >Display Routine der Inhalt von z1 in mp kopiert? Invertierung und >Ausgabe sind wieder klar. Von mp wird das Einerkomplement gebildet (d. h. alle Bits von mp werden getoggelt). Diese Operation möchte man nicht auf Z1 durchführen, weil man Z1 unverändert lassen will. Deshalb dupliziert man den Inhalt in von Z1 in mp und kann dann mit mp machen, was man will (sonst müßte man die Änderung an Z1 wieder rückgängig machen -> fehleranfällig -> nicht gut). >So, jetzt läuft das Programm in die warte >Routine. Hier wird wieder auf den Timer 0 gewartet, oder? Diesmal >halt anders umgesetzt, ich vermute mal zu Lernzwecken um die >unterschiedlichen Methoden zu demonstrieren. Nein, nicht zu Lernzwecken. Der Timer läuft mit einem Vorteiler von 1024. Wenn das Progamm aus der Displayroutine "zurückgekehrt" ist, hat der Timer deshalb immer noch den Stand Null! Er wird ihn auch noch für einige Zeit (geschätzt 1000 Taktzyklen) lang behalten, bis er endlich auf 1 springt. Eben dieses Springen auf die 1 wird in der Warteroutine abgewartet. Also: Der Zähler zählt nach dem Muster 0, 0, 0, ..., 0, 1, 1, 1, ..., 1, 2, 2, 2, ... 2, 3, 3, 3 ....... ^ (wobei die "..." für je 996 mal die Zahl stehen; von einer Zahl zur nächsten = ein Quarztakt) aber der Z1-Zähler soll nur beim Auftreten der ERSTEN Null (die mit "^" markierte) inkrementiert werden, und nicht beim Auftreten ALLER Nullen. Um dies zu erreichen, ist die "warte"-Schleife notwendig.
@Santa Klaus: Vielen Dank für deine Ausführungen, das meiste hab ich nun kapiert! Lediglich die Ausführung der zweiten "warte" Schleife ist mir noch nicht so klar. Könntest du nochmal bitte auf deine Ausführungen eingehen: >Nein, nicht zu Lernzwecken. Der Timer läuft mit einem Vorteiler von >1024. Wenn das Progamm aus der Displayroutine "zurückgekehrt" ist, >hat der Timer deshalb immer noch den Stand Null! Er wird ihn auch >noch >für einige Zeit (geschätzt 1000 Taktzyklen) lang behalten, bis er >endlich auf 1 springt. Eben dieses Springen auf die 1 wird in der >Warteroutine abgewartet. Also: Der Zähler zählt nach dem Muster > >0, 0, 0, ..., 0, 1, 1, 1, ..., 1, 2, 2, 2, ... 2, 3, 3, 3 ....... >^ > >(wobei die "..." für je 996 mal die Zahl stehen; von einer Zahl zur >nächsten = ein Quarztakt) Danke für deine Bemühungen und die Geduld!
Mhh, arbeitest Du vielleicht mit dem AVR Studio? Dann wäre es am einfachsten, wenn Du einfach mal im Simulator verfolgen würdest, wie sich das mit der Zählerei verhält. Du würdest die Sache dann sofort verstehen (kannst ja die warte-Schleife auskommentieren und gucken, was passiert). Kannst Du diesen Vorschlag realisieren? PS: Den Simulator brauchst Du eh, wenn Du ernsthaft programmieren willst. Da wäre das direkt eine gute Gelegenheit, sich mit diesem in allen "Krisensituationen" äußerst nützlichen Werkzeug vertraut zu machen.
Hi, ich werd mir das Studio mal besorgen und sehen wie weit ich komme. Danke für den Tip. Gruss
@Santa Klaus: Danke nochmal, ich glaub jetzt sitzt es! Gruss
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.