Forum: Mikrocontroller und Digitale Elektronik Arduino: OLED Display löscht Kommastelle nicht.


von Julian D. (juli_elektronik)


Lesenswert?

Ich habe wieder ein Problem mit meinem I2C OLED Display, angesteuert mit 
einem Arduino Uno.
Ich lese einen Wert ein (testweise mit einem Poti), rechne ihn um und 
gebe ihn auf dem dem Display wieder aus.
Die gemessene Spannung ist eine in einem Netzteil und ändert sich mit 
dem Ausgangsstrom. Hier ist mal der Sketch plus Schaltungssimulation.
https://wokwi.com/projects/325872467916620372
Das problem ist, wenn sich die Kommastelle veschiebt, weil z.b. der Wert 
vorher 8(A) war und jetzt 15, dann ändern sich zwar die Zahlen wie 
gewünscht, aber das Komma bliebt und überlagert sich mit der Zahl die 
dort hingehört. Beim Minus passiert das selbe, aber im fertigen Zustand 
wird dann eh nichts mehr nagativ, also ist das egal.
Aber wie schaffe ich es jetzt dass sich Komma und Zahl nicht mehr 
überlagern? Ich habe schon clearBuffer(); und auch clearDisplay(); vor 
dem sendBuffer(); ausprobiert, aber dann wird gar nichts mehr angezeigt.

Ideal wäre es, wenn das Komma einen fixen Platz hätte und sich nur die 
Zahlen herum ändern, aber ich weiß nicht wie das machbar ist. Der Wert 
10 müsste da ein bisschen weiter vorne geschrieben werden als z.B. 1. 
Oder davor einfach Leerzeichen als Platzhalter? Kann mir bitte jemand 
weiterhelfen?

Schönen Abend noch,
Julian

von Joachim B. (jar)


Lesenswert?

Julian D. schrieb:
> Hier ist mal der Sketch

hier ist er jedenfalls nicht, Code hier hochladen damit das später auch 
noch andere nachsehen können, das ist ein Forum!

von Julian D. (juli_elektronik)


Lesenswert?

1
#include <U8g2lib.h>
2
#include <Wire.h>
3
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
4
5
6
void setup() {
7
  // put your setup code here, to run once:
8
Serial.begin(9600);
9
u8g2.begin();
10
analogReference(DEFAULT);
11
}
12
void settings() {
13
   u8g2.setFont(u8g2_font_6x10_tr ); 
14
 u8g2.setFontRefHeightExtendedText(); 
15
 u8g2.setDrawColor(1);
16
 u8g2.setFontPosTop();
17
 u8g2.setFontDirection(0);
18
}
19
20
void loop() {
21
  // put your main code here, to run repeatedly:
22
23
int messung = analogRead(A0);
24
double spannung = messung / 204.8;
25
double strom = -45.411 + 44.5642 * spannung;
26
Serial.println(strom, 5);
27
String stromstr = String(strom, 5);
28
29
settings();
30
u8g2.drawStr(10, 10, stromstr.c_str());
31
32
u8g2.sendBuffer();
33
34
delay(100);
35
}

Hoffe der ist noch nicht zu lange. Funktioniert der Link gar nicht oder 
meinst du nur dass es besser ist wenn der Code auch hier steht?

von Wolfgang (Gast)


Lesenswert?

Julian D. schrieb:
> Ich habe schon clearBuffer(); und auch clearDisplay(); vor
> dem sendBuffer(); ausprobiert, aber dann wird gar nichts mehr angezeigt.

Vielleicht braucht der Display-Controller ein bisschen Zeit für das 
Löschen des Displays und du sendest ihm die neuen Daten, bevor er damit 
fertig ist.
Genaueres sollte im Datenblatt zu deinem Display stehen.
In den Code habe ich jetzt nicht geguckt - wer weiß, wo der Link 
hinführt.

von Joachim B. (jar)


Lesenswert?

