Assembler - AVR Frage

Gast #444631
Lesenswert?

Hallo Leute,
ich arbeite mich zur Zeit auf einem ATMEGA32 in Assembler ein (bin also 
Anfänger). Bei einem kleinen Progrämmchen habe ich nun ein Problem 
festgestellt. Die Fehlerursache habe ich ansich erkannt, weiß aber nicht 
wie ich es besser machen kann. Daher meine Frage an euch, ob Ihr mir 
weiterhelfen könnt.

Folgende Situation, ich versuche eine Uhr mittels Assembler zu 
programmieren. Vorhandene Beispielcodes in der Codesammlung habe ich 
angeschaut, dass eigentliche Problem konnte ich damit aber nicht lösen. 
Wie lasse ich das Programm bedingt in ein Unterprogramm springen, also 
wie löst man sowas in Assembler?
Zur Erläuterung was ich im Hinterkopf habe, ein kurzes Beispiel in C 
(ich weiß, dass dies 1:1 in Assembler nicht möglich ist, es dient also 
nur der Erläuterung was ich erreichen möchte):

//var=Laufvariable, wird "irgendwo" hochgezählt
if (var==x) // var identisch mit x?
{
  unterprogramm();
}

Ich habe nun folgendes geschrieben  (Auszug aus meinem Programm):

loop:
     cpi sekunde,60 //compare register & Konstante
     breq min       //verzweige zu "min" wenn z flag gesetzt
     rjmp loop

min:
    ldi sekunde, 0
    inc minute
    ret

(Hinweis: am Programmanfang habe ich ".def sekunde = R19" & ".def minute 
= R20" stehen , sind also beides register wie es sein sollte)

Mit meinem JTAG Debugger habe ich gemerkt, dass bei "breq min" der PC 
anscheinend nicht auf dem Stack gesichert wird (Adresse verkleinert sich 
nicht...), beim anschliessenden ret springt er dann wohl ins nirwana, 
JTAG ICE warnt dabei vor invalid value (0x7FFFFFFF) und mein Programm 
fängt ganz von vorne an. Offensichtlich ist breq (wohl auch brne etc.) 
nicht dafür geeignet, weil der PC nicht gesichert wird, richtig?

Einen Rücksprung aus einer Interruptroutine habe ich probiert, weiß also 
wie es aussehen müsste (was Stack und PC angeht).

Wie muss ich es stattdessen lösen?
Für ein kurzes, kommentiertes Beispiel wäre ich dankbar.

Danke und Gruß
Armin
Gast #444640
Lesenswert?

breq macht einen relativen Sprung. Das hat nix mit ret zu tun. 
Unterprogrammaufrufe gehen mit call bzw. rcall. Schau Dir den 
Befehlssatz mal genauer an. Du müsstest, wenn Du mit der obigen 
Bedingung springen willst, was in der Art

    cpi sekunde, 60
    brne weiter
    call min

weiter:
    ;weiter im Programm

min:
    ldi sekunde, 0
    inc minute
    ret

Dann springt das Programm bei ret wieder zurück (also nach "weiter")
Gast #444641
Lesenswert?

"call" dürfte dich interessieren.

Es dürfte dann auf ein Konstukt hinauslaufen, dass die beiden Variablen 
vergleicht und bei "negativem" Ergebnis die folgende Anweisung 
überspringt.
In diesem Fall wäre die Anweisung dann das "call".

Pseudocode: (ich kann Asm lesen, aber nicht schreiben...)
anfang:
.
.
.

compare X,Y
skip if equal
call ungleich
allgemeines Weitermachen
.
.
.
jmp anfang


ungleich:
.
.
.
ret

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren