Forum: Mikrocontroller und Digitale Elektronik 8-Bit Zahl an LCD ausgeben


von luxx (Gast)


Lesenswert?

Hallo
ich will eine 8-Bit Zahl aus register xy an ein lcd ausgeben.
wie stell ich das an?
weil ich muss die zahl ja praktisch in 1er, 10er und 100er zerlegen und
die Ziffern dan einzeln an das LCD senden. Aber wie ist sowas zu
bewerkstelligen?

Ich verwende den ATMega16 unter Assembler.

luxx

von Klaus2m5 (Gast)


Lesenswert?

Hallo Luxx,

Du brauchst also eine binär nach ASCII Umwandlung und die findest Du
hier: http://www.avr-asm-tutorial.net/avr_de/rechnen/konversion.html

Gruß, Klaus

von Mech-Michi (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

ich hab ein Programm in Verbindung mit dem aus dem Tutorial gegebenen
LCD-routines für eine 8 bit Zahl geschrieben.
War aber eines meiner ersten, daher vielleicht vom Code nicht so
einbahnfrei. Nach dem Programmtext befindet sich eine Erklärung,
 zudem habe ich den Programmcode auch dokumentiert.
Falls du noch fragen hast, noch mal schreiben.

Greetz

Mech-Michi

von Conlost (Gast)


Lesenswert?

Hallo,

das geht einfach, zuerst festellen ob Zahl größer als 100
wenn ja dann 100 abziehen
Zähler um eins erhöhen
Rest vergleichen ob größer als 100
wenn ja dann nochmal 100 abziehen
Zähler um 1 erhöhen

wenn nein dann das Selbe mit 10

Im Zähler steht dann immer deine 100er oder 10er Stelle.
Wenn 10er fertig ist der Rest die 1er Stelle.

es grüsst,
Arno

von luxx (Gast)


Lesenswert?

@ arno:
stimmt da hätte ich ja selber auch draufkommen können.

ich werde mal den quelltext von Mech_michi hernehmen , der is garnet
schlecht! Danke fürs posting!!

von Jogibär (Gast)


Lesenswert?

Hi ich habe da jetzt mal selber was geschrieben nur Klappt das ganze
nicht so wie ich will, die Zahlen 0 - 227 werden korekt angezeigt von
228 an zeigt mein Display nur noch "000" an. Wäre nett wenn sich
jemand das mal kurz anschauen könnte wo mein Fehler ist?

Mfg Jogibär.


.include "m16def.inc"

;Port A = Taster
;Port B =
;Port C =
;Port D = LCD

;r20 = Dauer 0b00110000 (Auf LCD eine "0")
;r21 = Dauer 0x01
;r22 = SUB Wert
;r23 =
;r24 =
;r25 =
;r26 =
;r27 = Wert 100er
;r28 = Wert 10er
;r29 = Wert 1er
;r30 =
;r31 =

.def temp = r16
.def temp1 = r19
.def temp2 = r18
.def temp3 = r17

; STACKPOINTER INITIALISIEREN

  ldi temp, LOW(RAMEND)
        out SPL, temp
        ldi temp, HIGH(RAMEND)
        out SPH, temp

;PORTS DEFINIEREN

  ldi r16, 0b00000000
  out DDRA, r16    ;PORT A = EINGANG

        ldi r16, 0b11111111
  out DDRD, r16           ;PORT D = AUSGANG

;PROGRAMM

  rcall lcd_init
  rcall lcd_clear

loop:
  in r16, PINA
  ldi r27, 0b00110000
  ldi r28, 0b00110000
  ldi r29, 0b00110000
  ldi r21, 0x01

L100:
  cpi r16, 0b01100100    ;Vergleichen mit 100
  brmi L010      ;Kleiner 100 --> L010
  add r27, r21
  ldi r22, 0b01100100
  sub r16, r22
  rjmp L100

L010:
  cpi r16, 0b00001010    ;Vergleichen mit 10
  brmi L001      ;Kleiner 10 --> L001
  add r28, r21
  ldi r22, 0b00001010
  sub r16, r22
  rjmp L010

L001:
  cpi r16, 0b00000001    ;Vergleichen mit 1
  brmi Ausgabe      ;Kleiner 1 --> Fertig
  add r29, r21
  ldi r22, 0b00000001
  sub r16, r22
  rjmp L001

Ausgabe:
  rcall lcd_1zeile

  mov temp1, r27     ;1.Zeichen anzeigen
  rcall lcd_data

  mov temp1, r28     ;2.Zeichen anzeigen
  rcall lcd_data

  mov temp1, r29     ;3.Zeichen anzeigen
  rcall lcd_data

  rjmp loop

.include "lcd-routines.asm"   ;LCD-Routinen werden hier eingefügt

von Conlost (Gast)


Lesenswert?

Hallo,

ich habe dein Programm etwas verändert,
die Änderungen sind mit ***** gekennzeichnet.
So sollte es funktionieren.

Es grüsst,
Arno

.include "m16def.inc"

;Port A = Taster
;Port B =
;Port C =
;Port D = LCD

;r20 = Dauer 0b00110000 (Auf LCD eine "0")
;r21 = Dauer 0x01
;r22 = SUB Wert
;r23 =
;r24 =
;r25 =
;r26 =
;r27 = Wert 100er
;r28 = Wert 10er
;r29 = Wert 1er
;r30 =
;r31 =

.def temp = r16
.def temp1 = r19
.def temp2 = r18
.def temp3 = r17

; STACKPOINTER INITIALISIEREN

  ldi temp, LOW(RAMEND)
        out SPL, temp
        ldi temp, HIGH(RAMEND)
        out SPH, temp

;PORTS DEFINIEREN

  ldi r16, 0b00000000
  out DDRA, r16    ;PORT A = EINGANG

        ldi r16, 0b11111111
  out DDRD, r16           ;PORT D = AUSGANG

;PROGRAMM

  rcall lcd_init
  rcall lcd_clear

loop:
  in r16, PINA
  ldi r27, 0b00110000
  ldi r28, 0b00110000
  ldi r29, 0b00110000
  ldi r21, 0x01

L100:
  cpi r16, 0b01100100    ;Vergleichen mit 100
  brcs L010      ;Kleiner 100 --> L010  *****
  add r27, r21
  ldi r22, 0b01100100
  sub r16, r22
  rjmp L100

L010:
  cpi r16, 0b00001010    ;Vergleichen mit 10
  brcs L001      ;Kleiner 10 --> L001 *****
  add r28, r21
  ldi r22, 0b00001010
  sub r16, r22

L001:
  add r29, r16   ;***** in r16 sind nur noch Einer *****
    rjmp Ausgabe

Ausgabe:

  rcall lcd_1zeile

  mov temp1, r27     ;1.Zeichen anzeigen
  rcall lcd_data

  mov temp1, r28     ;2.Zeichen anzeigen
  rcall lcd_data

  mov temp1, r29     ;3.Zeichen anzeigen
  rcall lcd_data

  rjmp loop

.include "lcd-routines.asm"   ;LCD-Routinen werden hier eingefügt

von Karl H. (kbuchegg)


Lesenswert?

@Jogibär

L100:
  cpi r16, 0b01100100    ;Vergleichen mit 100
  brcs L010      ;Kleiner 100 --> L010  *****
  add r27, r21
  ldi r22, 0b01100100
  sub r16, r22
  rjmp L100


Warum um alles in der Welt schreibst Du 100 als 0b01100100.
Ich bein jetzt 25 Jahre im Geschäft, aber das 0b01100100
dezimal 100 ergibt sehe ich immer noch nicht auf einen Blick.
Schreib das doch als

  cpi r16, 100        ;Vergleichen mit 100

und gut is.
Allerdings steht jetzt im Code und im Kommentar exakt dasselbe.
D.h. der Kommentar erzaehlt mir nichts, was ich nicht auch
im Code sehen wuerde und ist damit überflüsig und kann weg.

L100:
  cpi r16, 100
  brcs L010      ;Kleiner 100 --> L010  *****
  add r27, r21
  ldi r22, 100
  sub r16, r22
  rjmp L100

Allerdings waere ein Kommentar interessant, was den in diesem
Code Abschnitt tatsaechlich passiert:

; Ziehe von r16 immer wieder 100 ab solange bis r16 kleiner
; als 100 geworden ist. In r27 wird mitgezaehlt, wie oft das
; moeglich war

L100:
  cpi r16, 100
  brcs L010      ;Kleiner 100 --> L010  *****
  add r27, r21
  ldi r22, 100
  sub r16, r22
  rjmp L100

L010:

So erzaehlt mir der Kommentar sehr viel mehr, als wenn ich
nur im Kommentar das dokumentiere, was ohnehin im Code
auch ersichtlich ist. Den Kommentar beim brcs wuerde ich
(fuer mich) lassen, da ich weiss, dass ich immer wieder
Minutenlang ueberlegen muss, wie das nun mit den Flags
nach einem Compare ist: Welches Flag bedeutet was?
Und somit ist das 'Kleiner' etwas, was zumindest ich nicht
sofort (ohne Nachdenken) aus dem brcs ersehen kann.

PS: Anders als beim add, gibt es beim sub eine Variante in
der man die zu subtrahierende Zahl direkt angeben kann.

von Hannes L. (hannes)


Lesenswert?

> Warum um alles in der Welt schreibst Du 100 als 0b01100100.

Ich vermute mal, weil es dem Unwissenden zeigt, dass man Ahnung hat...

;-)  <--- datt iss'n 'Lächeln'...

