OLED Aktualisierung, Vorgehensweise

Hallo zusammen,

ich bastel mit gerade einen Boardcomputer für mein Motorrad. Ich nutze dazu einen Genuino Uno Rev. 3 mit einem Newhaven Display NHD-1.69-160128ASC3. In der Mitte des Display soll groß die Uhrzeit angezeigt werden. Soweit habe ich das jetzt auch. Ich verwende folgende librarys:

#include <RTClib.h>
#include <Wire.h>
#include <SEPS525_OLED.h>
#include <Adafruit_GFX.h>
#include <Fonts/FreeSansBold24pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h>
#include <SPI.h>
#include <DHT.h>

Meine Frage ist, wie ich am besten die Anzeige von zum Beispiel den Minuten aktualisiere?! Aktuell mache ich es so, dass ich den aktuellen Wert von Minuten vergleiche und wenn es eine Änderung gab, "male" ich an der Stelle ein gefülltes Rechteck mit der Hintergrundfarbe. Das funktioniert, sieht aber nicht schön aus, da die Anzeige in dem Moment natürlich sichtbar "blinkt". Woran liegt das und kann man das umgehen bzw. besser lösen?

Hier der Codeabschnitt:

  DateTime now = RTC.now();
  
  char s[16];

  sprintf(s,"%02u.%02u.%04u", now.day(), now.month(), now.year());
  tft.setFont(&FreeSansBold9pt7b);
  tft.setCursor(35, 16);
  tft.print(s);
  tft.setFont();

  if(Stunde != now.hour()){
    tft.fillRect(21, 46, 51, 37, BLACK);
  }
  if(Minute != now.minute()){
    tft.fillRect(85, 46, 51, 37, BLACK);
  }
  sprintf(s,"%02u:%02u", now.hour(), now.minute());
  tft.setFont(&FreeSansBold24pt7b);
  tft.setCursor(20, 80);
  tft.print(s);
  tft.setFont();

  Stunde = now.hour();
  Minute = now.minute();
  Sekunde = now.second();
  
  delay(1000);
  secCounter ++;

Ich habe den alten Character aus dem char[] erneut mit Schwarz gezeichnet und danach den neuen Character mit Weiß.
Sah bei mir immer gut aus!

Den alten Zeiger/Zahl in Hintergrundfarbe zeichen und dann den neuen Zeiger (eventuella auch Stundenzeiger) bzw Zahl in gewählter Farbe ausgeben.

Grüße Uwe

Du formatierst mit sprintf() deinen Text auf eine konstante Breite. Das ist im Prinzip bei allen Displays das korrekte Verfahren. So spart man sich den Zwischenschritt der das Flackern verursacht und der Text wird komplett überschrieben

Wenn ich das richtig in Erinnerung habe ist das Problem bei der Adafruit Library, dass da aber normal nicht alle Pixel neu gezeichnet werden. Es gibt aber zwei Versionen von setTextColor():

setTextColor(uint16_t c),
setTextColor(uint16_t c, uint16_t bg),

Wird dass nicht dadurch behoben dass man einfach die Version mit zwei Parametern verwendet und die Hintergrundfarbe explizit setzt?

Dann wird der Text aber immer geschrieben/ neu überzeichnet und dadurch kommt das wahrgenommene Flackern.

Wie ich schon von mir beschrieben und von Uwe nochmals verständlicher ausgedrückt wurde, ist das Verfahren besser, wenn nur geänderte Inhalte neuchgezeichnet werden.
Dabei wird das alte Zeichen zuerst mit der Hintergrundfarbe an die selbe Stelle gezeichnet und dana mit dem aktuellen Zeichen in der Schriftfarbe frisch gezeichnet.

Ich hatte mir dafür mal neu Funktion gebastelt:

void tft_Textupdate (const uint16_t _x, const uint16_t _y, char *alt, char *neu, uint8_t len, uint8_t textsize, uint16_t old_color, uint16_t new_color)
{
  uint8_t i = 0;
  tft.setTextSize(textsize);

  do {
    if (*alt != *neu) {         // Character unterscheidet sich?
      // Alten Character überzeichnen
      tft.setCursor(_x + (i * textsize * 6), _y);
      tft.setTextColor(old_color);
      tft.print(*alt);
      // Neuen Character zeichnen
      tft.setCursor(_x + (i * textsize * 6), _y);
      tft.setTextColor(new_color);
      tft.print(*neu);
    }
    i++;
    alt++; neu++;
  } while (i < len);
}

