Ich möchte gerne den Wert eines ADC als Balkengrafik auf einem 16x2 LCD
darstellen.
Dafür habe ich mir schon mal einen selbst definierten Zeichensatz
erstellt.
Den ersten Schritt dazu habe ich bereits gemacht.
Indem ich mal einfach den ADC Wert 1-5 als Zeichen ausgebe.
Jetzt müßte ich jedoch nach jedem dieser Schritte auf die nächste
Cursorposition stellen und den Zähler zurücksetzen.
Hat jemand einen Tipp wie man hier am besten ran geht. Oder wie würdet
ihr das machen?
Ein funktionierendes Beispiel dazu hätte ich hier zwar gefunden:
https://www.electronicsblog.net/arduino-lcd-horizontal-progress-bar-using-custom-characters/
Dies bläht den Speicher des ATmega 8 allerdings wieder dermaßen auf, da
hier mit Kommastellen gerechnet wird.
Aber das müßte doch Platzsparender gehen, oder?
Lokus Pokus schrieb:> Hat jemand einen Tipp wie man hier am besten ran geht. Oder wie würdet> ihr das machen?
Ganze Blöcke ausgeben und das Wandlungsergebnis runterzählen, bis der
Rest kleiner als 5 oder 6 ist und dann das passende Sonderzeichen mit
1..4 Elementen.
> Dies bläht den Speicher des ATmega 8 allerdings wieder dermaßen auf, da> hier mit Kommastellen gerechnet wird.
Wozu das. Dein Display hat bestenfalls 80 oder 96 Elemente. Da reicht
Festkommaarithmetik von der Dynamik völlig aus. Ein Komma kannst du
trotzdem in der Anzeige ausgeben.
Was Flash-Speicher kostet, ist die Float Bibliothek.
16 Zeichen mit jeweils 5 Reihen. Also genau 80 Werte wären das.
Der ADC liefert mir auf der Anzeige die Werte von 0 bis 100 (%)
Somit nur Ganzzahlenwerte, keine Nachkommastellen.
1
intmain(void)
2
{
3
init();
4
charbuffer[4];
5
intstelle=0;
6
7
lcd_puts_P("Schwellwert %\n");// Text von Flash auf LCD ausgeben
8
9
// lcd_puts_P("Helligkeit %\n"); // Text von Flash auf LCD ausgeben
Lokus Pokus schrieb:> 16 Zeichen mit jeweils 5 Reihen. Also genau 80 Werte wären das.>> Der ADC liefert mir auf der Anzeige die Werte von 0 bis 100 (%)> Somit nur Ganzzahlenwerte, keine Nachkommastellen.
Dann multiplizierst du deinen ADC-Wert mit 10 und teilst ihn durch 128
(ganzzahlig). Dann bekommst du die Anzahl der Segmente. Die teilst du
solange durch 5 und gibst jeweils immer einen 5er-Block aus, bis das
Ergebnis kleiner als 5 ist. Den Rest gibst du als Zeichen mit der Breite
des Rests aus (1..4).
Falk Brunner schrieb:> Festkommaarithmetik>> Immer noch nicht verstanden? Hmmm.
Falls du mich meinst, ich habe mich da nur falsch ausgedrückt.
npn schrieb:> bis das> Ergebnis kleiner als 5 ist. Den Rest gibst du als Zeichen mit der Breite> des Rests aus (1..4).
Soll heißen:
"Dieses Ergebnis gibst du als Zeichen mit der Breite
des Zahlenwertes aus (1..4)."
Der Begriff "Rest" war vielleicht irreführend, weil er klingt, als
wollte man Kommastellen benutzen und auswerten.
Lokus Pokus schrieb:> Jetzt müßte ich jedoch nach jedem dieser Schritte auf die nächste> Cursorposition stellen und den Zähler zurücksetzen.>> Hat jemand einen Tipp wie man hier am besten ran geht. Oder wie würdet> ihr das machen?
ADC Wert von 0-100
1
zeichen=Wert%5;
2
position=Wert/5;
3
// Wenn position > 0, einfach in einer Schleife von 0 bis position - 1
4
// Zeichen 5 ausgeben, in position zeichen einschreiben.
EDIT:
npn schrieb:> Dann multiplizierst du deinen ADC-Wert mit 10 und teilst ihn durch 128> (ganzzahlig). Dann bekommst du die Anzahl der Segmente. Die teilst du
Ja, das solltest du vorher machen, nur mit 100 multiplizieren.
Hallo Lokus Pokus,
willst Du eine eigene Software implementieren oder ein vorhandenes
Beispiel bei Dir einbauen?
Wenn Du es selbst implementieren möchtest, gehe ich mangels besserer
Infos von folgenden Bedingungen aus:
a) Du willst alle 16 Zeichen in einer Reihe verwenden
b) Der Bargraph wächst horizontal von links nach rechts
c) Dein ADC ist Masse bezogen und gibt also Spannungswerte von 0..x aus
d) 12Bit ADC -> Spannung: 0 ... 4095
a+b: Zur Display-Initialisierung müssen 6 Zeichen im cgram des Displays
angelegt werden, wobei jedes Zeichen aus 8 Byte besteht, z.B. so:
Das Resultat sieht dann aus, wie in meinem Anhang. In meinem Foto werden
jedoch statt 16 nur 6 Zeichen auf dem LCD verwendet - das Prinzip ist
natürlich gleich.
Jetzt nimmst Du Deine 16 Zeichen und entscheidest, welche zu 100% oder
zu 0% ausgefüllt sind, die bekommen das entsprechende Zeichen. Eines der
16 LCD-Zeichen ist zum teil gefüllt, hier musst Du dann etwas Code
bemühen:
4095 ADC-Werte / 5x16 = 51 --> also 1 LCD-Bit innerhalb eines
LCD-Zeichens stellt 51 Digits Deines ADC dar.
Viel Spaß beim Basteln
Marc Vesely schrieb:> EDIT:> npn schrieb:>> Dann multiplizierst du deinen ADC-Wert mit 10 und teilst ihn durch 128>> (ganzzahlig). Dann bekommst du die Anzahl der Segmente. Die teilst du> Ja, das solltest du vorher machen, nur mit 100 multiplizieren.
Sorry, war mein Fehler. Weil der TO von ADC geschrieben hatte, ging ich
von einem Maximal-ADC-Wert von 1023 aus, deshalb die 10. Dann klappt der
Rechenweg auch, wie ich ihn geschrieben hatte. Einverstanden? :-)
Lokus Pokus schrieb:> wieso "position = Wert / 5?"> Es sind doch 16 Zeichen die dargestellt werden können am LCD.
Ich hab das nur so aus dem Kopf geschrieben, npn schrieb doch
wie man die Zahl der Segmente kriegt, schien mir logisch, habe
es nicht weiter geprüft, aber jetzt denke ich, dass es mit 125
auch klappen muss.
Auf jeden Fall löse dich von der Annahme, Fließkomma Zahlen zu
benötigen.
Der ADC des AVR Mikrocontrollers meldet (z.B.) 4,99 Volt als 1023. Na
klingelt es? Der ADC braucht dazu auch keine Fließkommazahlen.
Mal ein ganz simples Beispiel: Angenommen, du wilst 50 Klötzchen bei 5
Volt anzeigen. Dann teilst Du einfach den Meßwert des ADC durch 20
(benzugnehmend auf obiges Beispiel). 1024/20=50 und ganz ohne Fließkomma
Zahlen.
Oder anders gesagt: 1,5 Meter kann man auch als 150 Zentimeter
bezeichnen - und schon kommt man ohne Fließkommazahlen aus.
Dieses Prinzip kannst Du sicher auch auf Deine Anwendung übertragen.
Wieso 125, wieso 128? Eure Rechnungen gehen mir nicht ganz ein.
Ich habe 16 Zeichen. Pro Zeichen 5 Segmente, dass wären 80 Segmente im
gesammten.
Der Maximalwert der ADC ist 100. (oder 1023 wenn man ihn direkt
ausliest)
Lokus Pokus schrieb:> Wieso 125, wieso 128? Eure Rechnungen gehen mir nicht ganz ein.> Ich habe 16 Zeichen. Pro Zeichen 5 Segmente, dass wären 80 Segmente im> gesammten.> Der Maximalwert der ADC ist 100. (oder 1023 wenn man ihn direkt> ausliest)
Was willst du denn jetzt anzeigen?
ADC-Wert bis 80% oder soll der Wert vorher auf die 80 skaliert werden?
Also ganzer Balken = 100%.
mfg.
@ Lokus Pokus (derschatten)
>Wieso 125, wieso 128? Eure Rechnungen gehen mir nicht ganz ein.>Ich habe 16 Zeichen. Pro Zeichen 5 Segmente, dass wären 80 Segmente im>gesammten.>Der Maximalwert der ADC ist 100. (oder 1023 wenn man ihn direkt>ausliest)
Na dann lies du mal den Artikel Festkommaarithmetik und besorg die
Prozentrechnung, das ist Mathematik Klasse 7 oder so.
Lokus Pokus schrieb:> Wieso 125, wieso 128? Eure Rechnungen gehen mir nicht ganz ein.> Ich habe 16 Zeichen. Pro Zeichen 5 Segmente, dass wären 80 Segmente im> gesammten.> Der Maximalwert der ADC ist 100. (oder 1023 wenn man ihn direkt> ausliest)
1023 x 10 / 128 = 79,92 (gerundet 80)
Alles klar? :-)
Bei einem Endwert von 1023 kann man es sich vielleicht auch so deutlich
machen:
Hier sei jedes des 16 LCD-Zeichen durch 5 Character dargestellt. Immer
nach diesen 5 Charactern (also immer zwischen jedem LCD-Zeichen) steht
der ADC-Wert auf dieser Anzeige-Skala:
[#####] [#####] [#####] [##___] [_____] [_____] ... [_____]
0 64 128 192 256 320 384 960 1024
Lokus Pokus schrieb:> ok, nun weiß ich aber immer noch nicht wie ich nach 5 Segmenten> zum> nächsten Zeichen springe.
Du gibst so viele vollständig gefüllte Kästchen aus, wie die Division
durch 5 ganzzahlig ergibt. Beispiel 76 durch 5 ergibt 15. Also gibst du
15 vollständig gefüllte Kästchen aus. Dann kommst der Rest. Weil 15 mal
5 gleich 75 ist und der Ausgangswert aber 76 ist, bleibt ein Rest von 1.
Also gibst du nach den 15 gefüllten Kästchen noch ein Zeichen aus, was
ein Segment darstellt. Bei 77 wäre das dann das Zeichen, was 2 Segmente
darstellt und so weiter. Jetzt klar? :-)
Ja, so wie hier die ersten beiden:
http://www.mikrocontroller.net/attachment/233039/LCD_Bargraph.JPG
Das dritte wäre dann ein Zeichen, was drei Segmente von 5 darstellt.
Die Zeichen mit 1 bis 4 Segmenten mußt du natürlich, wenn sie noch nicht
im Zeichensatz des LCD vorhanden sind, selbst definieren. Das
ausgefüllte Kästchen ist meist im Zeichensatz des LCD enthalten.
// Wenn position > 0, einfach in einer Schleife von 0 bis position - 1
4
// Zeichen 5 ausgeben, in position zeichen einschreiben.
> ok, nun weiß ich aber immer noch nicht wie ich nach 5 Segmenten zum> nächsten Zeichen springe.
Du springst nirgendwo hin, höchstens der Cursor, aber auch das
ist nicht nötig, weil du zuerst die Zeichen mit allen 5 Segmenten
reinschreibst. Und an letzter Stelle kommt 'zeichen'.
Ein Zeichen hat 5 Segmente (0-5), Display hat 16 Stellen (0-15).
Thomas Eckmann schrieb:> In diesem Sinne:>> unsigned char GK = ADC_Wert / 5;> for(unsigned char i = 0; i < GK; i++)> {> SchreibGanzeKaestchen();> }> SchreibRestKaestchen(ADC_Wert % 5);>> mfg.
Genau richtig. Wenn man die "Restkaestchen" als Zeichenadresse 1..4 im
LCD definiert und das LCD 20 Stellen hat, passt das. Wir haben hier aber
16 Stellen.
Wenn man als maximalen ADC-Wert 100 nimmt, muß die Berechnung lauten:
1
GK=ADCx100/125/5
Da kommt maximal 16 raus, die maximale Anzahl der vollständigen
Kästchen.
GK muß aber uint16_t sein, char reicht hier nicht.
npn schrieb:> Genau richtig. Wenn man die "Restkaestchen" als Zeichenadresse 1..4 im> LCD definiert und das LCD 20 Stellen hat, passt das. Wir haben hier aber> 16 Stellen.
Die richtige Skalierung habe ich natürlich vorausgestzt.
mfg.
Thomas Eckmann schrieb:> Die richtige Skalierung habe ich natürlich vorausgestzt.>
Ist schon klar, aber ich wollte es für den TO nachvollziehbar schreiben.
Wenn er bei der Rechnung auf 20 Zeichen gekommen wäre (ADC_Wert / 5),
würde das wieder neue Fragen aufwerfen. Okay? :-)
Was ist denn hier los?
Nach gefühlten 30 Beiträgen wird es doch wohl möglich sein, per simplem
Dreisatz von 1023 auf 80 umzuskalieren.
Das ist nun wirklich Schulmathematik der 7. Klasse ...
Mike schrieb:> Was ist denn hier los?>> Nach gefühlten 30 Beiträgen wird es doch wohl möglich sein, per simplem> Dreisatz von 1023 auf 80 umzuskalieren.> Das ist nun wirklich Schulmathematik der 7. Klasse ...
Es geht hier nicht vorrangig um Skalierung, sondern wie man mit selbst
definierten Zeichen im LCD-Display einen Balken darstellt mit der
Auflösung von einem fünftel Zeichenbreite. Das ist ein klein wenig mehr.
:-)
Lokus Pokus schrieb:> was meinst du mit vollständig gefüllte Kästchen? Ein Zeichen mit 5x7> Pixel?
Ich hoffe so wird klar, was mit den Begriffen gemeint ist ...
Jedes der 16 LCD-Zeichen besteht aus 5x8 Punkten. Die 8 Punkte liegen in
einer Reihe übereinander - davon wiederum gibt es 5 Reihen
nebeneinander. Darum kann ein Segment aus 5 einzelnen "Schritten"
bestehen, z.B. 3/5 sind "an" wie im angehängten Bild (mit Legende).
Mike schrieb:> Lokus Pokus schrieb:>> Wie lösch ich nun die Zeichen aber wieder?>> Indem du Leerzeichen schreibst.
Stimmt, wenn er den Hintergrund nicht "schattig" gestaltet.
Wenn er mein Beispiel (schattig) zur gc-ram Initialisieurng verwendet,
muss er Zeichen[0] des gc-rams nutzen, um ein "leeres" LCD-Zeichen
darzustellen.
nicht so ganz.
Abgesehen davon funktioniert mein Beispiel oben auch nicht so ganz
flüssig.
Es füllt zwar beim drehen die Segmente, aber in willkürlicher Folge.
Das passt noch nicht.
Was ist eigentlich der besondere Sinn von * 100 / 125 ?
1
unsignedcharADC80=ADCvalue1*8/10;
2
unsignedcharGK=ADC80/5;
3
unsignedcharpeace=ADC80%5;
4
5
...
Kümmere dich nicht darum, dass es jetzt eine Variable mehr ist. Der
Compiler wird das optimeren.
Lokus Pokus schrieb:> Muß nicht schattig sein. Reicht eine Leerstelle.
Mach vor der Ausgabe eine komplette Leerzeile. Bring das erstmal damit
zum Laufen. Damit optimeren, dass nur ab dem peace-Zeichen gelöscht
wird, kannst du immer noch.
mfg.
Lokus Pokus schrieb:> Beim löschen bleibt mir jetzt nur noch ein Strich übrig, den ich weg> bekommen muß.
Wenn der Strich ganz hinten ist, dann versuch mal: