Da gibt es noch "sei", den ich am Anfang vom Programm ausführe, also nachdem ich den Timer0 intitialisiere.
Bin gespannt, wann Sebastian wieder kommt, hab mich schon ein wenig über Timer1 informiert
Hallo Thomas!
Das klingt schon gut!
Naja, so ganz richtig ist das nicht, aber im Prinzip schon!Denn nur nach dem Befehl "reti" können Interrupts wieder ausgelöst werden, deshalb muss dieser Befehl so schnell wie möglich auftreten.
reti ist einer der Befehle, nach denen Interrupts wieder ausgelöst werden können!
Welchen Befehl kennst Du für diese Funktion noch?
Du hast ihn schon immer selbstverständlich verwendet! ;o)
Da gibt es noch "sei", den ich am Anfang vom Programm ausführe, also nachdem ich den Timer0 intitialisiere.
Bin gespannt, wann Sebastian wieder kommt, hab mich schon ein wenig über Timer1 informiert
Hallo, Leute
So wie ich sehe hast Du Thomas eine super Antwort gegeben, das ist der Grund!
Wenn Du anfängst im Interrupt delays zu machen, hin und her zu springen,
kommt kein anderer Interrupt zum Zuge,
Schön, daß Sprinter die Sache mit SREG angesprochen hat,
aber es war wieder meine Schuld, ich habe die Rettung von SREG zwischendurch
rausgeschmissen(sehe die Programme weiter oben), um den Thomas damit nicht zu verwirren, ich wollte damit heute kommen, nachdem er diese Aufgabe gelöst hat .
Naja ich werde den SREG hier nicht weiter ansprechen, das kann sich jeder unter
http://www.avr-asm-tutorial.net/avr_...ner/index.html durchlesen, ich sage nur, daß das ergebnis jeder mathematischen Operation, die man macht im SREG abgebildet wird.
Thomas Du hast ja Studio, dann schreib Dir einfach ein Miniprogramm, wo zb brne vorkommt
zb
ldi tmp,0x80
cpi tmp,0x90
brne hierhin
naja so was in der Art, dann geh Zeile für Zeile Durch, und beobachte den SREG und vor allen wenn Du die Werte änderst, was dann passiert, dann lese nach, was Die Bits von SREG zu bedeuten haben.
Der µC macht seine Sprünge anhand des SREGs und wenn Du ihn im Interrupt änderst,
dann hat er ganz anderen Wert wenn er zurückkommt,
Thomas hast Du schon was von Stack gehört ?
Tachschen Sebastian
Jo, vom Stack hab ich schonmal was im Tutorial gelesen. Das ist doch, wenn ich Unterprogramme aufrufe, dann merkt er sich im Stack, wo er hergekommen ist, wenn ich vom Unterprogramm wieder ein Unterprogramm aufrufe, schreibt er es in den Stack auch wieder rein. Stößt er dann auf den Befehl "ret", dann springt er Schritt für Schritt wieder zurück (in der umgekehrten Reihenfolge).
Hoffe mal, das stimmt einigermaßen so.
Gruß
Thomas
[edit]
Das mit dem SREG versteh ich nun auch viel besser durch die Simulation im AVR Studio
Ja genau, so in etwa sieht es aus.
Stack wird einfach am Ende von SRAM eingerichtet ( deswegen dieses RAMEND)
und wird benutzt um irgendwas eben kurz zwischenzuspeichern.
Die erste Möglichkeit hast Du schon genannt, bei rcalls speichert der µC die Adresse, wo er anschließend zurückspringen soll auf dem Stack und bei ret holt er sie sich wieder um zu wissen wo jetzt hin.
Das macht er auch bei Interrupts, da landet die Rücksprungadresse auch auf dem Stack.
Eine Eigenschaft vom Stack ist aber, daß ich nur was obendrauf werfen , oder nur was von oben hollen kann. an Sachen die dazwischen liegen komm ich nicht dran, ist wie ein Stapel
Bettonplatten, ich muß immer von oben entnehmen, oder obendrauf legen, kapito?
Jetz kommt eine schöne Sache, wo man den Stack benutzen kann.
bei Eintritt in die Interruptroutine hast Du den SREG in einen Register zwischengespeichert, gut, nur was machst Du wenn Du keinen Register mehr übrig hast?
Dann nimmst Du den Stack!
es geht so:
in tmp,SREG ;kopiere Inhalt von SREG in tmp
push tmp ;lege Inhalt von tmp auf den Stack
............ Hier folgt das Programm
pop tmp ;Hole die Spitze, also die oberste Stelle vom Stack und schreibe es in tmp
out SREG,tmp ; Gerettet!
reti
aber bevor wir einen RIESEN großen Fehler machen nochmal
das Gleiche, nur etwas kommt noch dazu:
push tmp ;lege tmp auf den Stack
in tmp,SREG ;kopiere Inhalt von SREG in tmp
push tmp ;lege Inhalt von tmp auf den Stack
............ Hier folgt das Programm
pop tmp ;Hole die Spitze, also die oberste Stelle vom Stack und schreibe es in tmp
out SREG,tmp ; Gerettet!
pop tmp ;Auch geretet!
reti
Kannst Du sagen, wo der unterschied ist, und was passiert wenn man den erste Code nimmt?
Puhh...
also ich bevorzuge den 2 Code Warum? Weil beim 1 Code der aktuelle Inhalt von tmp verloren geht, nachdem er wieder aus der Interruptroutine rausspringt. Denn wir speichern den aktuellen Code von tmp nirgends. Wir überschreiben ihn gleich mit SREG.
Das ist beim 2 Code richtig gelöst. Da bekommen wir alles wieder, nachdem die Interruptroutine durchlaufen ist.
So ist es, wie Du siehst ist der Stack eine echt gute Sache um eben irgendwas zwischenzuspeichern, nur auf eine Sache muß man wirklich achten, wenn man den Stack
verwendet, und zwar muß die Anzahl der push der Anzahl der pops entsprechen, sonst müllst Du Dir den Ram zu und irgendwann ist der komplett zu.
Was noch schlimmer ist liegen bei Mega 8 im Ram bis zu Adresse 0x60 (hoffe ich, habe keine Lust jetzt genau nachzuschauen) Inhalte aller Register also R1 - R31 alle Ports, PINS ,DDRs usw.
da schreibt der µC gnadenlos rein! Es wird nicht geprüft, was da passiert.
Welche Folgen das hätte kannst Du Dir vorstellen.
Jo, denk schon, Er ändert dann im schlimmsten Fall die Register und/oder die Ports, die ich auch verwende und die LEDs oder was auch immer blinken nicht so, wie ich es möchte.
Jo, genau, der AVR läuft Amok , ausprobiert habe ich es noch nicht,
also aufpassen, und vor allem auch auf die Reihenfolge achten, so wie das schon in
der Bibel steht, die Letzten werden zu Ersten,
beim zurückholen zuerst das was man als letztes abgelegt hat.
Hast Du noch Fragen zu den Sachen, die Du bis jetzt gelernt hast?
Hast Du alles verstanden, ich fasse nochmal zusammen:
Programmablauf -
fängt bei Adresse 0x000 an und arbeitet sich zeile für zeile nach unten
Labels also diese loop: oder was Du Dir da ausdenkst sind keine
Funktionen in dem sinne, sondern nur kleine Markierungen im
Programm um die adresse später einfacher anzuspringen
Register -
Register R1-R31 können mit Werten geladen werden um sie dann weiter in andere Register,Ports zu schreiben.
Register kann man als Variablen nutzen.
Bedeutung von .org .def .equ und wie sie uns das Leben einfacher machen.
Bitmanipulationen mit (1<<PB1) z.B oder (1<<PB1) | (1<<PB2)
interrupts, gefahren und nutzen
SREG Bedeutung
Stack Bedeutung und gefahren.
Timer , Takt vom Quarz und wie man daraus irgendeinen anderen Takt bekommt
Branches (breq,brne usw.), wie sie arbeiten und was sie mit SREG zu tun haben
Waren das alle Themen?
Wie ich sehe, haben wir schon jedemenge durch was ?
Es ist wirklich wichtig, daß Du das alles verstehst!
P.S.
Es sind keine Fragen, nur eine Zusammenfassung
Gruß Sebastian
Hui, ist wirklich schon ne Menge, denkt man ja gar nicht, dass man schon so viel kann.
Soweit ist alles klar, außer (das muss ja immer sein *g*):
Bitmanipulationen mit (1<<PB1) z.B oder (1<<PB1) | (1<<PB2)
Also das erste ist klar. Er verändert das Bit an der Stelle PB1. Dann würde daraus dann 0b00000010 das hier werden, oder eben dann wieder alles auf 0, je nach Befehl.
"(1<<PB1) | (1<<PB2)" <-- bei dem hier. Ist das sone Art UND-Befehl?
Also wird dann daraus 0b00000110 das hier?
[edit]
So, ich muss dann los zum bowlen. Bin heut abend so gegen 23:00 - 23:30 denk ich wieder hier.
Gruß
Thomas
Lesezeichen