Lopaka Basics 04: Live-Daten

Zwei Screens. Gleiches Board, gleicher Sensor, gleiche Zahlen. Aber einer blinzelt jedes Mal, wenn sich eine Zahl ändert. Verlangsame es, und du siehst warum: Das ganze Bild wird weggewischt und dann Stück für Stück zurückgemalt.
In dieser Episode findest du heraus, was loop() tut, warum ein Farbdisplay flackert, wenn ein OLED es nicht tut, und die drei Regeln, die es stoppen. Dann verwandelst du die Zahlen eines Lopaka-Designs in Variablen, fütterst sie von einem Temperatur- und Feuchtigkeitssensor und führst es auf einem simulierten ESP32 ohne ein einziges Blinken aus.
Was du bauen wirst: einen 320×240-Farb-Raummonitor mit Live-Temperatur- und Feuchtigkeitszahlen und einer Feuchtigkeitsleiste, zweimal pro Sekunde aktualisiert. Was du brauchst: einen Browser. Wir führen den Code auf einem simulierten ESP32 mit einem ILI9341-Display und einem DHT22-Sensor aus; ein echtes Board ist optional.
setup() und loop()
Jeder Arduino-Sketch hat zwei Teile:
setup()läuft einmal, beim Einschalten.loop()läuft danach, wieder und wieder, solange das Board Strom hat.
Live-Daten leben in loop(): Lies den Sensor, verwandle die Zahlen in Text, zeichne sie und wiederhole. Jede Runde zeichnet den Screen erneut.

Warum ein Farbscreen blinzelt
Das OLED zeichnet zuerst im Speicher
Das OLED aus den ersten Episoden blinkte nie. Seine Bibliothek, U8g2, zeichnet zuerst in den Speicher: einen Frame-Puffer von einem Kilobyte für 128 × 64 Pixel, wie du in Episode 1 gesehen hast. Nur das fertige Bild geht ans Display. Der Page-Modus tut dasselbe in acht Streifen von 128 Bytes, einer nach dem anderen.

Ein Farbframe bräuchte 150 KB
Ein 320×240-Farbscreen speichert zwei Bytes pro Pixel, also braucht ein Frame 320 × 240 × 2 = 153.600 Bytes, etwa 150 KB. Das ist fast die Hälfte des RAM, den ein ESP32 deinem Sketch gibt. Also malt TFT_eSPI direkt aufs Display, wie Adafruit GFX in Episode 3.

Du siehst jeden Schritt
Wenn die Bibliothek direkt aufs Display malt, siehst du jeden Schritt des Zeichnens. Wenn der Sketch den Screen zu Beginn jeder Runde löscht, wird das Display zuerst schwarz, und das Bild kommt Stück für Stück zurück.

In unserem Test (ESP32 im Simulator, SPI bei 27 MHz) brauchte das Löschen des 320×240-Screens 48 Millisekunden und das Zeichnen des Dashboards weitere 68. Fast 50 Millisekunden Schwarz bei jedem Update reichen, damit dein Auge es bemerkt.

Drei Regeln gegen Flackern
- Lösche den Screen nicht in
loop(). KeinfillScreen()bei jeder Runde. - Gib jeder Live-Zahl eine Hintergrundfarbe. Ohne eine werden die neuen Ziffern über die alten gezeichnet und stapeln sich zu einem Durcheinander. Mit einer wird jede Ziffer in einer Box mit Hintergrundfarbe gezeichnet, die löscht, was darunter war.
- Halte andere Formen von unter einer Live-Zahl fern. Eine gefüllte Karte unter der Zahl würde bei jeder Runde über sie gemalt, und die Zahl würde blinken. Eine umrissene Karte berührt die Pixel hinter den Ziffern nicht.
Lopaka kümmert sich um die ersten zwei.

Schritt 1: Entwirf den Raummonitor
Ein neues TFT_eSPI-Projekt
Klicke auf + Neues Projekt und wähle die Plattform TFT_eSPI, M5, Lovyan. TFT_eSPI ist eine der häufigsten Grafikbibliotheken für Farbdisplays auf dem ESP32. Setze den Titel auf „Room Monitor“ und die Screen-Größe auf 320×240, behalte die schwarze Hintergrundfarbe und klicke auf Speichern.

