Forum: Mikrocontroller und Digitale Elektronik Tutorial Fehler in Uhr und CTC


von Peter B. (pebez)


Lesenswert?

Nabend zusammen,

werden im Tutorial absichtlich kleine Fehler eingebaut um den
Anfängern das denken beizubringen?

Konkret im Tutorial Uhr und CTC Modus.

Im rcall lcd_number wird das Register temp1 nicht gesichert.
In der Folge zeigt das LCD "Chinesische" Ziffern an.

Original im Tutorial:
lcd_number:
        push    temp2

        ldi     temp2, '0'
lcd_number_10:
        subi    temp1, 10
        brcs    lcd_number_1
        inc     temp2
        rjmp    lcd_number_10

lcd_number_1:
        rcall   lcd_data
        subi    temp1, -10
        ldi     temp2, '0'
        add     temp1, temp2
        rcall   lcd_data

        pop     temp2
        ret

Bis man als Anfänger darauf kommt, dauert es etwas.

Richtigerweise müsste dort stehen:

lcd_number:
         push    temp2
         push    temp1

         mov     temp2, temp1
         ldi     temp1, '0'

lcd_number_10:
        subi    temp2, 10
        brcs    lcd_number_1
        inc     temp1
        rjmp    lcd_number_10
lcd_number_1:

        rcall   lcd_data
        subi    temp2, -10

        ldi     temp1, '0'
        add     temp1, temp2
        rcall   lcd_data

        pop     temp1
        pop     temp2
        ret

Gerade Anfängern wird es hier schwer gemacht (fehlende Erfolge):-)

Kann jemand den Code im Tutorial anpassen?

Gruß  Pebez

von Karl H. (kbuchegg)


Lesenswert?

Ich kann ehrlich gesagt nicht wirklich nachvollziehen, was daran falsch 
sein soll.
temp1 ist das Eingangsregister dieser Funktion. Der Wert in temp1 soll 
ausgegeben werden. Und wenn man sich die aufrufenden Stellen ansieht, 
ist klar dass es keine Rolle spielt, wenn das Register in der Funktion 
zuerstört wird.

Deine chinesischen Zeichen müssen woanders herkommen.

von gtf (Gast)


Lesenswert?

temp1 ist doch der Eingabewert.
 Die Routine läuft 1A.
Ob deine LCD- Ausgaberoutine richtig ist mag ich zu bezweifeln.

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


Lesenswert?

Leute, da ist wirklich ein Fehler drin  :-o
lcd_data erwartet das auszugebende Zeichen im temp1, und deshalb geht 
das schief, weil der 10er ja im temp2 gezählt wurde...
1
:
2
        ldi     temp2, '0'         
3
lcd_number_10:                
4
        subi    temp1, 10           ; abzählen wieviele Zehner in
5
        brcs    lcd_number_1        ; der Zahl enthalten sind
6
        inc     temp2               ; Zehner mitzählen
7
        rjmp    lcd_number_10
8
lcd_number_1:
9
        rcall   lcd_data            ; die Zehnerstelle ausgeben
10
:
Ich habe da mal einen schnellen Würgaround mit einem lokalen push/pop 
ins Tut gehackt, aber mir gefällt die Lösung von Peter Bednarz 
eigentlich besser...



Und das könnte man noch ein wenig abkürzen:
1
        subi    temp1, -10          ; 10 wieder dazuzählen, da die
2
                                    ; vorhergehende Schleife 10 zuviel
3
                                    ; abgezogen hat
4
                                    ; das Subtrahieren von -10
5
                                    ; = Addition von +10 ist ein Trick
6
                                    ; da kein addi Befehl existiert
7
        ldi     temp2, '0'          ; die übrig gebliebenen Einer
8
        add     temp1, temp2        ; noch ausgeben
9
        rcall   lcd_data            ;
Denn -(-10) und +'0' zusammen ergeben 10+'0'
1
        ldi     temp2, 10+'0'       ; die übrig gebliebenen Einer
2
        add     temp1, temp2        ; korrigieren und ausgeben
3
        rcall   lcd_data            ;
Oder noch kürzer:
1
        subi    temp1, -(10+'0')    ; die übrig gebliebenen Einer korrigieren und ausgeben
2
        rcall   lcd_data            ;

von Karl H. (kbuchegg)


Lesenswert?

Lothar Miller schrieb:
> Leute, da ist wirklich ein Fehler drin  :-o
> lcd_data erwartet das auszugebende Zeichen im temp1, und deshalb geht
> das schief, weil der 10er ja im temp2 gezählt wurde...

Ah. Nach unten hin, zu den LCD Routinen, hab ichs nicht mehr 
kontrolliert. Ich hab mich auf dioe Aufrufe dieser Funktion 
konzentriert.

> Ich habe da mal einen schnellen Würgaround mit einem lokalen push/pop
> ins Tut gehackt, aber mir gefällt die Lösung von Peter Bednarz
> eigentlich besser...


Eigentlich sollte diese ganze temp-erei bereinigt werden und vernünftige 
Namen für die Register vergeben werden. Dann passiert so etwas nicht.

von Peter D. (peda)


Lesenswert?

Das Problem ist, daß man sich als Assemblerprogrammierer erstmal 
Programmierkonventionen festlegen muß.
Also welche Register sind für Argumente und Returnwerte reserviert und 
denen dann entsprechende Namen gibt.

Und dann sollte man sich auch einige Scratchpadregister definieren, die 
niemals gepusht werden müssen.
Wenn der Aufrufer Variablen später noch braucht, muß er sie selber 
sichern oder im SRAM ablegen.

Und dann ist es ne gute Idee, für Interrupts Register zu reservieren, 
damit auch dort Push/Pop weitgehend überflüssig sind.

Generell sollte man globale Variablen nicht in Registern halten.
Register sollten nur die lokalen Arbeitspferde sein, sonst pusht/popt 
man sich nur tot.

Gerade als Assemblerprogrammierer kann man nicht so einfach drauflos 
programmieren.


Peter

von Karl H. (kbuchegg)


Lesenswert?

Peter Dannegger schrieb:

> Gerade als Assemblerprogrammierer kann man nicht so einfach drauflos
> programmieren.

Ich geb dir absolut recht.

Das Problem im Tut ist, dass man irgendwo anfangen muss.
Globale Variablen nicht in Register geht in den Kapiteln vor dem SRAM 
gar nicht.

Auf der anderen Seite will man im Tut natürlich auch ein paar 
interessante Programme zeigen ohne lange drumherum reden zu müssen. D.h. 
die scheinbare Einfachheit der ersten Tut-Kapitel rächt sich, sobald es 
darum geht möglichst wiederverwendbare Module zu schaffen (wie zb LCD 
Ansteuerung). Zum Zeitpunkt, wenn die LCD Routinen eingeführt werden, 
möchte man im Tut natürlich nicht die großen, eigentlich notwendigen, 
Gedankengänge einführen und erläutern, die aber notwendig wären.

Es ist halt schwer. Im Grunde läuft es immer wieder aufs Gleiche raus: 
Man müsste alles gleichzeitig vermitteln können:-)

Mal sehen, ob man da mit klammheimlich eingeführten Registerkonventionen 
noch etwas retten kann. Im Tut wird ja r16 praktisch überall benutzt, in 
Ermangelung von vorausschauender Arbeitsweise, die auch berücksichtigt, 
was in späteren Kapiteln noch dazu kommt und welche Register dort 
benutzt werden.

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.