Julian D. schrieb:
> Aber wie schaffe ich es jetzt dass sich Komma und Zahl nicht mehr
> überlagern?

anders programmieren

Erst mal baust du deinen String, ich schreibe das immer in ein 
Zeilenbuffer.
Mehr als 4- maximal 10 Aktualisierungen braucht kein Mensch ist nicht 
mehr lesbar, der µC ist viel schneller.
Ich schreibe in den Buffer wenn es sein soll, aber auf das Display nur 
wenn 25ms(100ms) um sind für 4(10) Updates/s

ich mittle auch einige ADC Werte je nach Bedarf 8 16 32 auf addieren und 
shift right 8->3 16->4 32->5

Neue Werte werden im Zeilenbuffer geschrieben also hast du das Problem 
nicht mit alten Daten!

Eine Ausnahme gibt es, der Zeichen Buffer im Oled wird nicht gelöscht, 
aber da du nichts zeigst ist das stochern im Nebel.

von Holger (Gast)


Lesenswert?

Julian D. schrieb:
> überlagern? Ich habe schon clearBuffer(); und auch clearDisplay(); vor
> dem sendBuffer(); ausprobiert, aber dann wird gar nichts mehr angezeigt.

u8g2.drawStr() wandelt die Daten in Pixel um und schreibt sie in einen 
Buffer. Wenn du danach clearBuffer() oder clearDisplay() aufrufst, sind 
die aufbereiteten Daten weg. Wenn du "clear" vor "drawStr" aufrufst 
sollte das funktionieren.

von Julian D. (juli_elektronik)


Lesenswert?

Wolfgang schrieb:
> In den Code habe ich jetzt nicht geguckt - wer weiß, wo der Link
> hinführt.

Er führt zu einem Arduino Schaltungssimulator, den benutze ich immer 
z.B. wenn ich zu faul bin meinen Arduino aufzubauen.
Und der Code stand übrigens auch schon vor deiner Antwort direkt im 
Forum ;)

Holger schrieb:
> Wenn du "clear" vor "drawStr" aufrufst
> sollte das funktionieren.

Danke, das hat funktioniert. Es wird alles angezeigt wie erwünscht, ohne 
Überlagerungen.

von Wolfgang (Gast)


Lesenswert?

Julian D. schrieb:
> Und der Code stand übrigens auch schon vor deiner Antwort direkt im
> Forum ;)

Er stand im Forum, bevor ich meine Antwort veröffentlicht habe, aber 
nicht, bevor ich auf Basis der vorhandenen Antworten angefangen habe, 
meine Antwort zu verfassen. Das ist ein kleiner Unterschied.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

clear ist ungünstig, weil jedesmal das gesamte Display gelöscht wird. 
Das führt zu flimmern, wirste später noch bemerken. In der Regel kennt 
man die maximale "Zeilenbreite" für sein Datenformat und löscht dahinter 
die nicht mehr benötigten Stellen mittels Leerzeichen. Das geht 
schneller und das gesamte Display flimmert nicht. Die Refreshrate 
langsamer stellen wurde schon erwähnt. Alles ohne delay dafür mittels 
millis lässt auch den Code nicht blockieren. Kannste ungebremst einlesen 
und filtern und unabhängig auf das Display ausgeben.

von Hugo H. (hugo_hu)


Lesenswert?

Veit D. schrieb:
> clear ist ungünstig, weil jedesmal das gesamte Display gelöscht wird.

Was meinst Du, was bei

Julian D. schrieb:
> sendBuffer();

passiert?

von Falk B. (falk)


Lesenswert?

Julian D. schrieb:
> Ideal wäre es, wenn das Komma einen fixen Platz hätte und sich nur die
> Zahlen herum ändern, aber ich weiß nicht wie das machbar ist.

In der Tat.

> Der Wert
> 10 müsste da ein bisschen weiter vorne geschrieben werden als z.B. 1.
> Oder davor einfach Leerzeichen als Platzhalter?

