www.mikrocontroller.net

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


Autor: Peter Bednarz (pebez)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: gtf (Gast)
Datum:

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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...
:
        ldi     temp2, '0'         
lcd_number_10:                
        subi    temp1, 10           ; abzählen wieviele Zehner in
        brcs    lcd_number_1        ; der Zahl enthalten sind
        inc     temp2               ; Zehner mitzählen
        rjmp    lcd_number_10
lcd_number_1:
        rcall   lcd_data            ; die Zehnerstelle ausgeben
:
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:
        subi    temp1, -10          ; 10 wieder dazuzählen, da die
                                    ; vorhergehende Schleife 10 zuviel
                                    ; abgezogen hat
                                    ; das Subtrahieren von -10
                                    ; = Addition von +10 ist ein Trick
                                    ; da kein addi Befehl existiert
        ldi     temp2, '0'          ; die übrig gebliebenen Einer
        add     temp1, temp2        ; noch ausgeben
        rcall   lcd_data            ;
Denn -(-10) und +'0' zusammen ergeben 10+'0'
        ldi     temp2, 10+'0'       ; die übrig gebliebenen Einer
        add     temp1, temp2        ; korrigieren und ausgeben
        rcall   lcd_data            ;
Oder noch kürzer:
        subi    temp1, -(10+'0')    ; die übrig gebliebenen Einer korrigieren und ausgeben
        rcall   lcd_data            ;

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.