Guten Tag.
Habe das Problem das ich mit bei Assembler daher das ich grad erst
angefangen habe erstmal ein 64er Lauflicht gebaut habe und er bei diesem
immer sagt: "AVR Simulator: Stack pointer below start of RAM"
Das Programm lautet:
;Test
.include "m8def.inc" ; AtMega8 laden
.def temp1 = r16 ; Register r16 als temp1 benennen
.def temp2 = r17 ; Register r17 als temp2 benennen
.def temp3 = r18 ; register r18 als temp3 benennen
rjmp Reset
Reset:
ldi temp1, 0xFF ; Register temp1 mit 0xFF beschreiben
ldi temp2, 0x01 ; Register temp2 mit 0x01 beschreiben
ldi temp3, 0xFE ; Register temp3 mit 0xFE beschreiben
out DDRB, temp1 ; Ausgangsregister DDRB mit 0xFF
out DDRD, temp1 ; Ausgangsregister DDRD mit 0xFF
Loop:
out PORTD, temp3 ; Über PORTD Inhalt von temp3 ausgeben
out PORTB, temp2 ; Über PORTB Inhalt von temp2 ausgeben
lsl temp2 ; 0 in Ihnalt von temp2 einschieben
brcs Zeile ; wenn C Flag 1, Zu Prog. Zeile springen
ldi temp1, 0x01 ; Register temp1 mit 0x01 beschreiben
rcall Warte ; Zu Prog. Warte springen
Zeile:
ldi temp2, 0x01 ; Register temp2 mit 0x01 beschreiben
rol temp3 ; 1 in Inhalt von temp3 einschieben
brcc Reset ; wenn C Flag 0, zu Prog. Reset springen
rjmp Loop ; Zu Prog. Loop springen
Warte:
dec temp1 ; Inhalt von temp1 um 1 veringern
nop ; einen Tackt nichts tun
brne Warte ; wenn Z Flag 0, zu Prog. Warte springen
rjmp Loop ; Zu Prog. Loop springen
Und der Curser steht in diesem Fall immer auf "dec temp1"
Währe nett wenn mir jemand helfen könnte.
(Ggf. auch sagen wie ich den Code in eine Extra Box lege, sodass ich es
nachträglich bearbeiten kann.)
Ich glaube nicht, dass das für so ein Minimalprogramm, was keine
Interrupts enabled (kein "sei" hinter "Reset:") und keine rcall-Aufrufe
macht, so etwas braucht, aber jedes Programm, was über ein Ansteuern
einer LED hinaus geht, muss am Anfang den Stack-Pointer initialisieren:
Reset:
ldi r16,high(RAMEND); Main program start
out SPH,r16 ; Set Stack Pointer to top of RAM
ldi r16,low(RAMEND)
out SPL,r16
(Mich wundert nur, dass der Simulator da moppert.)
Reicht es wenn ich diese Initialisierung nur einmal mache oder muss der
da dauernt drüber laufen?
Verstehe das Kapitel Stack aus dem Tutorial leider nicht so ganz ...
Hab grad auch nochmal ein wenig mit Rumversuchen versucht, kriege es
aber irgendwie nicht hin ... Habe anstatt r16 r19 genommen, falls das
wichtig sein sollte.
Hi
>Reicht es wenn ich diese Initialisierung nur einmal mache oder muss der>da dauernt drüber laufen?
Nein, nur ein mal. Den Rest macht der Controller.
MfG Spess
Hmm .. habe nun das mit dem Stack eingebastelt wie hier geschrieben und
das rcall Loop durch ret ersetzt. Nur irgendwie funktioniert das
nichtmehr so wie vorher. Vorher hatte ich es so das ich PORTB die X
Achse und PORTD die Y Achse einer LED Matrix anschließen konnte und ich
ein Lauflicht hatte. Nun ist es so das die X Achse Läuft und die Y Achse
aber immer einer mehr leuchtet ...
;Test
.include "m8def.inc" ; AtMega8 laden
.def temp1 = r16 ; Register r16 als temp1 benennen
.def temp2 = r17 ; Register r17 als temp2 benennen
.def temp3 = r18 ; Register r18 als temp3 benennen
.def Stack = r19 ; Register r19 als Stack benennen
ldi Stack,high(RAMEND)
out SPH,Stack
ldi Stack,Low(RAMEND)
out SPL,Stack
rjmp Reset
Reset:
ldi temp1, 0xFF ; Register temp1 mit 0xFF beschreiben
ldi temp2, 0x01 ; Register temp2 mit 0x01 beschreiben
ldi temp3, 0xFE ; Register temp3 mit 0xFE beschreiben
out DDRB, temp1 ; Ausgangsregister DDRB mit 0xFF
out DDRD, temp1 ; Ausgangsregister DDRD mit 0xFF
Loop:
out PORTD, temp3 ; Über PORTD Inhalt von temp3 ausgeben
out PORTB, temp2 ; Über PORTB Inhalt von temp2 ausgeben
lsl temp2 ; 0 in Ihnalt von temp2 einschieben
brcs Zeile ; wenn C Flag 1, Zu Prog. Zeile springen
ldi temp1, 0x01 ; Register temp1 mit 0x01 beschreiben
rcall Warte ; Zu Prog. Warte springen
Zeile:
ldi temp2, 0x01 ; Register temp2 mit 0x01 beschreiben
rol temp3 ; 1 in Inhalt von temp3 einschieben
brcc Reset ; wenn C Flag 0, zu Prog. Reset springen
rjmp Loop ; Zu Prog. Loop springen
Warte:
dec temp1 ; Inhalt von temp1 um 1 veringern
nop ; einen Tackt nichts tun
brne Warte ; wenn Z Flag 0, zu Prog. Warte springen
ret ; Zu Prog. Loop springen
Villeicht kann das ja jemand mal Simulieren ... ich nutze AVRStudio4.
Info am Rande: Die Fehler zeigt er nur wenn ich auf "Run" gehe, nicht
aber wenn ich auf "Auto Step" gehe (ausser bei dem mit ret da zeigt er
den extra genannten Fehler bei beiden Varianten).
So kannst Du Dir das rjmp Reset auch sparen.
Versuche nicht zu frunzeln bis es geht, sondern versuche erst mal zu
verstehen, was Du machst. Dieses "rjmp Reset" ist eigentlich nur in
Programmen nötig, die mit Interrupts arbeiten, weil ganz vorne die
Interrupt-Tabelle liegt, deren erster Eintrag der Reset-Handler ist.
Normalerweise sieht ein Programmanfang auf einem ATmega8 so aus:
Du brauchst das alles nicht, da Du kein "sei" brauchst, bis Du anfängst,
das Lauflicht durch einen der Timer zu steuern.
Solange Du aber keinen Stack hast, kanst Du keine Unterprogramme (Warte)
benutzen, was in diesem Fall einfach durch Verschieben des
entsprechenden Codes an die Stelle seines Aufrufs gelöst werden kann.
Wie nutze ich so einen Timer?
Habe es so gemacht wie ich es verstanden habe. Und daher das manche
Dinge häufig und nur in bestimmten Situtationen abgerufen werden habe
ich mir Unterprogrammen gearbeitet. Bekomme es irgendwie nicht zum
laufen und zusätzlich hat er plötzlich PIND ein Low wo an PORTD ein Low
ist .... wie geht das? ^^
spess53 schrieb:>>SPM_RDY:>>> iret>>>> Besser 'reti'
Kann zufällig jemand die Begriffe erklären .. ^^ (Bedeutung Funktion).
Will schon auch verstehen und nicht nur Copy and Paste machen ^^.
Wenn ich alle rcall in meinem Programm durch rjmp ersetze funktinierts
.. was ist der Unterschied zwischen diesen beiden befehlen?
Zudem wollte ich nochmal gerne fragen ob man während das Prog. auf "run"
steht irgendwie die Zustände der Aus/Eingänge sehen kann.
Hi
>Kann zufällig jemand die Begriffe erklären .. ^^ (Bedeutung Funktion).
Welche?
Wenn du
rjmp RESET ; Reset Handler
rjmp EXT_INT0 ; IRQ0 Handler
...
meinst. Das findest du im Datenblatt unter Interrupts.
'reti' und alle anderen Befehle in der Hilfe zum Assembler vom
AVR-Studio unter 'Instructions' oder hier
www.atmel.com/atmel/acrobat/doc0856.pdf
MfG Spess
Bei rcall wird die Adresse für den Rücksprung in den Stack geschrieben.
Bei ret wird die Adresse vom Stack geholt und dahin Gesprungen.
Dem ret ist es egal ob im Stack an der Position eine Adresse steht,
er versucht trotzdem dahin zu Springen und kann irgendwo im Programm
Landen!
Hi
>Wenn ich richtig verstanden habe geht dies ret also nur wenn ich "rcall">gemacht habe, aber nicht bei "brcc" oder "brne"
Richtig. 'rcall' und bei größeren AVRs auch 'call' springen zu dem
dahinter stehenden Label. Gleichzeitig wird die Adresse des
nachfolgenden Befehls auf dem Stack gespeichert. Beim Erreichen des
'ret' holt sich der Controller diese Adresse wieder vom Stack und macht
an der o.g. Stelle weiter.
Bei 'brxx', 'rjmp' und 'jmp' wird keine Adresse auf dem Stack
gespeichert. Also kann auch ein 'ret' nichts sinnvolles vom Stack holen.
MfG Spess
> Wenn ich richtig verstanden habe geht dies ret also nur wenn ich "rcall"> gemacht habe, aber nicht bei "brcc" oder "brne"
Ja, genau.
Ich habe das Gefühl, Dir ist das Konzept eines Stacks noch nicht so ganz
klar. Der Stack ist ein Stapelspeicher, wie ein Stapel Teller. Du legst
einen Teller A drauf, dann einen Teller B. Wenn Du die Teller wieder
herunter nimmst, kommt zuerst Teller B, dann Teller A.
Hier sind es jedoch keine Teller, sondern Bytes, die auf dem Stack
abgelegt werden. Wenn mit "rcall" ein Unterprogramm aufgerufen wird,
wird die aktuelle Stelle, an der das Programm gerade ist, also 2 Bytes,
auf dem Stack abgelegt, und dann wird zu der Adresse des Unterprogramms
gesprungen. Am Ende des Unterprogramms wird der oberste Teller vom
Stapel genommen, und dorthin zurück gesprungen. Der Befehl für beide
Aktionen ist "ret". Ein "reti" macht im Prinzip dasselbe, nur wird das
Flag, das Interrupts erlaubt, dabei gesetzt.
Der Stack wird repräsentiert durch den Stack-Zeiger, also einem
Register, in dem die Adresse des nächsten freien Platzes auf dem Stack
steht. Das bemerkenswerte bei diesem Stack ist, das die Teller quasi an
der Decke hängen, also der Stack am oberen Ende des Speichers anfängt,
und nach unten wächst. Deswegen die Initialisierung mit "RAMEND" (Ende
des RAM) am Anfang.
Der Stack wird aber nicht nur Rücksprungadressen verwendet, sondern
auch, um Werte zu sichern und sie später zu restaurieren. Mit "push r1"
legst Du den Inhalt des Wertes vom Register r1 auf dem Stack ab, mit
"pop r1" kannst Du dann den Wert wieder vom Stack holen. Das macht
besonders in Unterprogrammen Sinn, die durch Interrupts aufgerufen
werden, weil diese keine Register verändern dürfen, die woanders, also
möglicherweise in einem unterbrochenen Programmteil, gerade benutzt
werden.
> Was war das? .... Meinst jetzt dass das für AVR mit 32Bit war?
Nein, das war für 80x86 CPUs, wie sie auf PCs Verwendung finden. Der
erste Proz, für den ich (in den 80ern) Assembler programmiert habe, war
ein 8086. Irgendwie bleibt das haften und drängt immer wieder nach
außen. :-D
Ok .. wenn ich das alles nun richtig Verstanden habe war meine Aktion
das ich alle rcall durch rjmp ersetzt habe richtig, da ich immer am Ende
der unterprogramm Resete (Ganz von vorne anfange) oder Ein anderes
Unterprogramm/Hauptprogramm von vorne anfange.
Der Stack speichert bei einem rjmp die aktuelle Position sodass wenn man
ret eingibt er automatisch zu dieser Position zurückspringt und den
nächsten Befehl ausführt, welcher danach gekommen währe.
Zum Thema reti: Bei Interrupts bin ich nochnicht ^^.
Und zu dem mit dem pop und Push wollte ich nochmal frgaen: Wenn ich Push
genutzt habe dann kann ich aber kein ret mehr nutzen bis ich wieder ein
rcall hatte oder?
Michael Dierken schrieb:> Ok .. wenn ich das alles nun richtig Verstanden habe war meine Aktion> das ich alle rcall durch rjmp ersetzt habe richtig, da ich immer am Ende> der unterprogramm Resete (Ganz von vorne anfange) oder Ein anderes> Unterprogramm/Hauptprogramm von vorne anfange.
ja
> Der Stack speichert bei einem rjmp die aktuelle Position sodass wenn man> ret eingibt er automatisch zu dieser Position zurückspringt und den> nächsten Befehl ausführt, welcher danach gekommen währe.
nein der Stack speichert bei einem rcall o. call die 'Position'
> Zum Thema reti: Bei Interrupts bin ich nochnicht ^^.>> Und zu dem mit dem pop und Push wollte ich nochmal frgaen: Wenn ich Push> genutzt habe dann kann ich aber kein ret mehr nutzen bis ich wieder ein> rcall hatte oder?
ähm?!
du kannst ein ret vor einem rcall/call aufrufen, aber das hat nichts mit
push/pop zu tun
Wenn du mit rcall in ein Unterprogramm springst und dort push benutzt,
dann must du vor dem ret erst pop benutzen. Ebensowenig kannst du erst
push benutzen, dann mit rcall springen und dann pop benutzen.
Du hast die Funktion des Stack definitiv noch nicht verstanden.
Sascha
Hi
>Ok .. wenn ich das alles nun richtig Verstanden habe war meine Aktion>das ich alle rcall durch rjmp ersetzt habe richtig, da ich immer am Ende>der unterprogramm Resete (Ganz von vorne anfange)
Nein. Ein Reset als Folge eines 'ret' ist ein Programmabsturz! Außerdem
passiert das nur bei einem leeren Stack. Wenn sich etwas auf dem Stack
befindet geht das irgendwo ins Nirvana. Also:
rcall label
...
...
label: ...
...
...
ret
>Der Stack speichert bei einem rjmp die aktuelle Position sodass wenn man>ret eingibt er automatisch zu dieser Position zurückspringt und den>nächsten Befehl ausführt, welcher danach gekommen währe.
Nein. Das passiert bei rcall/call.
>Und zu dem mit dem pop und Push wollte ich nochmal frgaen: Wenn ich Push>genutzt habe dann kann ich aber kein ret mehr nutzen bis ich wieder ein>rcall hatte oder?
Nein. Wenn du in einem Unterprogramm ein oder mehrere Register auf den
Stack 'gepusht' hast müssen die vor dem 'ret' wieder mit 'pop' vom
Stack geholt werden:
Label: push r16
push r17
...
...
pop r17
pop r16
ret
MfG Spess
Hallo Michael
Ich glaube dir ist am besten geholfen, wenn man dir rät zuerst das
Tutorial abzuklappern. Mir hat das am Anfang am meisten gebracht, die
Themen einzeln und möglichst kurzschrittig auf einem Steckbrett
nachzuvollziehen und dann Änderungen im Code dazuzubasteln. Dadurch
kannst du selbst sehen welche effekte die änderungen haben - du hast
aber ein funktionierendes Programm als Ausgangspunkt.
Außerdem steht ganz viel nützliches Zeug im Datenblatt und es gibt auch
eine asm-Befehlsreferenz von Atmel im Netz (die hatte ich mir damals
ausgedruckt(!)).
Ich wünsche dir viel Erfolg und Freude beim "lernen"
Robert (seit 2 Jahren kein Anfänger mehr - aber noch lange kein Profi:))
Sascha Weber schrieb:> Du hast die Funktion des Stack definitiv noch nicht verstanden.
Deswegen frage ich ja nochmal ^^.
Habe ausversehen vorhin rjmp und rcall vertauscht .. meinete natürlich
das er bei rcall speichert.
Zu iche (Gast): Ja ich mache grad das Tutorial, aber überwiegend
Theoretisch, da die Hardware nochnicht da ist und da habe ich dann
einfach mal versucht soweit wie ich war mir ein 64Kanal Lauflicht zu
basteln ^^.
Vielen Dank für eure Geduldigen Antworten.
Auch wenn ich das mit push und pop nochnicht ganz verstehe:
Wenn ich dies Push mache, muss ich danach einfach nur das pop mit dem
gleichen Register machen?
So wie ich es zuvor verstanden habe kann man mit den push (Wert im
Register des Stack ablegen) da was reinschreiben was aber ja nicht mit
pop (Auslesen) wiederkommen würde.
push und pop haben nicht viel mit dem register zu tun auf welches sie
zugreifen/lesen
mit push schiebst du den inhalt des registers R (egal welches - du musst
halt eins nehmen) oben als letzten wert auf den stack
und mit pop lädst du den letzten wert auf dem stack in das register R".
R und R" können, müssen aber nicht das gleiche sein.
Meinst du mit R und R" sowas wie z.B. rr16 und r17?
Denke das ich den sinn so langsam kapiert habe .. muss mal ein wenig
rumprobieren, ggf. kommt das auchnicht im Tutorial ^^.
eigentlich kannst du immer nur 8bit (selbst) im sram (der stack befindet
sich im sram) ablegen. wie der SRAM genau aufgebaut ist, hab ich jetzt
nicht auf die schnelle gefunden (steht nicht direkt im datenblatt)
So aus dem Tutorial habe ich: SRAM 8bit - bei uC mit mehr als 256Byte
ram is der adresszähler dann natürlich breiter als 8bit (sonst könnte ja
die adresse $257 nie erreicht werden.
und wenn du 16/32/64 Bit auf dem Stack/Sram ablegen willst, musst du die
bytes eben alle nacheinander (in der richtigen reihenfolge) aufn Stack /
innen Sram packen.
aber bitte: fang klein und vor allem möglichst weit vort im tutorial an
- dann entstehen solche grundsatzlichen fragen nicht, und ich schreibe
mich nicht so in rage, dass ich gleich die groß-KLEINschreibung
vergesse^^
Michael Dierken schrieb:> Eine letzte Frage noch: Sehe ich das richtig das man max. 16Bit auf dem> Stack ablegen kann?
Du kannst auf dem Stack ablegen soviel du willst und solange der dafür
notwendige Speicher noch frei ist.
Am einfachsten macht man sich das Konzept eines Stacks (wieder mal) mit
Papier und Bleistift klar. Das weiter oben genannte Beispiel mit den
Tellern war schon nicht schlecht, trifft es aber konkret nicht so recht
Angenommen wir haben diesen Code
(die Zahlen in der linken Spalte geben an, wo genau im Speicher diese
Anweisung durch den Assembler abgelegt wurde. In deinem Programmtext
sind sie nicht vorhanden. Ich habe sie nur ergänzt um mich im Code auf
etwas beziehen zu können
1
0100 ldi r16, 0xAA
2
0102 ldi r17, 0x55
3
0104 rcall do_it
4
0106 ldi r18, 0x00
5
6
...
7
8
0200 doit:
9
0200 push r17
10
0202 push r16
11
0204 ldi r18, 0x02
12
0206 push r18
13
0208 pop r16
14
020A pop r17
15
020C pop r18
16
020E ret
der Stack sei symbolisiert, durch eine Spalte am rechten Bildschirmrand.
Wir wollen mal sehen, wie sich der entwickelt. Der Stackpointer sei
dabei ein Pfeil.
das Programm beginnt, der Stack wird initialisiert (nicht weiter
gezeigt) und irgendwann landet das Programm an der Adresse 0100
Hier ist der Stack
+------+
-->| |
+------+
die erste Anweisung
1
ldi r16, 0xAA
Register 16 wird mit 0xAA geladen, das hat keine Auwirkungen auf den
Stack, wir merken uns aber, dass in r16 0xAA steht
r16 r17 r18 +------+
+------+ +-------+ +-------+ -->| |
| AA | | | | | +------+
+------+ +-------+ +-------+
der Assembler hat schon dafür gesorgt, dass anstelle von do_it die
Adresse von do_it (0200) eingesetzt wurde. Für den Prozessor steht da
also ein Aufruf eines Unterprogrammes, das an der Stelle 0200 beginnt.
Damit beim ret wieder zum Aufrufer zurückgefunden wird, wird die
aktuelle Adresse der Ausführung (die schon durch die Befehlsverarbeitung
auf den Befehl nach den rcall gesetzt wurde) auf dem Stack gesichert.
der rcall steht auf Adresse 0104, der nächste Befehl steht auf 0106
nach Abarbeitung des rcall ist die Situation also so
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| AA | | 55 | | | +------+
+------+ +-------+ +-------+ | 01 |
+------+
-->| |
+------+
Auf dem Stack wurde die Adresse 0106 (in 2 Happen) abgelegt und die
Programmausführung geht bei 0200 weiter.
1
0200 doit:
2
0200 push r17
3
0202 push r16
4
0204 ldi r18, 0x02
5
0206 push r18
6
0208 pop r16
7
020A pop r17
8
020C pop r18
9
020E ret
die nächste Anweisung ist
1
push r17
r17 hat den Inhalt 55 und der wird als nächstes auf den Stack gepusht.
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| AA | | 55 | | | +------+
+------+ +-------+ +-------+ | 01 |
+------+
| 55 |
+------+
-->| |
+------+
pop ist die Umkehrung vom push. Das unterste (konzeptionell das zuletzt
abgelegte) Byte wird in das angegebene Register geholt. Hier ist das
jetzt 02, welches ins Register r16 geholt wird. Gleichzeitig wird dieses
Element auch vom Stack insofern entfernt, als der Stackzeiger sich
wieder um 1 Byte zurückbewegt. Dadurch werden zwar die 02 nicht aus dem
Speicher gelöscht, aber konzeptionell ist es 'nicht mehr auf dem Stack
vorhanden'.
Nach dem pop r16 sieht die Situation also so aus
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| 02 | | 55 | | 02 | +------+
+------+ +-------+ +-------+ | 01 |
+------+
| 55 |
+------+
| AA |
+------+
-->| |
+------+
1
pop r17
wieder: das letzte Byte am Stack wird nach r17 geholt
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| 02 | | AA | | 02 | +------+
+------+ +-------+ +-------+ | 01 |
+------+
| 55 |
+------+
-->| |
+------+
1
pop r18
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| 02 | | AA | | 55 | +------+
+------+ +-------+ +-------+ | 01 |
+------+
-->| |
+------+
und damit ist dann im nächsten Befehl der ret erreicht
1
ret
ret holt sich die letzten beiden Bytes vom Stack (wie auch immer die
dorthin gelangt sind) und nimmt sie als Adresse an der die
Programmausführung fortgesetzt werden soll. In diesem Beispiel sind die
beiden letzten Bytes 01 und 06. Zusammengesetzt ergibt das die Adresse
0106 und dort geht dann die Programmausführung nach dem ret weiter.
Und wenn du dir jetzt das ursprüngliche Programm ansiehst
1
0100 ldi r16, 0xAA
2
0102 ldi r17, 0x55
3
0104 rcall do_it
4
0106 ldi r18, 0x00
5
6
...
7
8
0200 doit:
9
0200 push r17
10
0202 push r16
11
0204 ldi r18, 0x02
12
0206 push r18
13
0208 pop r16
14
020A pop r17
15
020C pop r18
16
020E ret
dann ist 0106 genau die Adresse an der die nächste Anweisung nach dem
rcall steht, der den Unterprogrammaufruf (und damit das Ablegen von 0106
auf dem Stack) ausgelöst hat.
Und ja. Wenn wir im Unterprogramm einen pop zuwenig gemacht hätten, dann
hätte sich der ret ganz andere Bytes vom Stack geholt, weil dann 1 Byte
am Stack übrig geblieben wäre und damit der ret sich etwas völlig
Falsches vom Stack geholt hätte.
In Assembler gibt es hier keinerlei Überprüfung. Du pusht etwas auf den
Stack, du popst etwas vom Stack. Was, wieviel, in welche Register: das
ist dein Bier. Niemand redet dir da drein. Und schon gar nicht der
Prozessor. Push, Pop, Rcall, Ret all diese Befehle interessiert nicht
was vorher war. Ihr Verhalten ist genau festgelegt und dreht sich nur
darum ob ein Byte auf den Stack kommt, ein Byte vom Stack genommen wird,
bzw. ob bei einem Aufruf etwas auf den Sttack geschrieben wird oder beim
Ret wieder vom Stack geholt wird. Das das alles zusammenstimmt ... darum
musst du dich als Programmierer kümmern.
@Michael
Du kannst das doch alles mal im Simulator (AVR-Studio) nachvollziehen,
dann hast Du es kappiert.
Mach doch mal ein push und pop im Einelschritt-Modus, schau Dir die
Register und den Stack an etc. Und dann die Beispiele von K. H.
Buchegger, spess53 und den anderen.
Erstmal an Karl Heinz Buchegger: Respekt ... wie lange hast daran
geschrieben ^^.
Denke das ich es nun nach dem Beispiel von K. H. B. kurz Mod verstanden
habe und werde es nochmal wie von Frank angesprochen nochmal im
Einzelschritt anschauen.