Hallo,
ich versuche gerade mein erstes Assembler Programm zu erstellen.
Hierzu habe ich vor eine LED Blinken zu lassen.
Das Programm läuft vorerst nur im Simulator.
Das Problem ist nun das das Programm nach dem ersten rjmp nicht weiter
läuft sondern wieder unter "MainLoop" springt.
Wieso läuft das nicht weiter?
Hier der Code:
1
.nolist
2
.include <m8Adef.inc>
3
.list
4
5
.DEF reg16 = R16 ;definition Register16
6
7
.EQU freq = 1000000 ;1 MHz itern
8
.EQU ticksDelay = 0xff ;ein Tick = 1µsec
9
10
Start: ;Start des Programms
11
sbi DDRB, PB0 ;PORTB direction register laden PortB 0 = out
12
cbi PORTB, PB0 ;PORTB bit 0 setzen
13
14
MainLoop:
15
;LED ON
16
sbi PORTB, PB0 ;PORTB bit 0 setzen
17
ldi reg16, ticksDelay ;Wert in Register laden
18
rjmp Delay ;Sprung zur Schleife
19
20
;LED OFF
21
cbi PORTB, PB0 ;PORTB bit 0 rueck setzen
22
ldi reg16, ticksDelay ;Wert in Register laden
23
rjmp Delay ;Sprung zur Schleife
24
25
rjmp MainLoop ;Ruecksprung zur Hauptschleife
26
27
Delay:
28
dec reg16 ;runter zaehlen
29
brne Delay ;Jump wenn nicht Null
30
31
End: ;End des Programms
Könnte mir Jemand sagen was ich falsch mache?
Gruß Robert
Dein rjmp springt nach Delay. Wenn die Warte-Schleife durch ist, beendet
sich Dein komplettes Programm. Grund: Es gibt bei Deinem Programm keinen
Rücksprung ins Hauptprogramm.
Was Du brauchst, ist eine Methode zum Springen in eine Subroutine (call)
und nachher wieder zurück (return).
Robert C. schrieb:> Könnte mir Jemand sagen was ich falsch mache?
Du hast das Kapitel "Formatierung" über der Eingabebox nicht gelesen...
Verwende bitte fürderhin die [avrasm] Tags
Das "End" ist doch nicht richtig.Es ist irgendwie ein Widerspruch zur
Arbeitsweise eines Kontrollers. Der arbeitet immer in irgendeiner
Endlosschleife, außer es wird die bei einigen Kontrollern mögliche
HALT-funktion benutzt. END wird nicht in einen Maschinenbefehl
umgesetzt. Es ist eigentlich nur ein Hinweis für den Programmierer, dass
an dieser Stelle der text zuende ist.
nach brne Delay muss also die Alternative dazu stehen z.B. rjmp MainLoop
Hallo Frank,
Danke für die schnelle Antwort.
Hatte schon versucht das rjmp durch rcall zu ersetzen und im Delay ein
ret eingebaut.
Leider das gleich Ergebnis, es läuft nicht durch.
Keine Ahnung warum das so ist.
Hast du noch eine Idee?
Robert C. schrieb:> Hallo Frank,> Danke für die schnelle Antwort.> Hatte schon versucht das rjmp durch rcall zu ersetzen und im Delay ein> ret eingebaut.
Dazu musst du dann auch noch den Stackpointer initialisieren.
Aber prinzipiell ist das schon mal der richtige Weg.
Denn egal von wo der Aufruf von delay kommt, du willst ja wieder an
diese Aufrufstelle zurück kommen. Ein rjmp springt einfach nur. Ein
rcall hingegen springt zwar auch, legt aber die Adresse von wo der µC
gekommen ist, auf den Stack, damit ein ret sich dann diese Adresse holen
kann und mit dieser Information weiss, wohin er wieder zurckspringen
muss.
Nur: dazu muss wiederrum der Stackpointer so initialisiert sein, dass
der Stack auch dort liegt, wo es im µC Speicher gibt.
Wir haben ein so schönes Tutorial auf dieser Site.
Warum schaust du denn da nicht rein und arbeitest es (von vorne weg)
durch?
AVR-Tutorial> Hast du noch eine Idee?
Im Simulator ist der richtige Prozessor eingestellt?
Peter R. schrieb:> nach brne Delay muss also die Alternative dazu stehen z.B. rjmp MainLoop
Falsch, dann macht der µC nur noch die LED an und nie wieder aus.
Beachte, dass Robert zweimal Delay aufruft (einmal nach LED-An und
einmal nach LED-Aus) und auch wieder genau hinter dem jeweiligen Aufruf
weitermachen will.
Robert C. schrieb:> Hatte schon versucht das rjmp durch rcall zu ersetzen und im Delay ein> ret eingebaut.
Im Prinzip ist das richtig, nur gilt es, da noch ein paar Regeln zu
beachten. Ich kann daher nur Karl Heinz' Rat unterstützen, dass Du das
AVR-Tutorial von Anfang an durcharbeitest.
Auch wenn ich Dir jetzt direkt das Kapitel vorsage
https://www.mikrocontroller.net/articles/AVR-Tutorial:_Stack
wo es drin steht, was bei Unterprogrammen zu beachten ist, empfiehlt es
sich wirklich, es ganz von Anfang an zu lesen. Es lohnt sich.
Dein Programmm muss bei der mit Delay beginnenden Routine ein ret als
Ende haben und mit rcall delay aufgerufen werden. Dann läuft die
hauptschleife ab, ständig mit delay unterbrochen.
Das Ganze geht aber sehr schnell, so etwas mehr als 520 µsec für ein
bzw. aus
da leuchet die LED scheinbar nur mit halber Helligkeit.
Beweg mal, wenn möglich , die LED schnell hin und her. Vieleicht siehst
Du dann anstelle eines leuchtenden Strichs eine Punktekette.
Karl H. schrieb:>> Hast du noch eine Idee?>> Im Simulator ist der richtige Prozessor eingestellt?
Ja, der ATmega8A.
Werde das Tut durch arbeiten.
Könntest du mir trotzdem einen Tipp geben wieso das nicht so läuft wie
erwartet?
Den Stackpointer benötige ich doch nur wenn ich rcall verwende, richtig?
Peter R. schrieb:> Vieleicht siehst Du dann anstelle eines leuchtenden Strichs eine> Punktekette.
Bei knapp 1kHz? Das muss aber ein flottes Auge sein :-o
Und mit ein wenig Glück sind es gut 8kHz, weil zwar 1MHz angegeben ist,
die Fuses aber immer noch auf 8MHz stehen...
Robert C. schrieb:> Könntest du mir trotzdem einen Tipp geben wieso das nicht so läuft wie> erwartet?
Das steht doch schon im
Beitrag "Re: rjmp Problem"
Lothar M. schrieb:>> Vieleicht siehst Du dann anstelle eines leuchtenden Strichs eine>> Punktekette.> Bei knapp 1kHz? Das muss aber ein flottes Auge sein :-o
Das ist "noch" nicht das Problem.
Mir ist klar das das zum Blinken zu schnell ist.
Es kommt aber erst gar nicht zu Blinken.
Ne Idee wieso das rjmp nicht geht wie erwartet?
Robert C. schrieb:> Ne Idee wieso das rjmp nicht geht wie erwartet?
Wenn Du nur mit rjmp arbeiten willst, dann kannst Du Deine Routine
"Delay" niemals wiederverwenden.
Du willst:
1
Sprung in Delay
2
LED an ------------------ Warten ---
3
. |
4
. <----------------------------
5
. Rücksprung in Hauptschleife hinter "LED an"
6
.
7
. Sprung in Delay
8
LED aus ------------------ Warten ---
9
. |
10
. <----------------------------
11
. Rücksprung in Hauptschleife hinter "LED aus"
12
.
13
Sprung nach oben
Wenn Du auf rcall/ret verzichtest, dann kannst Du nach Deiner
Warteschleife nur noch an genau eine Stelle im Hauptpgrogramm per rjmp
zurückspringen, nämlich entweder hinter "LED an" oder hinter "LED aus"
Das reicht aber nicht. Du musst einmal zurückspringen hinter "Led An"
und einmal hinter "Led Aus".
Das geht nur mit rcall/ret und einem initialisierten Stackpointer. Den
Link aufs Tutorial hatte ich auch schon verraten:
https://www.mikrocontroller.net/articles/AVR-Tutorial:_Stack
P.S.
Manche Dinge funktionieren auch nicht, wenn man mit dem Kopf durch die
Wand will. Im Zweifel ist die Wand stärker.