BINGO!

> Kann mir bitte jemand
> weiterhelfen?

Grundlagen von C. Nicht immer nur auf dem Arduino-Level rumplanschen.
Formatierte Zahlenausgabe ist das Zauberwort. Man brauch auch keine 
Fließkommazahlen mit DOPPELTER Genauigkeit, Festkommaartithmetik 
reicht locker, auch wenn man da mal drei Minuten nachdenken muss.
1
void loop() {
2
char tmp_string[10];
3
4
long strom = -45411L + (44564L * analogRead(A0)) >> 11;  // mA
5
strom /= 100;  // 0.1A Auflösung
6
Serial.println(strom, 5);
7
8
sprintf(tmp_string, "%+2d.%1d" strom/10, abs(strom%10))
9
settings();
10
u8g2.drawStr(10, 10, tmp_string);
11
u8g2.sendBuffer();
12
13
delay(100);
14
}

von Joachim B. (jar)


Lesenswert?

Julian D. schrieb:
> Holger schrieb:
>> Wenn du "clear" vor "drawStr" aufrufst
>> sollte das funktionieren.
>
> Danke, das hat funktioniert. Es wird alles angezeigt wie erwünscht, ohne
> Überlagerungen.

aber alles zu "clearen" für dem Neuprinten kann lahm sein und das 
Display zu flackern bringen wenn es zu oft gemacht wird.Ich kenne die 
LIB un nicht genau, aber ähnliches verwende ich auch bei TFT, wenn die 
Lib die Möglichkeit bietet auch schwarz (keine leuchtenden Pixel) statt 
farbig (leuchtende Pixel) zu printen, dann schreibt man in einen Puffer 
die geänterten Zeichen in schwarz, also kein Pixel leuchtet mehr und 
danach wieder die Änderung.

Der Vorteil man spart Prozessorzeit, Das Programm kann evtl. leichter 
arebeiten, es findet keine überflüssige "Löschung des ganzen Screens" 
statt und es wird nur veränderter Inhalt neu geschrieben!

Falk B. schrieb:
> Festkommaartithmetik
> reicht locker

Falk hat soooo Recht, mit etwas Nachdenken werden aus Fliesskomma Volt 
Integer Volt z.B. je nach gewünschter Stellenzahl mV cV dV, alles 
Integer!
Das Komma fügen wir im String ein, muss nicht groß float gerechnet 
werden
bei 5002 mV 5,002V
bei 502 cV 5,02V
bei 52 dV 5,2V

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Joachim B. schrieb:
> aber alles zu "clearen" für dem Neuprinten kann lahm sein und das

AUA!!!!!

http://kamelopedia.net/wiki/Denglisch

von Joachim B. (jar)


Lesenswert?

Falk B. schrieb:
> AUA!!!!!

nix aua, das war bewusst auf:

Hugo H. schrieb:
> Veit D. schrieb:
>> clear ist ungünstig, weil jedesmal das gesamte Display gelöscht wird.

Julian D. schrieb:
> Holger schrieb:
>> Wenn du "clear" vor "drawStr" aufrufst
>> sollte das funktionieren.

Beitrag #7001763 wurde vom Autor gelöscht.
von Olaf (Gast)


Lesenswert?

> Fließkommazahlen mit DOPPELTER Genauigkeit, Festkommaartithmetik
> reicht locker, auch wenn man da mal drei Minuten nachdenken muss.

Ich hab mir dafuer vor vielen Jahren mal ein eigenes printf geschrieben.
Das kann dann sowas:

 printf("%2f", 123)  ==> 1.23

So kann ich in meiner Software immer mit zwei (oder mehr) 
Festkommastellen rechnen ohne es zu merken. :-D

Allerdings muss man leider sagen das Microcontroller heute so schnell 
geworden sind das man halt doch sehr oft double nutzen kann ohne drueber 
nachzudenken. Wichtig wird es erst dann wieder wenn man Sachen macht die 
mit sehr wenig Energie auskommen muessen. Der Unterschied zwischen klug 
und doof sind dann 3Monate oder 2Jahre mit derselben CR2032.