Ich habe den Code für zB Sekunde nun wie folgt abgeändert:

if(Sekunde != now.second()){
    sprintf(s,"%02u", Sekunde);
    tft.setTextColor(BLACK);
    tft.print(s);
  }else{
    sprintf(s,"%02u", now.second());
    tft.print(s);
  }

Jetzt flackert es aber genauso, wenn nicht noch schlimmer. Kann es sein, dass der UNO einfach zu langsam dazu ist?

Baue doch mal ein Minimalbeispiel (Sketch der andauernd von 0 - 10 Zählt) und poste, wenn das Flackern weiterhin auftritt, den gesamten Sketch.

ed881:
Jetzt flackert es aber genauso, wenn nicht noch schlimmer.

Du hast einen logischen Fehler in Deinem Sketch: Du schreibst erst die alte Sekunde, dann machst Du einen loop-Durchgang, dann erst schreibst Du die neue Sekunde. Ohne else sollte es besser aussehen.

Was Serenifly in #3 schreibt, ist die einzige mir bekannte flackerfreie Lösung. Jedwedes Löschen führt zum Flackern.

Mardetuino:
Dann wird der Text aber immer geschrieben/ neu überzeichnet und dadurch kommt das wahrgenommene Flackern.

Das Flackern kommt dadurch dass man erst mal den Text löscht und dann was neues drüber schreibt. Und vor allem wenn man dazu ein Rechteck nimmt fällt dass auf, da es etwas dauert so viele Pixel zu zeichnen.

Wenn du gleiches mit gleichem überschreibst sieht man gar nichts. Und wenn sich der Text ändert sollten die Hintergrundpixel auf die angegebene Hintergrundfarbe gesetzt werden. 100%ig sicher bin ich mir nicht, aber ich habe mir mal den Quellcode grob angesehen (dazu gibt es darin auch ein paar vage Kommentare) und ich erinnere mich dass es dieses Thema hier schon mal gab.

Serenifly:
... und ich erinnere mich dass es dieses Thema hier schon mal gab.

Keines der Themen wurde nach meiner Erinnerung zu einem erfolgreichen Ende geführt. Irgendwann hatten die Themensteller wohl keine Lust mehr.

Hi

Damals hüstel auf dem Schneider CPC464 wurden Sprites (Grafiken ... Spielfiguren) verschoben, in dem ein per XOR erstelltes Differenz-Bild auf das Display ausgegeben wurde.
Ähnliches könnte hier gut funktionieren:
Hier müsste man wohl die beiden Zeichen, Die man gegeneinander ersetzen will, 2x miteinander vergleichen.

  1. Die Pixel, die vorher gesetzt und nachher nicht mehr gesetzt sind
  2. Die Pixel, die vorher nicht gesetzt und nachher gesetzt sind
    Diese beiden 'Zeichen' geht man pixelweise ab, wenn dort ein Pixel gesetzt oder gelöscht 'eingetragen' ist, setzt oder löscht man diesen Pixel.
    Dadurch werden nur die Pixel 'angefasst', Die wirklich verändert wurden.

... hätte ich aber seit Dem auch nicht mehr gemacht, wenn hier auch einige e-Paper und Displays auf aufkommenden Spieltrieb warten.

MfG

postmaster-ino:

  1. Die Pixel, die vorher gesetzt und nachher nicht mehr gesetzt sind
  2. Die Pixel, die vorher nicht gesetzt und nachher gesetzt sind
    Diese beiden 'Zeichen' geht man pixelweise ab, wenn dort ein Pixel gesetzt oder gelöscht 'eingetragen' ist, setzt oder löscht man diesen Pixel.
    Dadurch werden nur die Pixel 'angefasst', Die wirklich verändert wurden.

Wobei es mindestens um Vordergrund/Hintergrund-Farbe geht, oder im allgemeinen Fall wesentlich komplizierter als gesetzt/nicht gesetzt ist.

Hi

Bei verschiedenen Farben geht Das ja ebenfalls - wenn die Pixelfarbe sich ändern soll -> ändern, sonst belassen.
Wenn der Hintergrund hierbei nicht einfarbig ist, muß man den Hintergrund separat mit beiden Zeichen abgleichen und dann halt, wo das Alt-Zeichen war, aber kein Neu-Zeichen ist, in Hintergrund einfärben.

Noch sehe ich da kein wirkliches Problem, gerade da akut das Zeichen per Rechteck bzw. Alt-Zeichen in Hintergundfarbe gelöscht wird - klingt nach 'einfarbig'.