Aber um die Verwirrung mal perfekt zu machen:
1
lcd_print8:             ;Wird vom Makro aufgerufen. Gibt Byte als 2
2
                        ;oder 3 Ziffern an LCD aus.
3
 push wl                    ;Reg sichern
4
 ldi wl,-1+'0'              ;Hunderter-Stelle als ASCII-Zeichen,
5
Zahl
6
                            ;ist positiv
7
 inc wl                     ;Hunderter hoch und
8
 subi xl,100                ;100 subtrahieren bis negativ wird
9
 brsh pc-2                  ;negativ? nein, 2 Zeilen hoch
10
 cpi wl,'0'                 ;ja, ist Ziffer = "0"?
11
 breq pc+2                  ;ja, nicht ausgeben...
12
 rcall lcd_data             ;Hunderter ausgeben...
13
 ldi wl,10+'0'              ;Zehner-Stelle als ASCII-Zeichen, Zahl
14
                            ;ist negativ
15
 dec wl                     ;Zehner runter und
16
 subi xl,-10                ;10 addieren bis positiv wird
17
 brlo pc-2                  ;positiv? nein, 2 Zeilen hoch...
18
 rcall lcd_data             ;ja, Zehner Stelle ausgeben...
19
 ldi wl,'0'                 ;ASCII-0