Zeichne das Dashboard
Zeichne den Screen auf dieselbe Weise wie letztes Mal: einen Titel, zwei umrissene Karten, zwei Beschriftungen, zwei große Zahlen, ein Gradzeichen, eine Leiste für Feuchtigkeit, eine Bildunterschrift und eine rote LIVE-Markierung. Das sind die Werte, die wir nutzten:
| Ebene | Werkzeug | Werte im Inspektor | Schriftart | Farbe |
|---|---|---|---|---|
Living room | Text | X 12, Y 30 | FreeSansBold12pt7b | #FFFFFF |
| Temperaturkarte | Rechteck | X 12, Y 46, W 142, H 120, R 10 | #FF8200 | |
| Feuchtigkeitskarte | Rechteck | X 166, Y 46, W 142, H 120, R 10 | #4C8DFF | |
Temperature | Text | X 24, Y 72 | FreeSans9pt7b | #FF8200 |
Humidity | Text | X 178, Y 72 | FreeSans9pt7b | #4C8DFF |
23.5 | Text | X 24, Y 140 | FreeSansBold24pt7b | #FFFFFF |
48% | Text | X 178, Y 140 | FreeSansBold24pt7b | #FFFFFF |
C | Text | X 132, Y 122 | FreeSansBold12pt7b | #FFFFFF |
| Gradzeichen | Ellipse | X 124, Y 104, RX 3, RY 3 | #FFFFFF | |
| Leiste | Rechteck, Gefüllt | X 12, Y 182, W 142, H 18 | #4C8DFF | |
| leerer Teil der Leiste | Rechteck, Gefüllt | X 154, Y 182, W 154, H 18 | #1F2937 | |
Updated every 0.5 s | Text | X 12, Y 228 | FreeSans9pt7b | #6B7280 |
| LIVE-Punkt | Ellipse, Gefüllt | X 260, Y 16, RX 4, RY 4 | #EF4444 | |
LIVE | Text | X 272, Y 27 | FreeSans9pt7b | #EF4444 |
Der erste Text in einem TFT_eSPI-Projekt startet in der kleinen Schriftart Adafruit 5x7, und jeder Text danach startet in der letzten Schriftart, die du gewählt hast.
Die Karten sind Umrisse und folgen Regel 3. Die Leiste sind zwei Rechtecke Seite an Seite, der gefüllte Teil und der leere Teil, sodass kein Pixel der Leiste zweimal gemalt wird. Wenn du die ganze dunkle Leiste und den blauen Teil darüber zeichnen würdest, würde der blaue Teil bei jeder Runde blinken.
Das Y eines Textes
Schau dir die große Temperaturzahl im Code an:
tft.drawString("23.5", 24, 104);Der Inspektor sagt Y 140, der Code sagt 104. Wie bei U8g2 ist das Y des Inspektors die Grundlinie, die Linie, auf der die Ziffern stehen. Das drawString von TFT_eSPI nimmt stattdessen den oberen Rand des Textes, also wandelt Lopaka die Zahl für dich um. Farben werden auch umgewandelt: #FF8200 wird zu 0xFC00 in RGB565, dem Zwei-Byte-Farbformat aus Episode 3.
Gerade sind diese Zahlen einfacher Text. Sie werden sich nie ändern.
Schritt 2: Ebenen werden Variablen
Benenne die Ebene
Um eine Zahl live zu machen, verwandle sie in eine Variable. Benenne zuerst die Ebene: Doppelklicke im Ebenen-Panel auf string 6, den 23.5-Text, und benenne ihn in temp um.
Klicke den Variablen-Button
Wähle die Ebene aus und klicke den Variablen-Button am rechten Ende ihres Textfeldes im Inspektor (sein Tooltip sagt Variable hinzufügen). Der Button wird orange, und zwei Dinge ändern sich im Code:
const char* temp_text = "23.5";// temp
tft.drawString(temp_text, 24, 104);Lopaka deklariert oben im Code eine Variable, benannt nach der Ebene, mit dem Text als Startwert. Der Zeichenaufruf nutzt jetzt die Variable statt des festen Textes. Dein Sketch kann jeden Text in temp_text legen, und der nächste Aufruf der Zeichenfunktion zeigt ihn.

