Forum: Mikrocontroller und Digitale Elektronik Dezimalzahl an LCD


von Philip (Gast)


Lesenswert?

hallo zusammen,


damit beispielsweise einen Zahlenwert von 123 am LCD ausgegeben wird, 
gibt es  im AVR-Tutorial den folgenden Code:
1
lcd_number:
2
           push  temp1            ; die Funktion verändert temp1 und temp2,
3
           push  temp2            ; also sichern wir den Inhalt, um ihn am Ende
4
                                  ; wieder herstellen zu können
5
 
6
           mov   temp2, temp1     ; das Register temp1 frei machen
7
                                  ; abzählen wieviele Hunderter
8
                                  ; in der Zahl enthalten sind
9
;** Hunderter ** 
10
           ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen
11
lcd_number_1:
12
           inc   temp1            ; ASCII erhöhen (somit ist nach dem ersten
13
                                  ; Durchlauf eine '0' in temp1)
14
           subi  temp2, 100       ; 100 abziehen
15
           brcc  lcd_number_1     ; ist dadurch kein Unterlauf entstanden?
16
                                  ; nein, dann zurück zu lcd_number_1
17
           subi  temp2, -100      ; 100 wieder dazuzählen, da die
18
                                  ; vorherhgehende Schleife 100 zuviel
19
                                  ; abgezogen hat
20
           rcall lcd_data         ; die Hunderterstelle ausgeben
21
 
22
;** Zehner  **
23
           ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen
24
lcd_number_2:
25
           inc   temp1            ; ASCII erhöhen (somit ist nach dem ersten
26
                                  ; Durchlauf eine '0' in temp1)
27
           subi  temp2, 10        ; 10 abziehen
28
           brcc  lcd_number_2     ; ist dadurch kein Unterlauf enstanden?
29
                                  ; nein, dann zurück zu lcd_number_2
30
           subi  temp2, -10       ; 10 wieder dazuzählen, da die
31
                                  ; vorherhgehende Schleife 10 zuviel
32
                                  ; abgezogen hat
33
           rcall lcd_data         ; die Zehnerstelle ausgeben
34
 
35
;** Einer **        
36
           ldi   temp1, '0'       ; die Zahl in temp2 ist jetzt im Bereich
37
           add   temp1, temp2     ; 0 bis 9. Einfach nur den ASCII Code für
38
           rcall lcd_data         ; '0' dazu addieren und wir erhalten dierekt
39
                                  ; den ASCII Code für die Ziffer
40
 
41
 
42
           pop   temp2            ; den gesicherten Inhalt von temp2 und temp1
43
           pop   temp1            ; wieder herstellen
44
           ret                    ; und zurück

Wie würde es aussehen, wenn man einen Wert von 10 auf dem LCD ausgeben 
will....
wenn ich 10 abziehe, dann erhalte ich eine Null.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Philip schrieb:

> Wie würde es aussehen, wenn man einen Wert von 10 auf dem LCD ausgeben
> will....
> wenn ich 10 abziehe, dann erhalte ich eine Null.

Ja.
Aber
1
            subi  temp2, 10        ; 10 abziehen
2
            brcc  lcd_number_2     ; ist dadurch kein Unterlauf
bei 0 entsteht noch kein Unterlauf (das Ergebnis ist noch nicht 
negativ).

D.h. du zählst 1 Zehner.
Was ja auch richtig ist.

: Bearbeitet durch User
von Philip (Gast)


Lesenswert?

wie sieht der Code aus...
1
lcd_number_2:
2
           inc   temp1            ; ASCII erhöhen (somit ist nach dem ersten
3
                                  ; Durchlauf eine '0' in temp1)
4
           subi  temp2, 10        ; 10 abziehen
5
           brcc  lcd_number_2     ; ist dadurch kein Unterlauf enstanden?
6
                                  ; nein, dann zurück zu lcd_number_2
7
           subi  temp2, -10       ; 10 wieder dazuzählen, da die
8
                                  ; vorherhgehende Schleife 10 zuviel
9
                                  ; abgezogen hat
10
           rcall lcd_data         ; die Zehnerstelle ausgeben
11
 
12
;** Einer **        
13
           ldi   temp1, '0'       ; die Zahl in temp2 ist jetzt im Bereich