20
 add wl,xl                  ;Einer addieren (Rest war ja positiv)
21
 rcall lcd_data             ;Einer ausgeben...
22
 pop wl                     ;Reg wiederherstellen
23
 ret                        ;zurück

Grins, duck & weg...

...

von Karl H. (kbuchegg)


Lesenswert?

@Hannes

Ich denke mal Du hast nichts dagegen, wenn ich diesen Code,
so wie vieles andere von Dir Geschriebene, einfach verwende.
Ich finde naemlich, dass Dein Assembler extrem gut zu lesen
und zu verstehen ist.

Das musste naemlich auch mal gesagt werden!

von Hannes L. (hannes)


Lesenswert?

@Karl Heinz:

Erstmal danke für das Lob...

Was soll ich denn dagegen haben? Ist doch auch nur zusammengestoppelt,
aufbereitet und dabei auf das Niveau eines Hobbybastlers gebracht. Aber
er ist verstanden , besteht also nicht nur aus zusammengesuchten
unverstandenen Schnipseln.

Die 'gute Lesbarkeit' hat damit zu tun, dass ich den Code ja selbst
verstehen möchte, wenn ich ihn nach Wochen oder Jahren wieder lese.

Bit- & Bytebruch...
...HanneS...

von Profi (Gast)


Lesenswert?

Schonmal über sowas nachgedacht:

#include<stdio.h>
unsigned char byt;
void main(void){
  for(byt=0;byt<255;byt++){
    printf("%d%d%d ",byt/100,byt%100/10,byt%10);
  }
}