Feuchtigkeit und die Leiste
Mache dasselbe für Feuchtigkeit und gib der Leiste variable Größen:
- Benenne
string 7, den48%-Text, inhumum und klicke den Variablen-Button neben seinem Text:hum_text. - Benenne die gefüllte Leiste in
hum_barum und klicke den Variablen-Button neben W:hum_bar_w. - Benenne den leeren Teil der Leiste in
hum_restum und klicke die Variablen-Buttons neben X und W:hum_rest_xundhum_rest_w.
Die Leiste bekommt eine variable Breite und ihr leerer Teil eine variable Position und Breite, sodass der Sketch jedes Pixel der Leiste einmal malt, egal wie die Feuchtigkeit ist.
int hum_bar_w = 142;
int hum_rest_w = 154;
int hum_rest_x = 154;
const char* hum_text = "48%";
const char* temp_text = "23.5";// hum_bar
tft.fillRect(12, 182, hum_bar_w, 18, 0x4C7F);
// hum_rest
tft.fillRect(hum_rest_x, 182, hum_rest_w, 18, 0x1946);Ein Text wird zu einem const char*, eine Zahl wie eine Breite wird zu einem int. Der Ebenenname und die Eigenschaft ergeben den Variablennamen: hum_bar + w.

Schritt 3: Kein Blinken
Ein Hintergrund hinter jeder Zahl
Wähle temp aus und setze seine Hintergrund-Farbe auf #000000, Schwarz wie der Screen. Mache dasselbe für hum. Der Code setzt jetzt zwei Farben für den Text, die Ziffern und die Box dahinter:
// temp
tft.setTextColor(0xFFFF, 0x0);
tft.setFreeFont(&FreeSansBold24pt7b);
tft.drawString(temp_text, 24, 104);
// hum
tft.drawString(hum_text, 178, 104);0xFFFF ist Weiß, 0x0 ist Schwarz. Die Feuchtigkeitszahl nutzt dieselben Farben, also wiederholt Lopaka den Aufruf nicht. Das ist Regel 2.

