Forum: Compiler & IDEs Variabel an LCD ausgeben


von Sepp (Gast)


Lesenswert?

Hallo

Ich habe eine Frage was die lcd library von Peter Fleury betrift.

Bei mir funktioniert sie eigentlich sehr gut, nur habe ich es noch
nicht geschaft eine Variabel (char, int, eigentlich egal was) als
Dezimalzahl ans LCD auszugeben.

Weiss jemand ob das überhaupt möglich ist und wenn ja wie es
funktioniert?

Für eure Antworten danke ich euch schon im voraus.

Gruss Sepp

von Fritz Ganter (Gast)


Lesenswert?

sprintf oder itoa

von Sepp (Gast)


Lesenswert?

Danke für die schnelle Antwort.

Ist sprintf nicht ein Befehl zur Ausgabe an ein Terminal???
Wie muss ich itoa anwenden?

Vieleicht meine Frage noch mal etwas genauer:

Eine Variabel (unsigned char Test;) soll über den Befehl lcd_puts();
aus der LCD Library von Peter Fleury als Dezimalzahl an ein LCD
ausgegeben werden. Wie geht dass?

Falls du mit deiner Antwort genau dass gemeint hast, bitte ich um
weitere Erklärungen, denn ich habs anscheinend nicht kapiert.

von Daniel Jelkmann (Gast)


Lesenswert?

Hi,

Fritz hatte schon recht, mit itoa() oder sprintf() kannste das machen.
itao() geht nur für Zahlen, sprintf() kann im Vergleich mehr, aber
beide schreiben die Werte in einen Buffer rein, den Du übergibst. Dann
musst Du nur noch die Zeichen aus dem Buffer einzeln per lcd_puts() an
das LCD senden. Die genaue Syntax für die beiden Funktionen hab ich
gerade nicht im Kopf, da musste selbst mal suchen. sprintf() ist glaube
ich genau wie printf(), nur dass Du vorher einen ausreichend großen
Buffer angibst. Könnte dann so aussehen:

char buffer[10];
int zahl = 42;
sprintf(buffer, "Zahl: %d", zahl);
while (...)
  lcd_puts(buffer[i]);


Bye
  Daniel Jelkmann

von Fritz Ganter (Gast)


Lesenswert?

Nein, nein! lcd_puts gibt schon den string aus, lcd_putc macht es
zeichenweise.

es geht z.b. so:

char text[34];

sprintf(text,"Es ist %02d:%02d Uhr", stund, min);

Ergibt: Es ist 09:15 Uhr

Mehr dazu gibts in der Doku der avr-libc. Wennst Linux hast kannst auch
"man 3 printf" in der Konsole eingeben.

von Sepp (Gast)


Lesenswert?

Ok; ich habe die erste Methode getestet (von Daniel Jelkmann) und das
funktioniert wunderbar!!

Jetzt kommt aber bereits das nächste Problem:

Mit diesem Befehl wird mein Programm um unglaubliche 5KB grösser!!!!!

Da kann ich mit meinem AT90S8535 nicht mehr gerade viel anfangen (8KB
SRAM).

Gibts da keine platzsparendere Möglichkeit? Muss ein neuer uP her?

von Jörg Wunsch (Gast)


Lesenswert?

Wenn Du den Komfort von printf() haben willst, braucht das viel Platz.
Steht auch in der Doku.  Es gibt drei verschiedene Varianten von
printf-Bibliotheken:

* Standard, kann alles außer Gleitkomma
* minimal, kann keine Feldweiten, keine Füllzeichen, fast nichts,
  taugt eigentlich bestenfalls fürs Debuggen
* voll, d. h. Standard + Gleitkomma

Wenn Du wirklich 5 KB mehr Flash brauchst, vermute ich allerdings, daß
Du die Gleitkommavariante ausgewählt hast.  Brauchst Du diese denn
überhaupt?  Auf einem AT90S8515 ist der Unterschied in der Codegröße
zwischen Standard und Gleitkomma fast 2 KB, außerdem braucht die
Gleitkommaversion noch malloc(), wenn Du das sonst nicht benötigst,
ist das nochmal ein halbes KB.

Wenn Du knapp mit Flash dran bist, mußt Du Dir halt die Ausgaben
selbst zimmern.  Auch dafür bietet die Bibliothek Basisroutinen, siehe
Doku.

Meist lohnt es sich, sich über solche Kleinigkeiten vorher klar zu
werden.  Die zwei Euro mehr für einen ATmega16 statt eines ATmega8
(der AT90S8535 ist sowieso Auslaufmodell) machen das Kraut gerade bei
einem Einzelstück nicht fett, wenn Du Dir überlegst, wie viel
umständlicher Du dafür dies oder jenes jetzt vielleicht machen mußt,
nur weil printf() nicht mehr reinpaßt.  Zusätzlich kann man den
ATmega16 sogar noch via JTAG debuggen, wenn's eng wird.