Sollte in Asm auch nur ein paar Zeilen sein, denn div (/) und mod
(%)können die meisten µC in Asm.

Führende Nullen unterdrücken:
    printf("%c%c%d ",byt/100?'0'+byt/100:' ',
                     byt/10?'0'+byt%100/10:' ',
                     byt%10);

von peter dannegger (Gast)


Lesenswert?

@Profi,

printf macht auf nem 8051 erstmal nen riesen Hopser um 2kB nach oben.
Anders gesagt, ein AT89C2051 macht sofort die Grätsche (hat nur 2kB).

Und der AVR hat keine Division.

Dein Rat war also richtig gut um zu zeigen, wie man es nicht machen
sollte !


Peter

von peter dannegger (Gast)


Lesenswert?

@HanneS

Ich mußte erstmal nachgucken, daß BRSH = BRCC ist.

Der Kommentar zu Zeile 9 ist nicht ganz korrekt, da das Carry nur für
positive Zahlen gilt. Man sollte wohl besser von Überlauf und Unterlauf
sprechen.

Und deshalb darf man auch nicht die Vergleiche für vorzeichenbehaftete
Zahlen (BRPL, BRMI) nehmen, sonst stimmen Werte über 227 nicht mehr.


Peter

von Hannes L. (hannes)


Lesenswert?

@Peter:

Danke...

> Der Kommentar zu Zeile 9 ist nicht ganz korrekt, da das Carry nur
> für
> positive Zahlen gilt. Man sollte wohl besser von Überlauf und
> Unterlauf
> sprechen.

Dann werde ich aus:

brsh pc-2                  ;negativ? nein, 2 Zeilen hoch

wohl

brsh pc-2                  ;Unterlauf? nein, 2 Zeilen hoch

machen müssen...

Auf BRPL und BRMI bin ich anfangs auch gelegentlich reingefallen, ist
mir aber schon lange nicht mehr passiert. Inzwischen benutze ich BRSH
und BRLO nicht mehr, dafür BRCC und BRCS (ist ja das selbe), das
erscheint mir irgendwie logischer bzw. direkter. Aber da besteht bei
mir noch etwas Lernbedarf, so richtig sattelfest bin ich da noch
nicht...

Gruß...
...HanneS...

von Jogibär (Gast)


Lesenswert?

Ja wunderbär, mit BRCS statt BRMI klappt das ganze.

Dankeschön Jogibär.

von Conlost (Gast)


Lesenswert?

Freut mich wenn ich helfen konnte.

Es grüsst,
Arno

von Profi (Gast)


Lesenswert?

@Peter:
tut mir leid, ich wußte nicht, dass der AVR keine Div kann. Habe damit
noch nichts gemacht.

Das mit dem C-Programm und dem printf sollte ja nicht heißen, dass man
es so programmieren soll, sondern rein als Denkanstoß, dass es außer
der Subtraktionsmethode auch noch andere Wege gibt.

>Dein Rat war also richtig gut um zu zeigen, wie man es nicht machen
sollte !

besser: ... wie man es nicht auf einem µC, der kein div und mod kann,
machen sollte.

z.B. auf einem 68hc908 läuft das nämlich wunderbar, ist halt ein CISC.

Deshalb hier noch der Code für 16-bit-Ausgabe:
#include<stdio.h>
unsigned int w;  //Word
void main(void){
  for(w=0;w<567;w++){
    printf("%d%d%d%d%d
",w/10000,w%10000/1000,w%1000/100,w%100/10,w%10);
  }
}

Führende Nullen unterdrücken:
    printf("%c%c%c%c%d   ",
       w/10000?'0'+w     /10000:' ',
       w/ 1000?'0'+w%10000/1000:' ',
       w/  100?'0'+w% 1000/ 100:' ',
       w/   10?'0'+w%  100/  10:' ',
       w%10);
Läuft natürlich auf einem 16-bitter optimal, auf einem 8-bitter gibt es
bestimmt elegantere Methoden.

Code aus dem Stegreif gedichtet, ohne ihn kontrolliert zu haben.

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.