14
           add   temp1, temp2     ; 0 bis 9. Einfach nur den ASCII Code für
15
           rcall lcd_data         ; '0' dazu addieren und wir erhalten dierekt
16
                                  ; den ASCII Code für die Ziffer
17
 
18
 
19
           pop   temp2            ; den gesicherten Inhalt von temp2 und temp1
20
           pop   temp1            ; wieder herstellen
21
           ret                    ; und zurück

: Bearbeitet durch User
von Philip (Gast)


Lesenswert?

fällt dann der Teil am Anfang dann weg?

ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen

von Karl H. (kbuchegg)


Lesenswert?

Philip schrieb:
> fällt dann der Teil am Anfang dann weg?
>
> ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen

Die Frage würde sich erübrigen, wenn du das Prinzip kapiert hättest.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Im übrigen.
Was denkst du, warum ich im Tutorial
1
;** Zehner  **
2
           ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen
3
lcd_number_2:
4
           inc   temp1            ; ASCII erhöhen (somit ist nach dem ersten
5
...

den Kommentar
1
;** Zehner  **
genau dort platziert habe, wo er steht?

Es hilft nix. Wenn man in Assembler programmiert, d.h. gerade wenn man 
in Assembler programmiert, muss man mitdenken. Unter anderem auch 
deshalb, weil man sich da um jeden noch so kleinen Pfurz selber kümmern 
muss.

: Bearbeitet durch User
von Heinz V. (heinz_v)


Lesenswert?

Philip schrieb:
> fällt dann der Teil am Anfang dann weg?
>
> ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen

Nein, denn um die "0" auf einem Display darzustellen sendest Du diesem 
0X30 bzw 48dez, denn so ist der Binaerwert des Zeischens "0" im 
*A*merican *S*tandart *C*ode for *I*nformation *I*nterchange 
(amerikanischer Standart Code zum Informationsaustausch) definiert.

Also musst Du jeder Ziffer die 0x30 hinzuadieren, hier sind es 0x2F, da 
eine 1 schon vorhanden ist.

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Karl H. schrieb:
> warum ich im Tutorial

Ich hoffe der Code im Tutorial ist so programmiert, wie er programmiert 
ist, nur um vereinfacht das Prinzip zu verdeutlichen, denn ein "echter" 
Assemblerprogrammierer hätte das etwas optimierter gemacht..

von Wolfgang A. (Gast)


Lesenswert?

Thomas H. schrieb:
> ... denn ein "echter" Assemblerprogrammierer hätte das etwas
> optimierter gemacht..

Dann zeig mal, wie du das angehen würdest ...

von Magic S. (magic_smoke)


Lesenswert?

>> ... denn ein "echter" Assemblerprogrammierer hätte das etwas
>> optimierter gemacht..
> Dann zeig mal, wie du das angehen würdest ...

BUMM Treffer, versenkt! :)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Das Prinzip ist in dem Assembler Snippet doch schon sehr 
selbsterklärend. Wenn es um jedes Byte geht, könnte man nun noch die 
100,10 und 1 aus einer Tebelle holen und noch jedem 'Unterlauf' den 
Pointer auf diese Tabelle auffrischen, aber das ist bei den heutigen 
Flashgrössen eigentlich nicht mehr nötig.
Auch eine Erweiterung auf 5-stellig oder so ist da einfach, wenn man 
sich ans Schema hält - lediglich Bytes sind dann zu klein, Words sind 
dann angesagt.
Hier mal mein altes Snippet für den MCS51 nach diesem Schema, auch nur 
für Bytes, aber mit Unterdrückung von führenden Nullen:
1
lzero    BIT  STA2    ; suppress leading zeros flag in PRDEC output
2
; Prints a decimal number out of a byte in ACC
3
; method: Subtracting until carry, then next digit 
4
; we have suppression of leading zeros here 
5
; uses R3,R4,R5 and our scratch at R7
6
;
7
PRDEC:  CLR     lzero      ; Flag in bit adressable area
8
    MOV     R5,#0h     ; counter
9
    MOV  R3,A         ; save the value   
10
    SETB  double         
11
PRDEC1:  MOV     R4,#0h
12
    MOV      A,R5    ; counter 
13
PRDEC2:  MOV     DPTR,#DECTBL
14
    MOVC    A,@A+DPTR  ; get value to sutract
