Forum: Mikrocontroller und Digitale Elektronik LCD ansteuerung (ausgabe von variablen wörtern bzw. zahlen)


von Manuel (Gast)


Lesenswert?

Hallo!

Ich habe Mir eine Schaltung mit nem LCD aufgebaut, und den code aus
dem
LCD tut einigermaßen übernommen.
Es funktioniert auch alles wunderbar...

Doch nun solls ja weiter gehen, ich will eben nicht nur das wort
"Test" ausgeben, sondern eventuell verschiedene zahlen die in den
registern abgelegt sind.
Dies können sowohl einstellige, als auch mehrstellige zahlen sein.

Im Tut wurde ja schon erwähnt das es bei großen textausgaben nicht
sinnvoll sei, wegen jedem Buchstaben ein "lcd_data" aufzurufen.
Vielmehr ist das auch sehr schwer umzusetzen.

Wie kann ich nun vorgehen wenn ich zb. einen Taster habe der pro
tastendruck eine Zahl (sagen wir Null) inkrementiert.
Der Wert soll bis sagen wir 999 hochgezählt werden und dann wieder bei
null beginnen.

Erste frage:
Kann man die Zahlen binär hochzählen und dann jeweils durch 10 teilen
und die Nachkommastelle dann in ASCII umwandeln und zum LCD senden?
Oder hat jemand eine Idee wie es vernünftiger zu realisieren ist.
Ich habe mir da noch nicht soviele Gedanken darüber gemacht.

Zweite frage:
Wie kann ich es umgehen bei jedem Zeichen die routine "lcd_data"
aufzurufen?


MfG
Manuel

von johnny.m (Gast)


Lesenswert?

> Kann man die Zahlen binär hochzählen und dann jeweils durch 10
> teilen und die Nachkommastelle dann in ASCII umwandeln und zum LCD
> senden?
Kann man prinzipiell so machen, ist aber eher umständlich. Wenn Du in C
programmierst, ist das recht einfach. In der stdlib.h gibts dafür
fertige Funktionen (itoa z.B. erzeugt aus einer Binärzahl (Integer)
einen ASCII-String, den man direkt ans LCD senden kann). Wenn Du
AVR-GCC-C benutzt, dann schau mal in die Doku der AVR-libc, da ist das
beschrieben.

itoa(Wert, String, Basis)
speichert im String "String" die ASCII-Zeichen für die
Integer-Variable "Wert" ab, und zwar dargestellt mit der angegebenen
Basis (z.B. Basis = 10 für Dezimal- und Basis = 16 für
Hexadezimal-Darstellung).

Beispiel:
unsigned int zaehler = 65432;
char string[6];
//....
itoa(zaehler, string, 10);

Jetzt enthält string den ASCII-String "65432" mit abschließendem
Nullterminator (deshalb auch ein 6er-Array für die max. 5 Stellen einer
Integer-Variable). Den String kann man jetzt wie gewohnt ausgeben.

von Karl heinz B. (kbucheg)


Lesenswert?

> Kann man die Zahlen binär hochzählen und dann jeweils durch 10
> teilen und die Nachkommastelle dann in ASCII umwandeln und zum LCD
> senden?
> Oder hat jemand eine Idee wie es vernünftiger zu realisieren ist.

Genau so macht man das.
Alternativ könnte man die Division durch 10 einsparen, wenn
man nicht binär zählt, sondern in BCD.
Also nach 0x09 kommt nicht 0x0A sondern 0x10 usw.
Dann stellt jedes Nibble schon ein fertiges Digit dar. Man
muss es nur noch extrahieren, den Code für '0' noch addieren
und hat schon das Zeichen das zum LCD muss.

> Wie kann ich es umgehen bei jedem Zeichen die routine "lcd_data"
> aufzurufen?

Gar nicht.
Letztendlich muss immer für jedes Zeichen lcd_data aufgerufen
werden, da ja das Zeichen zum LCD übertragen werden muss und genau
das ist der Job von lcd_data.

Was das Tut meint (und nie ausgeführt hat), ist wenn du einen
längeren konstanten Text ausgeben willst. Dann macht man das
nicht dadurch dass man händisch jedes Zeichen einzeln angibt.
Stattdessen definiert man sich einen konstanten String und schreibt
eine Funktion der man die Startaddresse dieses Strings übergibt.
Die Funktion geht dann in einer Schleife durch die Bytes des Strings
durch, lädt jeden einzelnen und schickt ihn per lcd_data zum LCD.

von pumpkin (Gast)


Lesenswert?