Und die Ausgabe eines kompletten Buffers an ein Display ist auch 
Schwachsinn.

Bei mir sieht der Buffer fuers Display so aus:

#define SEGMENTSIZE 32

typedef struct{
   unsigned char segment[SEGMENTSIZE];
   unsigned char dirty;
} OLEDColumnType;

#define PAGES 8
#define SEGMENTS 4

OLEDColumnType OLED_Buff[SEGMENTS][PAGES];

Mein Buffer ist also in Segmente eingeteilt. Wird eines beschrieben wird
das als dirty markiert. In meinem TickerIRQ wird dann geschaut ob es ein 
dirty Segment gibt und dann nur dieses ausgeben. Es ist erstaunlich wie 
wenig Datenverkehr es dann noch zum Display gibt. .-)

Aber ja, da muss man wohl mal was selber programmieren und nicht nur im 
Internet von den Einaeugigen abschreiben damit man selber blind bleiben 
kann.

Olaf

von Joachim B. (jar)


Lesenswert?

Olaf schrieb:
> Mein Buffer ist also in Segmente eingeteilt. Wird eines beschrieben wird
> das als dirty markiert. In meinem TickerIRQ wird dann geschaut ob es ein
> dirty Segment gibt und dann nur dieses ausgeben. Es ist erstaunlich wie
> wenig Datenverkehr es dann noch zum Display gibt. .-)

liest sich wie mein Ansatz, mit anderen Worten.
Schon erstaunlich das verschiedene Menschen durch nchdenken zur selben 
Lösung kommen,
Grammophon, Fahrrad, Automobil, Telefon

Ein Glück müssen wir nicht um Patente streiten.

von Hugo H. (hugo_hu)


Lesenswert?

Joachim B. schrieb:
> Hugo H. schrieb:
>> Veit D. schrieb:
>>> clear ist ungünstig, weil jedesmal das gesamte Display gelöscht wird.

Bitte korrekt zitieren:

Hugo H. schrieb:
> Veit D. schrieb:
>> clear ist ungünstig, weil jedesmal das gesamte Display gelöscht wird.
>
> Was meinst Du, was bei
>
> Julian D. schrieb:
>> sendBuffer();
>
> passiert?

von W.S. (Gast)


Lesenswert?

Julian D. schrieb:
> Ich habe wieder ein Problem mit meinem I2C OLED Display, angesteuert mit
> einem Arduino Uno.

Ähem... nein. Mit dem OLED hast du gewiß kein Problem. Dein Problem ist 
die Ausgabe-Routine für deine Display-Grafik. Ich habe schon vor Jahren 
dieses U8G2 Zeugs nicht gemocht, zum einen, weil es keine saubere 
Trennung zwischen dem GDI und dem eigentlichen Treiber zum Display hin 
hat, sodann weil es keine wirkliche Trennung zwischen den grafischen 
Daten (Fonts, Grafiken usw.) und dem Programm hat und hier in deinem 
Falle auch deshalb, weil du sowas lediglich benutzt, ohne dabei 
verstanden zu haben, wie das Zeugs funktioniert.
Also: stelle dir mal ne Tafel in der Schule vor. Da kann man was 
draufschreiben. Und man muß auch das früher geschriebene irgendwann mal 
wieder ablöschen, wenn man etwas neues draufschreiben will und es 
hinterher auch lesbar sein soll. So ungefähr geht es bei vielen GDI 
Versionen. Wenn man (anders als bei der Schultafel mit der Kreide) als 
Textzeichen immer nur gleichgroße "Kacheln" auf die Grafik-Oberfläche 
malt und dabei nicht nur die Stellen malt, die bei der Tafel etwas 
Kreide abkriegen, sondern dabei auch alle die Stellen ablöscht, die 
keine "Kreide" abkriegen sollen, dann spart man sich das vorherige 
Ablöschen und erkauft sich das mit einem höheren Schreib-Aufwand beim 
Malen des Textzeichens.