15
    MOV     R7,A    ; subtractor
16
PRDEC4:  MOV     A,R3    ; get value
17
    CLR     C    ; math ahead
18
    SUBB    A,R7    ; try it
19
    JC      PRDEC3    ; it was too much
20
    MOV     R3,A    ;
21
    INC     R4    ; value adder                      
22
    SJMP    PRDEC4
23
PRDEC3:  JB      lzero,PRDEC8     ; leading zero suppression
24
    CJNE    R4,#0h,PRDEC5      ; its not zero
25
    CJNE    R5,#02h,PRDEC7     ; its the not last digit, print nothing
26
    SJMP    PRDEC8              ; its the last digit , print a zero
27
PRDEC5:  SETB    lzero
28
PRDEC8:  MOV     A,#030h  ; add a 0 
29
    ADD     A,R4
30
PRDEC6:  ACALL   LCDASC              ; print to LCD
31
PRDEC7:  INC     R5
32
    CJNE    R5,#003h,PRDEC1  
33
    RET
34
DECTBL:     db     0100d,010d,01d, 0d
Formatierung ist leider platt gemacht vom Forum.

: Bearbeitet durch User
von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Wolfgang A. schrieb:
> Dann zeig mal, wie du das angehen würdest ...

Ich denke die Frage ist mittlerweile schon beantwortet. Sich 
wiederholende Aufgaben kommen in eine Schleife. Das ist besonders 
sinnvoll wen man einmal mehr als 3 Ziffern ausgegeben möchte. Über die 
Sinhaftigkeit Programme zu verkürzen weil ja heute der Speicher so groß 
und billig ist habe ich weder an dieser, noch an anderer Stelle Lust zu 
diskutieren. Das schon mal vorweg. Das können gerne andere machen. Wenn 
man zu Assembler greift hat man sicher seine Gründe. Einer davon ist es 
eine Codeoptimierung zu betrieben. Deshalb gehören zum erlernen von 
Assembler eben auch diese Aspekte.

von Magic S. (magic_smoke)


Lesenswert?

Achsooo Du bemängelst die Ausführung - und ich dachte Du hast eine 
bessere Technik.

von Philip (Gast)


Lesenswert?

Also ich habe den Code aus dem Tutorial übernommen und bekomme am LCD 
anstatt 10 1B angezeigt.

von Karl H. (kbuchegg)


Lesenswert?

Thomas H. schrieb:
> Karl H. schrieb:
>> warum ich im Tutorial
>
> Ich hoffe der Code im Tutorial ist so programmiert, wie er programmiert
> ist, nur um vereinfacht das Prinzip zu verdeutlichen, denn ein "echter"
> Assemblerprogrammierer hätte das etwas optimierter gemacht..

Schon klar, dass man das auch noch kürzer schreiben kann.
In einem Tutorial hast du immer das Problem, dass du es mit Neulingen zu 
tun hast. D.h. ein Tutorial muss darauf Rücksicht nehmen, zuallererst 
einmal für Neulinge verstehbare Lösungsmöglichkeiten zu zeigen.
Und wie sich hier ja zeigt, ist selbst mit dieser simplen Lösung noch 
lange nicht garantiert, dass dieses einfache Verfahren verstanden wird.

von Karl H. (kbuchegg)


Lesenswert?

Philip schrieb:
> Also ich habe den Code aus dem Tutorial übernommen und bekomme am LCD
> anstatt 10 1B angezeigt.

Dann hast du eben nicht den Code aus dem Tutorial übernommen. Denn der 
funktioniert nachweislich. Also vergleiche, wo dein Code von dem 
veröffentlichten abweicht.

Hinweis: Es ist immer eine gute Idee, wenn man Code erst mal so 
übernimmt, wie er veröffentlicht wird. Das mag vielleicht nicht genau 
das sein, was dir vorschwebt, aber man kann erst mal testen, ob das 
Prinzip überhaupt funktioniert. Abspecken und die Teile, die man nicht 
braucht rauswerfen kann man immer noch.
Aber man erspart sich die Peinlichkeit, Code als nicht funktionsfähig zu 
bezeichnen, während das eigentliche Problem in den modifizierten Teilen 
steckt, die man selbst verbockt hat.

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.