ich will ja nicht klugscheissen (wie es leider zu oft der fall hier
ist), aber das ist imho nicht ganz korrekt:

>>unsigned int zaehler = 65432;
>>char string[6];
>>//....
>>itoa(zaehler, string, 10);
>>
>>Jetzt enthält string den ASCII-String "65432" mit abschließendem
>>Nullterminator (deshalb auch ein 6er-Array für die max. 5 Stellen
>>einer Integer-Variable). Den String kann man jetzt wie gewohnt
>>ausgeben.

ein string[5] reicht, da bei string[0] angefangen wird. also insgesamt
6 8bit felder, wobei string[6] der /0 entspricht (NULL).
sorry, nicht böse sein, aber das musste klargestellt werden.

pumpkin

von Manuel (Gast)


Lesenswert?

@ johnny.m
Vielen dank für den Tipp, aber meine C Kenntnise bewegen sich leider
auf ziemlich niedrigem Niveau.
Stattdessen programmiere ich lieber in Assembler wobei ich da auch nur
die nötigsten Grundkenntnisse habe, und noch ein wenig das know how zu
solchen problemen fehlt.

@Karl Heinz Buchegger

Also wenn ich nun die Zahl 17 habe (0b10001) die binär in ein register
passt, brauche ich für die ausgabe 2 register da ich jede stelle
einzeln als ASCII speichern muss?

Existieren irgendwo codebeispiele um die Ausgebe eines ganzen Strings
dynamisch zu erledigen?
Ich habe bis jetzt leider noch nichts gefunden...

von Stefan (Gast)


Lesenswert?

> pumpkin:
> ein string[5] reicht

Dein IMHO trügt dich.

char string[5];

schafft ein Array für fünf char Elemente. Der Index des Arrays darf
somit von 0 bis 4 laufen. '65432' enthält fünf einzelne Zeichen, das
passt. Aber ein abschliessendes, unbedingt notwendiges Nullbyte passt
nicht mehr rein. Das ist also ein klassischer Kandidat für einen
Bufferoverflow.

von Michele B. (luxx) Benutzerseite


Lesenswert?

ja manuel ich habe es so gemacht:
4 register:
- register1: der wert der ausgegeben werden soll
- 3 register: hunderter, zehner, einer
nun prüfe ich ob der auszugebende wert über hundert leigt, wenn ja
ziehe ich hundert ab und inkrementiere reister "hunderter". So lange
bis der wert unter hundert liegt, dann mache ich mit zehner und einern
das gleiche.

der vorteil ist, dass man wenn man sich die ASCII-Tabelle des
LCD-Controllers ansieht, sieht dass alle zahlen in einer reihe liegen,
man muss also zu jedem register(hunderter,zehner,einer) nur noch
0b00110000 addieren und das register per lcd_data ans lcd zu senden.

Fertig.

Ich hoffe das hilft dir weiter.

luxx

von pumpkin (Gast)


Lesenswert?

@stefan (alle anderen gucken bitte weg ; )  ):

string[0]: 6
string[1]: 5
string[2]: 4
string[3]: 3
string[4]: 2
string[5]: NULL

auszug C for dummies (öl ins feuer? g):

"[...]
char var[laenge];

laenge zeigt die anzahl der zeichen an, die der string enthalten
kann. [...]"

pumpkin

von Stefan (Gast)


Lesenswert?

> laenge zeigt die anzahl der zeichen an, die der *string*
> enthalten kann.

Richtig. Und jetzt zähl mal in deinem Falschbeispiel ;-)

von Hannes L. (hannes)


Lesenswert?

Nachdem der Thread ins C abgedriftet ist, Manuel aber in AVR-Assembler
arbeiten will, möchte ich auf eine (unfertige) Routinensammlung
verweisen, die all das macht, was Manuel sucht:
http://www.mikrocontroller.net/forum/read-1-164017.html#164028
Mit "unfertig" meine ich, dass die Routinen bei Bedarf ergänzt,
abgeändert oder aus Platzmangel gestrichen werden.

...

von pumpkin (Gast)


Lesenswert?

kränk, ich muss gestehen, du hast recht. seit wann gehört das NULL byte
dazu? scheinbar schon immer. sorry, ich war zu sehr davon überzeugt
dass ich recht habe.

pumpkin

von johnny.m (Gast)


Lesenswert?

Ist wieder so ein typischer (Rein)Fall, den man leider allzu oft sieht.
Bei der Deklaration wird die Anzahl der Elemente angegeben, beim
Zugriff die laufende Nummer, und die Zählung beginnt nunmal bei Null...

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.