Forum: Mikrocontroller und Digitale Elektronik Einfacher Zähler von 0->99 auf 2 Halbbyte


von Tim S. (Firma: Germany) (timex09)


Lesenswert?

Was läuft denn hier falsch?!

Ich habe einen 1Byte Wert dieser soll mir jeweils aus dem Oberen und 
unteren Byte eine Dez. Zahl von 1 bis 9 Zählen und dann auf einen 
Display ausgeben.

Nur leider Zählt es jetzt mit den Einer 1->3->7->? FERTIG
und die Zehner  1.2.3.4.5.6.7.8.9 noch 6 Sonderzeichen und dann wieder 
bei 0 und die Einerstelle ändert sich nicht. Ist hier ein Denkfehler 
drin?

R21 : Ist sind meine zwei Dez. Zahlen … also 00 bis 99


zaelen:     push    r16
            ldi     r16,0
            mov     r16,r21
            cbr     r16,0b11110000      ;Lösche Oberes Halbbyte
            cpi     r16,9               ;Ist die Zahl jetzt 9?
            breq    zaelenZehn          ;Dann verzweige
            inc     r16                 ;Addiere um 1
            add     r21,r16             
            pop     r16
            ret                         ;Zurück

zaelenZehn:
            mov     r16,r21             
            swap    r16                 ;Oberes und unteres Halbbyte tau 
schen
            cbr     r16,0b11110000      ;Löschen Oberes Halbbyte
            cpi     r16,9               ;Ist der Wert jetzt 9?
            breq    zaelenReset         ;Dann verzweige
            inc     r16                 ;Addiere um 1
            swap    r16                 ;Oberes und unteres Halbbyte tau 
schen
            mov     r21,r16
            pop     r16
            ret
            
zaelenReset:
            clr     r20
            pop     r16
            ret



AusgabeWertA:
            ldi     r16,0x44
            rcall   lcdGoto
            ldi     r17,0x30
            mov     r16,r21
            swap    r16
            cbr     r16,0xF0
            add     r16,r17
            rcall   lcdData
            ldi     r17,0x30
            mov     r16,r21
            cbr     r16,0xF0
            add     r16,r17
            rcall   lcdData
            ret

von hdd (Gast)


Lesenswert?

breq schreibt keien Rücksprungadresse auf den Stack so wie z.B. rcall. 
Das heißt beim ret am Ende von zaehlenZehn landest du irgendwo aber 
nicht dort wo du hinwillst.

von Tim S. (Firma: Germany) (timex09)


Lesenswert?

Ne das ist es nicht. Das sollte ja so sein dann will ich ja wieder in 
mein mainloop da wo ich her komme.

Ich habe aber den fehler.
            inc     r16                 ;Addiere um 1
(bevor ich die Werte wieder zusammenbringe muss ich doch den unteren 
bzw. oberen Halbbyte löschen sonst addiere ich den wert mit dem wert 1 - 
3 - 7

also

          ->cbr     r21,0x0F            ;Unteren Halbbyte löschen <-

            add     r21,r16
            pop     r16
            ret                         ;Zurück


Aber danke für die Antworten... man muss manchmal eben nur eine rauchen 
und nochmal überlegen. in diesem fall war das erfolgreich =)

von Anja (Gast)


Lesenswert?

Tim Simon schrieb:
> und nochmal überlegen.

Was soll denn bei Erreichen von 99+1 passieren?

Wenn schon Assembler: mit dem BRHC-Befehl könntest Du die Zählerei auf 
ca 10 Befehle kürzen.

Gruß Anja

von spess53 (Gast)


Lesenswert?

Hi

>Wenn schon Assembler: mit dem BRHC-Befehl könntest Du die Zählerei auf
>ca 10 Befehle kürzen.

Nein. Das wird erst bei $xF+1 gesetzt. Aber das mit den 10+x Befehlen 
kommt trotzdem hin.

MfG Spess

von Anja (Gast)


Lesenswert?

spess53 schrieb:
> Nein. Das wird erst bei $xF+1 gesetzt. Aber das mit den 10+x Befehlen
> kommt trotzdem hin.