Ich mache das bei meinen Projekten so, daß ich eine strikte Trennung 
habe zwischen GDI und Display-Treiber und das GDI zeichnet auf eine 
Grafik-Oberfläche im RAM. Das GDI setzt bei jedem Schreibvorgang eine 
Boolean-Variable, die anzeigt, daß die Grafik-Oberfläche verändert 
wurde. Ganz woanders, zumeist irgendwo in main() wird danach geschaut 
und wenn besagte Variable gesetzt ist, wird der Display-Treiber 
aufgerufen, der die Daten ins Display kopiert und die Variable wieder 
löscht. Nun ja, obendrein trenne ich auch sowas wie Fonts und Grafiken 
vom auszuführenden Code. Und bei mir muß der betreffende Bereich 
abgelöscht werden, bevor dort irgend etwas draufgemalt wird. Aber das 
ist auch alles selber geschrieben und nicht von irgendwo kopiert.

Also: Verstehe du mal das, was du benutzt. Dann wird dir gewiß klar, an 
welcher Stelle der Programmfehler bei dir steckt.

W.S.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

Libs sind zum benutzen da. Man muss die internen Abläufe nicht 
verstehen. Nur wenn es einen genau interessiert schaut man hinter die 
Kulissen. Oder lernt jeder Auto Mechaniker nur damit er Auto fahren 
darf? Ich glaube nicht.
Jeder der selbst Libs schreibt benutzt sie danach nur noch. Die internen 
Abläufe interessieren später nicht mehr. Dafür hat man sie ja 
schließlich geschrieben um sich und vielleicht anderen den Umgang 
einfacher zu machen. Also lasst mal die Kirche im Dorf.

von Falk B. (falk)


Lesenswert?

Veit D. schrieb:
> Also lasst mal die Kirche im Dorf.

Was erwartest du von W.S.?

Beitrag #7002149 wurde von einem Moderator gelöscht.
von Olaf (Gast)


Lesenswert?

> Libs sind zum benutzen da. Man muss die internen Abläufe nicht
> verstehen.

Das kann man sich mit Einschraenkungen noch auf PCs erlauben, aber 
selbst da fuehrt es dazu das Computer sich heute 10x langsamer anfuehlen 
als sie sein muessten.
Bei den begrenzten Resourcen eines Microcontrollers sieht das anders 
aus. Da kuemmerst du dich um deine Libaries, versteht ihren Inhalt, bist 
dir darueber im klaren ob die Vorgehensweise in einer Libarie zu deinem 
Gesamtprojekt passt oder nicht, oder du produzierst Muell. Letzeres 
kannst du derzeit sehr schoen bei der Programmierung in aktuellen VWs 
sehen. Man hat dort Controller mit mehreren Kernen in der 1Ghz Klasse 
und trotzdem ist das Ergebnis ein laecherlicher Witz.
Bei noch kleineren Controllern wird es dann immer schlimmer, ausser sie 
sind dann wieder so klein das man keine Libaries verwenden kann. :)

Das muss nicht zwangslaeufig heissen das man keine Libaries verwenden 
darf!

Ein sehr schoenes Beispiel dafuer ist die FAT-Libarie von elm-chan. 
Programmiert man sich sowas selber wird man, angesichts der grossen 
Anzahl unterschiedlichster Speicherkarten schnell feststellen das es 
hier die breite Nutzung dieser Libarie zu sehr viel mehr 
Zuverlaessigkeit fuehrt als man es selber in endlicher Zeit schaffen 
wird.
Benutzt man sie aber nur ohne Nachzudenken und mal reinzuschauen, ist 
man also faul und bequem, wird man schnell auf Anwendungen stossen wo 
man Probleme bekommt. Die Loesung der Faulen und Dummen ist dann 
normalerweise nach mehr Rechenleistung zu schreien. (vgl auch VW :-) )