Schalte Display löschen/füllen aus
Jetzt Regel 1. Finde in der Liste der Schalter neben dem Code Display löschen/füllen. In einem neuen TFT_eSPI-Projekt ist es an, und die Zeichenfunktion beginnt damit, den ganzen Screen zu füllen:
void drawScreen_1(void) {
tft.fillScreen(0x0);Diese eine Zeile verursacht das Blinken: Die Funktion läuft bei jeder Runde von loop(), also wird der Screen bei jeder Runde schwarz. Schalte Display löschen/füllen aus, und die Zeile ist weg.

Schalte Schriftarten einbeziehen aus
Ein weiterer Schalter: Schalte Schriftarten einbeziehen aus. TFT_eSPI bringt diese FreeFonts bereits mit, also braucht der Sketch keine Schriftartdateien.
Schritt 4: Deine eigene Schleife
Schreibe um den generierten Block herum
Der Rest sind wenige Zeilen von dir. Du kannst den ganzen Sketch direkt hier im Code-Panel schreiben. Lopaka hält deinen Code um seinen generierten Block herum, zwischen // [BEGIN lopaka generated] und // [END lopaka generated], und er bleibt, wenn du das Design änderst oder die Seite neu lädst.
Klicke über die BEGIN-Zeile und tippe die Includes und Objekte:
#include <TFT_eSPI.h>
#include <DHTesp.h>
TFT_eSPI tft;
DHTesp dht;
char t[8], h[8];Füge dann unter der END-Zeile setup() und loop() hinzu:
void setup() {
tft.begin();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextPadding(94);
dht.setup(27, DHTesp::DHT22);
}
void loop() {
TempAndHumidity d = dht.getTempAndHumidity();
snprintf(t, sizeof t, "%.1f", d.temperature);
snprintf(h, sizeof h, "%.0f%%", d.humidity);
temp_text = t;
hum_text = h;
hum_bar_w = d.humidity * 2.96;
hum_rest_x = 12 + hum_bar_w;
hum_rest_w = 296 - hum_bar_w;
drawScreen_1();
delay(500);
}
Was setup() tut
setup() startet das Display, dreht es mit setRotation(1) ins Querformat und malt es einmal schwarz, dann startet es den Sensor an Pin 27. Das eine fillScreen hier ist in Ordnung: Es läuft beim Einschalten, nicht bei jeder Runde.
setTextPadding(94) gibt jeder Live-Zahl eine feste Box mit 94 Pixeln Breite. TFT_eSPI füllt den Texthintergrund nur so breit wie der neue Text. Wenn „23.5“ sich zu einem schmaleren Wert wie „9.8“ ändert, bliebe das rechte Ende der alten Ziffern auf dem Screen. 94 Pixel ist die Breite eines zweistelligen Werts wie „48%“ in dieser Schriftart, und die Box stoppt vor dem Gradzeichen.
Was loop() tut
loop() liest Temperatur und Feuchtigkeit, schreibt sie in die Textvariablen, verwandelt Feuchtigkeit in die Leistenbreite und ruft die Zeichenfunktion auf. Dann wartet es eine halbe Sekunde und macht weiter:
snprintfverwandelt eine Zahl in Text:\"%.1f\"behält eine Dezimalstelle, also wird aus 23,46 „23.5“, und\"%.0f%%\"ergibt „48%“.%%druckt das Prozentzeichen.temp_text = t;lässt die Variable auf diesen Text zeigen. Die Puffertundhsind außerhalb vonloop()deklariert, also ist der Text noch da, wenn die Zeichenfunktion ihn liest.- Die Leiste ist bei 100 % 296 Pixel lang, von x = 12 bis 308, also ist ein Prozent 2,96 Pixel. Der leere Teil beginnt, wo der gefüllte Teil endet, und nimmt den Rest.
delay(500)gibt zwei Updates pro Sekunde.
Schritt 5: Führe ihn aus
Im Simulator
Klicke über dem Code auf Kopieren. Es kopiert das ganze Panel, deinen Code eingeschlossen. Im Simulator aus Episode 1:
- Erstelle ein neues ESP32-Projekt.
- Füge ein ILI9341-Display hinzu und verbinde es: VCC und LED mit 3V3, GND mit GND, CS mit 15, RST mit 2, D/C mit 0, MOSI mit 13, SCK mit 14, MISO mit 12.
- Füge einen DHT22-Sensor hinzu: VCC mit 3V3, GND mit GND, SDA mit 27.
- Füge im Bibliotheksmanager TFT_eSPI und DHT sensor library for ESPx (die Bibliothek mit
DHTesp.h) hinzu. - Füge den Code in
sketch.inoein und drücke Play.
TFT_eSPI liest seine Pins aus einer Einstellungsdatei im Bibliotheksordner. Der Simulator nutzt die Standardeinstellungen der Bibliothek: ein ILI9341 an diesen ESP32-Pins.
Klicke auf den DHT22 und ziehe seine Schieberegler. Zahlen und Leiste folgen den Reglern ohne ein einziges Blinken.

Der vollständige Code vom Kopieren-Button, mit dem Lopaka-Block in der Mitte:
#include <TFT_eSPI.h>
#include <DHTesp.h>
TFT_eSPI tft;
DHTesp dht;
char t[8], h[8];
// [BEGIN lopaka generated]
int hum_bar_w = 142;
int hum_rest_w = 154;
int hum_rest_x = 154;
const char* hum_text = "48%";
const char* temp_text = "23.5";
void drawScreen_1(void) {
// string 1
tft.setTextColor(0xFFFF);
tft.setTextSize(1);
tft.setFreeFont(&FreeSansBold12pt7b);
tft.drawString("Living room", 12, 12);
// rect 2
tft.drawRoundRect(12, 46, 142, 120, 10, 0xFC00);
// rect 3
tft.drawRoundRect(166, 46, 142, 120, 10, 0x4C7F);
// string 4
tft.setTextColor(0xFC00);
tft.setFreeFont(&FreeSans9pt7b);
tft.drawString("Temperature", 24, 58);
// string 5
tft.setTextColor(0x4C7F);
tft.drawString("Humidity", 178, 58);
// temp
tft.setTextColor(0xFFFF, 0x0);
tft.setFreeFont(&FreeSansBold24pt7b);
tft.drawString(temp_text, 24, 104);
// hum
tft.drawString(hum_text, 178, 104);
// string 8
tft.setTextColor(0xFFFF);
tft.setFreeFont(&FreeSansBold12pt7b);
tft.drawString("C", 132, 104);
// ellipse 9
tft.drawEllipse(127, 107, 3, 3, 0xFFFF);
// hum_bar
tft.fillRect(12, 182, hum_bar_w, 18, 0x4C7F);
// hum_rest
tft.fillRect(hum_rest_x, 182, hum_rest_w, 18, 0x1946);
// string 12
tft.setTextColor(0x6B90);
tft.setFreeFont(&FreeSans9pt7b);
tft.drawString("Updated every 0.5 s", 12, 214);
// ellipse 13
tft.fillEllipse(264, 20, 4, 4, 0xEA28);
// string 14
tft.setTextColor(0xEA28);
tft.drawString("LIVE", 272, 13);
}
// [END lopaka generated]
void setup() {
tft.begin();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextPadding(94);
dht.setup(27, DHTesp::DHT22);
}
void loop() {
TempAndHumidity d = dht.getTempAndHumidity();
snprintf(t, sizeof t, "%.1f", d.temperature);
snprintf(h, sizeof h, "%.0f%%", d.humidity);
temp_text = t;
hum_text = h;
hum_bar_w = d.humidity * 2.96;
hum_rest_x = 12 + hum_bar_w;
hum_rest_w = 296 - hum_bar_w;
drawScreen_1();
delay(500);
}Für einen ESP32 kompiliert, nutzt der Sketch 24 % des Programmplatzes und 6 % des RAM.
Derselbe Sketch mit Display löschen/füllen
Der geteilte Screen unten führt denselben Sketch zweimal aus: links mit eingeschaltetem Display löschen/füllen, rechts unseren. Der einzige Unterschied ist die Zeile tft.fillScreen(0x0); am Anfang von drawScreen_1(). Der linke Screen ist mitten im Neuzeichnen erwischt, mit nur der ersten Ziffer zurück. Rechts ändern sich nur die Ziffern.

Auf einem echten Board
Installiere TFT_eSPI und DHT sensor library for ESPx aus dem Bibliotheksmanager in der Arduino IDE, verdrahte Display und Sensor auf dieselbe Weise und lade hoch. Dinge, die du auf echter Hardware prüfen solltest:
- TFT_eSPI-Einstellungen. Die Bibliothek nimmt Display-Treiber und Pins aus
User_Setup.hin ihrem eigenen Ordner. Der Standard ist ein ILI9341 mit den obigen Pins. Ändere für ein anderes Display oder andere Pins diese Datei, nicht den Sketch. - Boot-Pins. An einem echten ESP32 entscheiden GPIO 0 und GPIO 12 auch, wie das Board startet. Wenn das Board mit angeschlossenem Display nicht bootet, verschiebe D/C und MISO in
User_Setup.hauf andere Pins. - Der Sensor. Ein DHT22 gibt höchstens jede zwei Sekunden eine neue Messung. Die Bibliothek gibt die letzte Messung dazwischen zurück, also zeichnet der Screen trotzdem zweimal pro Sekunde neu. Wenn die Zahlen
nanzeigen, antwortete der Sensor nicht: Prüfe seine Verdrahtung.
Zusammenfassung
loop()zeichnet deinen Screen für immer neu: Lies, mache Text, zeichne, wiederhole.- Benenne eine Ebene, erhalte eine Variable: Der Variablen-Button verwandelt einen Text oder eine Größe in eine Variable, benannt nach der Ebene, und deine Schleife füttert sie.
- Kein Löschen plus ein Hintergrund bedeutet kein Blinken: Schalte Display löschen/füllen aus und gib jeder Live-Zahl eine Hintergrundfarbe.
Nächste Episode: Vom Browser zum Board. Wir bringen ein Design vom Screen auf ein echtes Board und gehen fünf Gründe durch, warum ein neues Display schwarz bleibt. Lies Episode 5 oder schaue sie auf YouTube.
Bereit, es zu versuchen? Öffne Lopaka und mache deinen eigenen Screen live.