Ich wollte jetzt nicht die komplette Lösung zu den Hausaufgaben 
hinschreiben aber wenn man will kann man den Überlauf des digit carry 
bei $xA + testweise Addition von 6 in ein Hilfsregister erzwingen.

Gruß Anja

von Peter D. (peda)


Lesenswert?

Eine CPU rechnet immer binär. Es kostet daher viel Code, wenn man 
versucht, sie auf dezimal zu vergewaltigen.

Einfacher ist es, binär zu zählen und nur zur Ausgabe nach Dezimal zu 
wandeln:
1
.def    counter = r16
2
.def    wr0     = r18
3
.def    wr1     = r19
4
;----------------------------------------
5
6
;count up 0 .. 99
7
count:
8
        inc     counter
9
        cpi     counter, 100
10
        brcs    _count1
11
        clr     counter
12
_count1:
13
        ret
14
;----------------------------------------
15
16
;input: wr0 = number 0 .. 99
17
;output: wr0 = ones, wr1 = tens (ASCII)
18
numout:
19
        ldi     wr1, '0' - 1
20
_numout1:
21
        inc     wr1
22
        subi    wr0, 10
23
        brcc    _numout1
24
        subi    wr0, -(10 + '0')
25
        ret
26
;----------------------------------------

Es ist sinnvoll, die Register zu benamen. Ansonsten kommt man sehr 
schnell durcheinander, was nun welches Register für eine Funktion hat.

Auch sollte man einige Register als zerstörbar (Arbeitsregister) 
reservieren, das erspart haufenweises Push/Pop. Sinnvoll dienen sie auch 
gleich der Parameterübergabe (Argumente und Returnwerte).


Peter

von spess53 (Gast)


Lesenswert?

Hi

>Es kostet daher viel Code, wenn man
>versucht, sie auf dezimal zu vergewaltigen.

Nicht wirklich. Mit der Anregung von Anja:
1
bcd_cnt:   push r16
2
           ldi r16,$67
3
           add r21,r16
4
           brcs bcd_cnt20
5
           brhs bcd_cnt10
6
           subi r21,$06
7
bcd_cnt10: subi r21,$60
8
bcd_cnt20: pop r16
9
           ret

Wenn man die $67 noch in einem der unteren Register ablegt, würden es 
nur noch 6 Befehle sein. Gerade einer mehr wie bei dir.

MfG Spess

von Peter D. (peda)


Lesenswert?

spess53 schrieb:
> Gerade einer mehr wie bei dir.

Ziemlich tricky der Code, schwer zu durchschauen.
Wenn man nicht nur INC, sondern auch andere Operationen machen will, 
artet das aber schnell aus.
Und die Ausgabe muß die Nibble ja wieder auseinanderpfrimeln.

Die Ausgabe des Binärwertes würde so aussehen:
1
AusgabeWertA:
2
        ldi     wr0, 0x44
3
        rcall   lcdGoto
4
5
        mov     wr0, counter    ; get value
6
        rcall   numout          ; bin -> dec
7
        push    wr0
8
        mov     wr0, wr1        ; tens first
9
        rcall   lcdData
10
        pop     wr0             ; then ones
11
        rjmp    lcdData


Peter

P.S.
Der Originalcode sichert R16 beim Zählen, aber die Ausgabe zerstört R16, 
R17. Entweder immer sichern oder garnicht.
Gerade bei Assembler ist es wichtig, konsequent zu sein, sonst sucht man 
sich dumm und dämlich nach den Fehlern.
Deshalb auch der Tip mit der Benamung, damit die zerstörbaren Register 
sofort ins Auge fallen. Und auch, damit man Argumente nicht im falschen 
Register übergibt. Namen lassen sich leichter merken, als nur die Zahlen 
0 .. 31.

von spess53 (Gast)


Lesenswert?

Hi

>Wenn man nicht nur INC, sondern auch andere Operationen machen will,
>artet das aber schnell aus.

Ist richtig. Mit BCD/Packet BCD kann man kaum etwas herausreissen.

>Der Originalcode sichert R16 beim Zählen,...

Da passt einiges nicht.

MfG Spess

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.