ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display)
Utility Settings und WLAN-Scan
Bevor ihr mit diesem Artikel startet, solltet ihr euch zum Einstieg in die Materie zuerst ein wenig einlesen und die Hardware und das Pinout des TouchScreen-ESP32 ESP32-2432S028R-kennenlernen.
Außerdem solltet ihr euch eine Entwicklungsumgebung mit PlatformIO einrichten, wie in diesem Artikel besprochen. Danach solltet ihr noch den Artikel Programmierung des Displays mit der TFT_eSPI-Library lesen, in dem ihr lernt, wie wir etwas auf dem Display ausgeben.
Sowie den Artikel über die Programmierung des Touchscreen Digitizer XPT2046, der im Cheap Yellow Display steckt.
Damit wäre dann die Hardware-Ansteuerung von Display und Touchscreen bewerkstelligt. Nun kommt als Dialogsystem die LGVL Library obendrauf. In diesem Artikel erfahrt ihr, wie man diese für die weitere Verwendung einbindet und mit der Standard-LVGL-Demo (die, mit dem das Gerät ausgeliefert wurde) testet.
Im darauffolgenden Artikel haben wir dann gelernt, wie man LVGL-Dialoge entwirft und mittels Events steuert. Damit haben wir genügend gelernt, um unsere eigenen Anwendungen mit LVGL-Dialogen zu programmieren.
Doc Cool's Utilities V3
Im vorletzten Artikel habe ich die erste Version von Doc Cool's Utilities vorgestellt. Dies soll eine Sammlung von nützlichen Programmen sein, die über ein Menü aufgerufen werden sollen.
Da ich bemerkt habe, das es auch einige englischsprachige Leser gibt, versuche ich, die Dialog im Programm in (einfachem) Englisch zu halten, damit mehr Leute etwas davon haben, denn die fertige Firmware wird es wieder zum Download geben.
Außerdem spare ich mir, den kompletten Source-Code immer wieder zu wiederholen. Der steht ja schon in den vorhergehenden Artikeln. Ich werde also nur noch auf die neu hinzugekommenen Sachen eingehen. Das macht die ganzen Erklärungen kürzer und übersichtlicher.
Aus technischen Gründen, nämlich damit die WLAN-Antenne und evtl. weitere Antenne nicht von der Hand verdeckt werden und weil es der natürlicher Handhaltung am meisten entspricht, habe ich mich für ein Design der Dialoge im Portrait-Modus, also hochkant, entschieden.
Erweiterung der Touch Kalibrierung
Zu Anfang war es ja so, dass die Bereichswerte für die Größe des Touch-Screens, also wo der eigentlich berührungsempfindliche Bereich losgeht und endet, in der platformio.ini angegeben und damit "hart" einkompiliert wurde. Das ist natürlich unschön, weil man dann für jedes CYD neu kompilieren muss. Darum gab es in den Utilities V2 ja die Möglichkeit, die Daten auf der SD Karte zu speichern und dann beim Start wieder zu laden. So hat jedes CYD seine eigene SD und seine eigenen Einstellungen. Nebenbei erwähnt: das CYD ist nicht wählerisch mit der SD-Karte, es akzeptiert auch die Billig-Micro-SD-Karten für um die 2 Euro das Stück aus China.
Während XPT_XMIN, XPT_XMAX, XPT_YMIN und XPT_YMAX angeben, in welchem Bereich die Touch-Folie anklickbar ist und damit wie groß der auswertenbare Bereich, kann es trotzdem noch sein, dass die Folie ein wenig versetzt aufgeklebt ist und man immer ein paar Pixel daneben klickt. Das wiederum ist bei jedem Display individuell.
Der X-/Y-Versatz (TFT_XDIFF und TFT_YDIFF) ist jetzt nicht so gewaltig, dass man einen halbwegs großen Button nicht mehr treffen kann, aber wer es gerne präzise mag, der kann nur den Versatz pixelgenau einstellen. Dazu dienen die vier neuen Knöpfe, die glaube ich nicht viel Erklärung brauchen. Änderungen an TFT_XDIFF und TFT_YDIFF werden sofort aktiv und sind unmittelbar sichtbar.
Wichtig ist es allerdings, zuerst einmal die XPT_X/Y-Kalibrierung durchzuführen und zu speichern. Erst danach sollte man die TFT_X/Y-Kablibrierung durchführen, die die zuerst genannte Kalibrierung als Grundlage benötigt. Ist alles perfekt, kann man die Einstellungen mit Save speichern.
Damit man nicht nicht selbst eine Falle stellt, sind TFT_XDIFF und TFT_YDIFF nur im Bereich von -10 bis +10 einstellbar.
Sollte trotzdem einmal etwas fatal schiefgehen, das CYD ohne SD-Karte booten, dann werden die gespeicherten Einstellungen nicht geladen und es kann neu kalibriert werden.
Neues Entwicklertool: Raster einblenden für Dialog-Design
Es gibt eine neue "geheime" Entwickler-Option. Während 3 Sekunden lang oben links in die Ecke drücken den Screenshot auslöst, löst 3 Sekunden lang oben rechts in die Ecke drücken nun aus, dass per TFT_eSPI ein Raster auf den derzeitigen Dialog gezeichnet wird.
Dabei wird ein Linien-Raster mit 5 Pixeln Abstand gezeichnet. Das ursprüngliche Bild darunter bleibt dabei erhalten. Die Abstände all2 20 Pixel sind hellgrau und die alle 100 Pixel gelb, so dass sich leicht abzählen lässt, wohin ein Dialogelement verschoben werden muss, wenn es zum Beispiel nicht ganz mittig ist.
Ich glaube, dass wir mir eine gute Hilfe beim zukünfitgen Dialogdesign sein.
Zur Programmierung: Die Linien werden mit den TFT_eSPI-Library-Funktionen drawFastVLine() und drawFastHLine() gezeichnet, die besonders schnell sind:
void drawDesignGrid(){ // Grid mit TFT_eSPI zeichnen, um Dialogpositionen von TOPLEFT aus besser abschätzen zu können
uint16_t col;
// 5er-Schritte in blau, 20er in grau und 100er in gelb
for (int x = 0; x < TFT_HOR_RES; x += 5) {
col=TFT_BLUE;
if (x % 20 == 0) col=TFT_LIGHTGREY;
if (x % 100 == 0) col=TFT_YELLOW;
tft.drawFastVLine(x, 0, TFT_VER_RES, col);
}
for (int y = 0; y < TFT_VER_RES; y += 5) {
col=TFT_BLUE;
if (y % 20 == 0) col=TFT_LIGHTGREY;
if (y % 100 == 0) col=TFT_YELLOW;
tft.drawFastHLine(0, y, TFT_HOR_RES, col);
}
// vertikale, höherwertige Linien wurden unterbrochen, neu zeichnen
for (int x = 0; x < TFT_HOR_RES; x += 20) {
col=TFT_LIGHTGREY;
if (x % 100 == 0) col=TFT_YELLOW;
tft.drawFastVLine(x, 0, TFT_VER_RES, col);
}
}
Neuer Dialog: Settings
In Zukunft sollen natürlich auch Utilities dazu kommen, die das WLAN nutzen, wie etwa Web-Radio. Dazu braucht man natürlich eine Internetverbindung und dazu muss man irgendwo die SSID und das Passwort für den Router eingeben oder hinterlegen.
In den Beispielen müssen diese Logindaten immer als Strings fest im Source-Code eingetragen werden und werden dann "hart" mitkompiliert. Aber das ist natürlich für Utilities, die jeder nur downloaden und dann nutzen können soll ein No-Go.
Irgendwo müssen die WLAN-Logindaten also eingegeben werden. Und damit das nicht jedesmal passieren muss, sollen sie auf der SD-Karte gespeichert und beim Neustart dann automatisch wieder geladen werden. So dass man sie im Normalfall nur einmal eingeben muss, falls man das CYD nur im heimischen WLAN nutzt; aber doch noch ändern kann, um dem Freund sein CYD in dessen WLAN einmal vorzuführen.
Die Eingabemöglichkeit der Login-Daten findet man ab sofort im Dialog "Settings", in dem man zur Zeit auch die Helligkeit der Hintergrundbeleuchtung einstellen kann. Später werden hier noch weitere, notwendig werdende Einstellungen hinzukommen.
Die Benutzung ist ganz einfach: Man tippt in ein Eingabefeld, wobei sich eine Bildschirm-Tastatur im unteren Drittel des Bildschirms öffnet. Verdeckt sie dort dummerweise das Eingabefeld, dann klickt man auf das kleine Tastatur-Symbol unten links in der Tastatur und die Tastatur springt an den oberen Rand, so dass man nun sehen kann, was man eingibt.
Tippt man irgendwo außerhalb des Eingabefeldes, verschwindet die Tastatur auch wieder. Ich habe übrigens das Standard-US-Layout mit für uns vertauschtem Y und Z gelassen, weil ja auch die Benutzerführung in englisch gehalten ist.
Das Passwort-Feld zeigt das Passwort nur mit * an, so dass es keiner lesen kann, der einem kurz über die Schulter blickt. Damit man weiß, was man eingibt, wird der zuletzt eingegebene Buchstabe kurz angezeigt.
Ein Klick auf "Save" speichert die Logindaten dann auf der SD in /settings/wlan.ini und zwar unverschlüsselt. Also auf die SD-Karte gut achtgeben. Das hat den Hintergrund, dass ich ganz gerne mal Sonderzeichen in meinen Passwörtern benutze, die nicht über die Bildschirmtastatur eingegeben werden können. Durch das unverschlüsselte Speichern kann man dieses Problem nämlich folgendermaßen meistern: SD herausnehmen, in PC stecken und dort die .ini-Datei in einem beliebigen Editor editieren mit allen Sonderzeichen, die einem zur Verfügung stehen.
Neben dem Eingabefeld "WLAN SSID" ist ein kleiner Button. Diese kopiert den Inhalt der Zwischenablage in das Eingabefeld. Wie die SSID in die Zwischenablage kommt, lest ihr gleich im Dialog "Scan WLAN".
Vorher noch kurz zur Programmierung: Das Eingabefeld ist neu und wird wie folgt in LVGL definiert:
txt_wlan_ssid = lv_textarea_create(lv_screen_active());
lv_obj_add_event_cb (txt_wlan_ssid, evt_txt_field, LV_EVENT_ALL, NULL);
lv_textarea_set_one_line (txt_wlan_ssid, true);
lv_textarea_set_password_mode(txt_wlan_ssid, false);
lv_textarea_set_max_length (txt_wlan_ssid, sizeof(WLAN_SSID)-1);
lv_textarea_set_text (txt_wlan_ssid, WLAN_SSID);
lv_obj_set_width (txt_wlan_ssid, TFT_HOR_RES-45);
lv_obj_align (txt_wlan_ssid, LV_ALIGN_TOP_LEFT, 0, y);
Der Event, der für alle Textfelder gleich aussehen darf, sieht so aus und regelt das Ein- und Ausblenden der Bildschirmtastatur:
static void evt_txt_field (lv_event_t *e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t *ta = (lv_obj_t *) lv_event_get_target(e);
if (code == LV_EVENT_CLICKED || code == LV_EVENT_FOCUSED) {
if(Keyboard == NULL) createKeyboard();
lv_keyboard_set_textarea(Keyboard, ta);
} else if (code == LV_EVENT_DEFOCUSED) {
closeKeyboard();
} else if (code == LV_EVENT_READY) {
closeKeyboard();
}
}
static void createKeyboard() {
// Create a keyboard
Keyboard = lv_keyboard_create(lv_screen_active());
lv_obj_add_event_cb (Keyboard, evt_keyboard, LV_EVENT_ALL, NULL);
lv_obj_set_size (Keyboard, LV_HOR_RES, 100);
}
static void closeKeyboard() {
if (Keyboard == NULL) return;
lv_obj_delete (Keyboard);
Keyboard = NULL;
}
static void evt_keyboard(lv_event_t *e) {
int y;
lv_event_code_t code = lv_event_get_code(e);
if (code == LV_EVENT_CANCEL) { // The Close button is clicked.
// closeKeyboard();
// zwischen oben und unten wechseln
y = lv_obj_get_y(Keyboard);
// LV_LOG_USER ("Y of Keyboard = %d", y);
if ( y > TFT_VER_RES/2) { // ist unten, soll nach oben
lv_obj_align(Keyboard, LV_ALIGN_TOP_LEFT, 0, 0);
//lv_obj_set_y(Keyboard, 0);
} else {
lv_obj_set_y(Keyboard, TFT_VER_RES - lv_obj_get_height(Keyboard));
}
}
}
Neues Utility: Scan WLAN
Hat man eine WLAN-SSID wie "CNW", dann ist das leicht zu merken und einzugeben. Was aber, wenn man den Routernamen nicht geändert hat oder ändern kann und die SSID zum Beispiel "FRITZ!Box 6490 Cable" ist? Wer soll sich das denn merken?
Dafür gibt es das neue Scan WLAN-Utility. Kurz erzählt: Scannen, anklicken und damit in die Zwischenablage kopieren und dann in Setting die Zwischenablage wieder unter SSID einfügen. Fertig.
Länger erklärt: Zu Anfang ist die Liste leer. Dann klickt man auf Scan WLAN und dann braucht der ESP32 ein paar Sekunden, das WLAN zu scannen und die Daten zusammen zu suchen. Sobald das geschehen ist, wird die Tabelle gefüllt, und zwar nach dBm sortiert die Geräte mit der besten Signalstärke zuerst:
- Nr.
- SSID: Name des Routers / Access Points
- dBm: Signalstärke bzw. -dämpfung, je höher der Wert, desto besser der Empfang. BTW: -54 ist höher als -66 (Minus nicht übersehen)
- Channel: Der Kanal, den der Router im Frequenzband belegt. Hilfreich, einen leeren, störungsfreien Channel für sein eigenes WLAN zu finden
- Auth.: Art der WLAN-Verschlüsselung, von "none", also ohne Passwort über WEP, WPA2 und WPA3. Hinweis: Nicht jedes "none"-WLAN ist auch tatsächlich offen. Oft kann man nur Port 80 (HTTP) benutzen, um sich über einen Browser anzumelden.
In der Realität sieht die Tabelle übrigens ein bisschen schöner aus mit wechselnden Hintergrundfarben pro Zeile. Aber da scheint die Funktion der TFT_eSPI-Library zu versagen. Für das wahre Farb-Erlebnis also bitte das Demovideo anschauen oder die Firmware downloaden und selbst ausprobieren. Aber Fotos von dem kleinen Screen zu machen, die gut lesbar sind, ist wirklich schwierig. Da sind die Screenshots für mich einfach praktisch.
Beim Klick auf eine Zelle der Tabelle wird der Inhalt der SSID-Zelle auf dieser Zeile in die Zwischenablage kopiert und kann im Dialog Settings in das SSID-Feld kopiert werden.
Ein Hinweis zu einem Fehler, der auftauchen kann: Macht das CYD nach Klick auf Scan WLAN einfach einen Reset/Reboot, dann noch einmal die serielle Ausgabe beobachten. Wenn da etwas von Error: "Brownout detector was triggered" ("Brownout-Detektor wurde ausgelöst") steht, dann weist das darauf hin, dass nicht genügend Strom zur Verfügung steht. Der Scan-Vorgang braucht nämlich schon einiges an Saft und so manchen alte USB-Schnittstelle am PC oder kleine Powerbank kann die nicht liefern. Das führt dann zu diesem Fehler.
Ursachen dafür können sein:
- Schlechte Qualität des USB-Kabels
- USB-Kabel ist zu lang
- CYD-Platine mit einigen Defekten (schlechte Lötstellen)
- USB-Port auf der CYD-Platine hat sich "lose gewackelt"
- Defekter USB-Anschluss des Computers
- Der USB-Anschluss des Computers liefert nicht genügend Strom
- Die Powerbank liefert nicht genügend Strom
Nun aber zur Programmierung des Dialoges. Bis auf die Tabelle ist ja alles bekannt. Also beginnen wir mit deren Definition:
if (wlan_table != NULL) lv_obj_delete(wlan_table); // sonst absturz nachdem 3x hintereinander draufgeklickt
wlan_table = lv_table_create(lv_screen_active());
Je nachdem, wie breit die Spalten sein sollen, setzen wir diese. Es sind ungefähr nochmal 30 Pixel pro Zeile zu dem eigentlichen Überschriftentext hinzu zu addieren:
int p=30;
lv_table_set_column_width (wlan_table, col, p+20);
...
lv_obj_add_event_cb(wlan_table, evt_draw_table, LV_EVENT_DRAW_TASK_ADDED, NULL);
lv_obj_add_flag(wlan_table, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
lv_obj_add_event_cb(wlan_table, evt_tab_wlan_scan, LV_EVENT_VALUE_CHANGED, NULL);
Der LV_EVENT_VALUE_CHANGED dient dazu abzufangen, wenn jemand in die Tabelle klickt, um dann einen Wert in die Zwischenablage zu kopieren. Hinweis: Auch wenn LV_EVENT_CLICKED sehr viel naheliegender ist, ist dass der falsche. Der wird zwar auch bei einem Klick aufgerufen, man kann dort aber nicht die angeklickte Zelle bestimmen!
Danach füllt man einfach die Tabellezellen mit Werten über:
lv_table_set_cell_value (wlan_table, row, col, "Text");
lv_table_set_cell_value (wlan_table, 0, 0, "Nr.");
lv_table_set_cell_value (wlan_table, 0, 1, "SSID");
lv_table_set_cell_value (wlan_table, 0, 2, "dBm");
lv_table_set_cell_value (wlan_table, 0, 3, "Ch.");
lv_table_set_cell_value (wlan_table, 0, 4, "Auth.");
lv_obj_set_width(wlan_table, TFT_HOR_RES);
lv_obj_set_height(wlan_table, 180);
lv_obj_align (wlan_table, LV_ALIGN_TOP_MID, 0, 100);
static void evt_draw_table (lv_event_t * e) {
lv_draw_task_t *draw_task = lv_event_get_draw_task(e);
lv_draw_dsc_base_t *base_dsc = (lv_draw_dsc_base_t*) draw_task->draw_dsc;
// If the cells are drawn...
if(base_dsc->part == LV_PART_ITEMS) {
uint32_t row = base_dsc->id1;
uint32_t col = base_dsc->id2;
// Erste Zeile Überschrift gelb auf dunkel
if(row == 0) {
lv_draw_label_dsc_t *label_draw_dsc = lv_draw_task_get_label_dsc(draw_task); // Schriftfarbe
if(label_draw_dsc) label_draw_dsc->color = lv_color_hex(0xffff00);
lv_draw_fill_dsc_t *fill_draw_dsc = lv_draw_task_get_fill_dsc(draw_task); // Hintergrundfarbe
if(fill_draw_dsc) fill_draw_dsc->color = lv_color_hex(0x080808);
} else { // weiß auf mittel
lv_draw_label_dsc_t *label_draw_dsc = lv_draw_task_get_label_dsc(draw_task);
if(label_draw_dsc) label_draw_dsc->color = lv_color_hex(0xffffff);
lv_draw_fill_dsc_t *fill_draw_dsc = lv_draw_task_get_fill_dsc(draw_task);
if(fill_draw_dsc) fill_draw_dsc->color = lv_color_hex(0x101010);
}
// jede 2. zeile weiß auf etwas heller
if(row != 0 && (row % 2) == 0) {
lv_draw_fill_dsc_t *fill_draw_dsc = lv_draw_task_get_fill_dsc(draw_task);
if(fill_draw_dsc) fill_draw_dsc->color = lv_color_hex(0x181818);
}
}
}
static void evt_tab_wlan_scan(lv_event_t *e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t *obj = (lv_obj_t *) lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
uint32_t col;
uint32_t row;
lv_table_get_selected_cell(obj, &row, &col);
// LV_LOG_USER ("changed: row %d, col: %d", row, col); // mit LV_EVENT_VALUE_CHANGED statt clicked geht es
// SSID in Textfeld kopieren
if (lab_status != NULL) {
String txt = lv_table_get_cell_value(obj, row, 1);
txt.concat (" copied to clipboard.");
lv_label_set_text (lab_status, txt.c_str());
Clipboard = lv_table_get_cell_value(obj, row, 1);
}
}
}
Firmware Download via ESP Web Tools
Du möchtest die Firmware schon einmal ausprobieren, ohne die Entwicklungsumgebung zu installieren oder zu programmieren?
Kein Problem. Schließe einfach dein ESP32 an einen USB-Port deines PC an und klicke auf den deinem Gerät entsprechenden Button:
Demo und Video
Ich habe wieder ein kleine Demonstrations-Video gemacht, dass die neuen Dialoge in Aktion zeigt:Mein Fazit zu dieser Programmier-Episode
Bei der Touchscreen-Kalibrierung ist vielleicht ein wenig der Perfektionist in mir durchgegangen, aber jetzt ist das Thema wenigstens abgeschlossen: Genauer geht es nicht mehr.Ich war überrascht, wie einfach man mit LVGL die virtuelle Tastatur mit einem Eingabefeld verknüpfen kann. Das war super easy und klappt hervorragend.
Auch das Tabelle-Dialogelement ist sehr schön gemacht. Es macht geradezu Spaß, durch die Inhalte zu scrollen - naja, okay, mit einem kapazitiven Display würde das sicher noch eine Spur mehr Spaß machen. Aber es ist toll, wie man mit der Tabelle viele Daten anzeigen kann, wenn auch wegen des kleinen Bildschirm nicht alles auf einmal. Auf das Wie managt LVGL wirklich toll.
Einzig verwirrend ist, dass man das Value-Changed statt des Click-Events benutzen muss, will man herausfinden, welche Zelle angeklickt worden ist. Aber dann geht das auch und ist eine wertvolle Hilfe, Dinge auszuwählen.
Weitere Aussichten
In der nächsten Version und im nächsten Artikel werden wir dann endlich auch den Speaker-Anschluss benutzen und ich werde ein Web-Radio vorstellen und erklären, wie man es programmiert.Quellen, Literaturverweise und weiterführende Links
(1) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Vorstellung Hardware und Pinout
(2) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Erste Schritte Programmierung der RGB LED
(3) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Programmierung des Displays mit der TFT_eSPI-Library
(4) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Programmierung des Touchscreen Digitizer XPT2046
(5) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Einbinden der LVGL Library
(6) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Dialoge entwerfen mit der LVGL Library
(7) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - LVGL-Dialog / Utilities: RGB-LED Color Changer
(8) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Utilities Test Display und Touch
(9) LVGL-Dokumentation für Version 9.1
(2) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Erste Schritte Programmierung der RGB LED
(3) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Programmierung des Displays mit der TFT_eSPI-Library
(4) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Programmierung des Touchscreen Digitizer XPT2046
(5) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Einbinden der LVGL Library
(6) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Dialoge entwerfen mit der LVGL Library
(7) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - LVGL-Dialog / Utilities: RGB-LED Color Changer
(8) ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Utilities Test Display und Touch
(9) LVGL-Dokumentation für Version 9.1