Forum: Mikrocontroller und Digitale Elektronik rjmp Problem


von Robert C. (anykey)


Lesenswert?

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

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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).

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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

von Peter R. (pnu)


Lesenswert?

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

von Robert C. (anykey)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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?

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Robert C. (anykey)


Lesenswert?

Sorry.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch Moderator
von Peter R. (pnu)


Lesenswert?

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.

: Bearbeitet durch User
von Robert C. (anykey)


Lesenswert?

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?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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"

: Bearbeitet durch Moderator
von Robert C. (anykey)


Lesenswert?

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?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch Moderator
von Robert C. (anykey)


Lesenswert?

Alles klar, hab es geschnallt.
Mit rjmp springt man nur irgendwo hin aber nie zurück.
Vielen Dank.

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
Noch kein Account? Hier anmelden.