Die gute Nachricht: der ATmega16 ist pinkompatibel zum AT90S8535...

von Fritz Ganter (Gast)


Lesenswert?

Ich hab bei mir lcd_puts vergessen, sorry.

Trotzdem ist seine Methode unnötig kompliziert, es muss heissen:

char text[34];

sprintf(text,"Es ist %02d:%02d Uhr", stund, min);
lcd_puts(text);

Leider wird das Programm grösser, aber dafür hast du die ganze printf
Funktionen zur Verfügung. Wenn du keine Fliesskomma Sachen brauchst,
kannst du es anders linken:
LDFLAGS += -Wl,-u,vfprintf -lprintf_min

von Sepp (Gast)


Lesenswert?

Vielen Dank für Eure Tipps.

Ich habe mich entschieden dass ich mir einen Atmega 128 oder was
ähnliches anschaffe; der Aufwand lohnt sich wirklich nicht, und ein
neuer uP ist sowieso schon lange fällig.

von Jörg Wunsch (Gast)


Lesenswert?

Ja, zum Experimentieren ist der '128 auf alle Fälle zu empfehlen.
Platz ohne Ende. :-)

Aber Vorsicht mit -lprintf_min: Formatieranweisungen wie %02d
degradieren dann zu %d -- Feldbreite, Precision usw. wird in der
Minimalvariante schlicht ignoriert.  Dafür ist sie eben die
Minimalvariante.

Einfach nichts weiter an Linkeroptionen angeben und die
Standardvariante benutzen.

von Daniel Jelkmann (Gast)


Lesenswert?

Hi,

sorry, mit dem lcd_puts() hat Fritz natürlich recht, da wird gleich der
ganze String ausgegeben. Dann muss die while(...)-Geschichte natürlich
raus und einfach ein lcd_puts(buffer); dahin...

Wenn Dir die printf()-Geschichte zu groß wird und Du nur einfache
Sachen ausgeben willst, kannst Du es Dir auch selbst zusammencoden, wie
Jörg schon schreibt. Wenn Du z.B. weisst, dass die Variable nie größer
als 999 wird und Du somit mit 3 Stellen auskommst, könntest Du das so
machen:

int zahl = 987;
char buffer[4]; // 3 Ziffern + Nullzeichen
buffer[0] = 48 + zahl / 100 % 10;
buffer[1] = 48 + zahl / 10 % 10;
buffer[2] = 48 + zahl % 10;
buffer[3] = 0;
lcd_puts(buffer);

Die 48 entspricht dem Zeichen 0 in der ASCII-Tabelle, 49 der 1, 50 der
2, usw. Das sollte dann eigentlich klappen. (Wenn Du keine führenden
Nullen haben willst, musst Du if-Abfragen einbauen.)

Bye
  Daniel Jelkmann

von Jörg Wunsch (Gast)


Lesenswert?

Hmm, erstmal Verbesserungsvorschlag für den gezeigten Code:

int zahl = 987;
div_t d;
char buffer[4]; // 3 Ziffern + Nullzeichen

d = div(zahl, 10);
buffer[2] = '0' + d.rem;
d = div(d.quot, 10);
buffer[1] = '0' + d.rem;
d = div(d.quot, 10);
buffer[0] = '0' + d.rem;
buffer[3] = 0;
lcd_puts(buffer);

div() ist eine der weniger bekannten Funktionen des C-Standards.  Sie
nutzt sich die Tatsache aus, daß bei einer Division auch immer
automatisch der Rest (Modulus) berechnet wird, so daß man beide
Ergebnisse auch gleich gemeinsam zurückgeben kann.  Intern wird für
div(), den Operator / oder den Operator % jeweils dieselbe Funktion
gerufen.  Da die Division die kostpieligste Grundrechenart ist, kann
man damit Rechenzeit sparen.

Es wird natürlich auch offensichtlich, daß man um alles auch gleich
eine Schleife schreiben kann. ;-)

Die Benutzung von '0' statt 48 verdeutlicht optisch, daß man hier
nicht an einer Zahl, sondern an einem ASCII-Zeichen interessiert ist.
(Sie hat den zusätlichen Vorteil, daß man damit standardkonform völlig
unabhängig vom benutzten Zeichensatz ist, da der C-Standard
vorschreibt, daß die Ziffern im `char' alle aufeinanderfolgend
abgebildet sein müssen.)

Man kann natürlich genausogut auch itoa() benutzen.  Siehe Doku.

von Daniel Jelkmann (Gast)


Lesenswert?

Hi Jörg,

danke für Deinen Verbesserungsvorschlag. Das mit dem div() hab ich noch
 in keinem Code so gesehen, nur in der AVR-Doku :) Aber der Vorteil
leuchtet ein und es scheint ja durchaus sinnvoll zu sein, ich werde mir
versuchen es zu merken und auch in Zukunft anzuwenden.

Bye
  Daniel Jelkmann

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.