Man braucht halt den Platz für die Matrix, zwischen Alt- und Neuzeichen oder muß 'on the fly' Prüfen.

MfG

Ich habe das nun wie folgt gelöst. Ein leichtes Flackern ist zwar noch zu erkennen bei einem Wertewechsel aber das ist zu verkraften.

/*############## Uhrzeit anzeigen ##############*/
  
  
  if(Stunde != now.hour()){          // prüfen, ob sich die aktuelle Stunde (now.hour) geändert hat
    sprintf(s,"%02u", Stunde);
    tft.setTextColor(BLACK);
    tft.setCursor(20, 37);
    tft.print(s);
    sprintf(s,"%02u", now.hour());
    tft.setTextColor(WHITE);
    tft.setCursor(20, 37);
    tft.print(s);
  }else{
    sprintf(s,"%02u", now.hour());
    tft.setCursor(20, 37);
    tft.print(s);
  }

  tft.setCursor(57, 37);
  tft.print(":");

  if(Minute != now.minute()){          // prüfen, ob sich die aktuelle Minute (now.minute) geändert hat
    sprintf(s,"%02u", Minute);
    tft.setTextColor(BLACK);
    tft.setCursor(64, 37);
    tft.print(s);
    sprintf(s,"%02u", now.minute());
    tft.setTextColor(WHITE);
    tft.setCursor(64, 37);
    tft.print(s);
  }else{
    sprintf(s,"%02u", now.minute());
    tft.setCursor(64, 37);
    tft.print(s);
  }

  tft.setCursor(101, 37);
  tft.print(":");

  if(Sekunde != now.second()){          // prüfen, ob sich die aktuelle Sekunde (now.second) geändert hat
    sprintf(s,"%02u", Sekunde);
    tft.setTextColor(BLACK);
    tft.setCursor(108, 37);
    tft.print(s);
    sprintf(s,"%02u", now.second());
    tft.setTextColor(WHITE);
    tft.setCursor(108, 37);
    tft.print(s);
  }else{
    sprintf(s,"%02u", now.second());
    tft.setCursor(108, 37);
    tft.print(s);
  }
 


  Jahr = now.year();
  Monat = now.month();
  Tag = now.day();
  Stunde = now.hour();
  Minute = now.minute();
  Sekunde = now.second();

Du könntest meine Änderung der Bibliothek Adafruit_GFX verwenden: Anleitung: Anzeige einer sich schnell ändernden Zahl ohne Flackern

Die Bibliothek "SSD1306.h" flackert grundätzlich nicht.
da habe ich hier was geschrieben.

Warum braucht Du die Uhrzeit auf dem Motorrad? Darauf ist es so schön, dass die Zeit stehen bleibt;-)
P.S. Ist Dein Display in prallender Sonne noch lesbar?

RIN67630:
Die Bibliothek "SSD1306.h" flackert grundätzlich nicht.

In #0 sehe ich #include <SEPS525_OLED.h>, wie kommst Du auf SSD1306?

Da ich nicht weiß, welche Bibliothek verwendet wird, weiß ich auch nicht, wie es beschrieben wird. Wenn aber ein Flacker zu sehen ist, wird es vermutlich direkt beschrieben. Dann könnte meine Änderung der hier auch eingebundenen Bibliothek Adafruit_GFX helfen.

agmue:
In #0 sehe ich #include <SEPS525_OLED.h>, wie kommst Du auf SSD1306?

Da ich nicht weiß, welche Bibliothek verwendet wird, weiß ich auch nicht, wie es beschrieben wird. Wenn aber ein Flacker zu sehen ist, wird es vermutlich direkt beschrieben. Dann könnte meine Änderung der hier auch eingebundenen Bibliothek Adafruit_GFX helfen.

Gut beobachtet. Ich ziehe alles zurück und behaupte das Gegenteil! :o

Für den SEPS525 ist die c++ Auswahl bei Github sehr dünn. Eine Bibiliothek mit Framing scheint es nicht zu geben.

RIN67630:
Gut beobachtet. Ich ziehe alles zurück und behaupte das Gegenteil! :o

Schon sind wir uns einig :slight_smile:

RIN67630:
Für den SEPS525 ist die c++ Auswahl bei Github sehr dünn. Eine Bibiliothek mit Framing scheint es nicht zu geben.

Die Standard-Arduinos wie der UNO haben dafür zu wenig Speicher.

Aber der TO scheint auch mit flackernder Anzeige glücklich zu sein und saust damit durch die Gegend.