Forum: Mikrocontroller und Digitale Elektronik Assembler - AVR Frage


von Armin (Gast)


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

von johnny.m (Gast)


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

von unsichtbarer WM-Rahul (Gast)


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

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

Da war ich etwas langsamer...

von johnny.m (Gast)


Lesenswert?

...Oder mit der Schleife von oben:

loop:
    cpi sekunde, 60
    brne loop
    call min

min:
    ldi sekunde, 0
    inc minute
    ret

von Armin (Gast)


Lesenswert?

danke, besonders @johnny m., habe deinen ersten Tip verwendet, da ja 
hier noch ein Unterprogramm Stunde, u.a. kommen wird. Hat auf Anhieb 
funktioniert und habs auch verstanden...

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.