Olaf

von Falk B. (falk)


Lesenswert?

Olaf schrieb:
> Das kann man sich mit Einschraenkungen noch auf PCs erlauben, aber
> selbst da fuehrt es dazu das Computer sich heute 10x langsamer anfuehlen
> als sie sein muessten.

Das ist wohl leider wahr. :-(

https://de.wikipedia.org/wiki/Bloatware

> Bei den begrenzten Resourcen eines Microcontrollers sieht das anders
> aus. Da kuemmerst du dich um deine Libaries, versteht ihren Inhalt,

Jain. Man kann und WILL nicht jedes Detail einer Lib verstehen, wohl 
aber wesentliche Eigenschaften und Konzepte. Das ist ein Unterschied.

von Olaf (Gast)


Lesenswert?

> Jain. Man kann und WILL nicht jedes Detail einer Lib verstehen, wohl
> aber wesentliche Eigenschaften und Konzepte. Das ist ein Unterschied.

Natuerlich, so meinte ich das. Man kann nicht jede einzelne Zeile 
kontrollieren, obwohl das manchmal (SIL-Zertifizierung/Audit) auch 
notwendig ist. Aber man sollte schon wissen wie eine Libary 
funktioniert.

Olaf

von Falk B. (falk)


Lesenswert?

Olaf schrieb:
> Das kann man sich mit Einschraenkungen noch auf PCs erlauben, aber
> selbst da fuehrt es dazu das Computer sich heute 10x langsamer anfuehlen
> als sie sein muessten.

https://de.wikipedia.org/wiki/Wirthsches_Gesetz

von W.S. (Gast)


Lesenswert?

Olaf schrieb:
> Ein sehr schoenes Beispiel dafuer ist die FAT-Libarie von elm-chan.
> Programmiert man sich sowas selber wird man, angesichts der grossen
> Anzahl unterschiedlichster Speicherkarten schnell feststellen das es
> hier die breite Nutzung dieser Libarie zu sehr viel mehr
> Zuverlaessigkeit fuehrt als man es selber in endlicher Zeit schaffen
> wird.

Da schreibst du hanebüchenen Unsinn, denn gerade der Teil, der sich mit 
"der großen Anzahl unterschiedlichster Speicherkarten" befassen muß, ist 
da augeklammert und muß vom jeweiligen Anwender beigesteuert werden.

W.S.

von Olaf (Gast)


Lesenswert?

> Da schreibst du hanebüchenen Unsinn, denn gerade der Teil, der sich mit

Nein, ich schreibe aufgrund intellektueller Ueberlegenheit und 
angeborener Schoenheit immer das richtige. .-)

> "der großen Anzahl unterschiedlichster Speicherkarten" befassen muß, ist
> da augeklammert und muß vom jeweiligen Anwender beigesteuert werden.

Nein. Die Libarie hat ja eine sehr grosse Zahl von Anwender welche sich 
vermutlich schon im Forum bei elm-chan gemeldet haetten wenn sie ein 
Problem gefunden haetten. Ich weiss auch das man den Lowleveltreiber 
selber schreiben soll und hab das auch schon getan, aber viele sind ja 
auch schon dafuer zu faul.

Und auch die hoeheren Level des FAT-System sind nicht ganz ohne. Es ist 
schon nett das dies von einer Menge Leute getestet wurde bevor man es 
selbst nutzt.

Ich hab sowas vor 20Jahren mal komplett selber geschrieben. Getestet mit 
etwa 20 verschiedenen Speicherkarten in allen groessen. Trotzdem kam 
kurz nach der Auslieferung der erste Kunde mit einer noch groesseren 
Karte an als man erwartet haette und ich damals kaufen konnte und ein 
Jahr spaeter wieder groesser usw.
Da nimmt einen elm-chan schon 50% der Arbeit ab die man sonst haette.

Olaf

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.