Das CrowPanel 1.28-inch HMI ESP32 Rotary Display von Elecrow ist ein kompaktes, rundes Modul, das einen ESP32-S3 Mikrocontroller, einen 1,28-Zoll 240×240 IPS Rund-Touchscreen, einen RGB-LED-Ring und einen Drehencoder mit Druckknopf in einer Einheit vereint.
In diesem Tutorial gehen wir die wesentlichen Schritte durch, um mit dem CrowPanel zu starten – von der ersten Einrichtung bis zum Testen der Anzeige- und Eingabefunktionen. Du lernst, wie du die RGB-LEDs steuerst, Drehencoder-Daten für eine flüssige Benutzereingabe ausliest und Touch-Events vom runden Display mit einfachen Codebeispielen erfasst.
Benötigte Teile
Du benötigst nur ein CrowPanel 1.28-inch HMI ESP32 Rotary Display Board. Das Display-Modul wird mit einem USB-Kabel und GPIO-Stecker geliefert, sodass keine weitere Hardware erforderlich ist.

CrowPanel 1.28inch-HMI ESP32 Rotary Display
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
Hardware des CrowPanel 1.28inch-HMI ESP32 Rotary Display
Das CrowPanel 1.28-inch HMI ESP32 Rotary Display ist ein integriertes Hardwaremodul, das ein hochauflösendes rundes IPS-Display, einen kapazitiven Touchscreen, einen Ring aus RGB-LEDs und einen Drehencoder mit Druckknopf-Funktion kombiniert, alles gesteuert von einem ESP32-S3 Mikrocontroller.
Das Modul ist als kompakte Mensch-Maschine-Schnittstelle (HMI) für Embedded- und IoT-Projekte konzipiert, bei denen visuelles Feedback und interaktive Steuerung auf kleinem Raum benötigt werden. Das Bild unten zeigt Vorder- und Seitenansicht des Moduls mit seinen Abmessungen:

Mikrocontroller
Im Kern verwendet das CrowPanel den ESP32-S3R8, einen Dual-Core Xtensa LX7 Prozessor mit bis zu 240 MHz. Der Mikrocontroller integriert Wi-Fi (802.11 b/g/n) und Bluetooth 5.0 LE und bietet so lokale und entfernte Konnektivitätsoptionen. Er verfügt über 8 MB PSRAM und 16 MB Flash-Speicher.
Display
Das Display ist ein 1,28-Zoll rundes IPS-Panel mit einer Auflösung von 240 × 240 Pixeln und voller 65K-Farbunterstützung. Der Bildschirm nutzt SPI-Kommunikation für die Datenübertragung und bietet einen weiten Betrachtungswinkel von bis zu 178 Grad. Ein kapazitiver Touch-Controller ist im selben Modul integriert und über die I²C-Schnittstelle verbunden, was präzise Mehrpunkt-Touch-Erkennung und Gestenunterstützung ermöglicht.
Für die physische Eingabe verfügt das Modul über einen Drehencoder mit integriertem Druckknopf. Der Encoder liefert inkrementelle Positionsrückmeldung, ideal für Menü-Navigation, Parameteranpassung oder Drehwahlauswahl.
RGB LED Streifen
Das Modul enthält außerdem einen integrierten WS2812 RGB LED-Streifen mit fünf einzeln adressierbaren LEDs. Die LEDs sind in Serie geschaltet und können mit gängigen Bibliotheken wie Adafruit NeoPixel oder FastLED angesteuert werden.
Jede WS2812 LED arbeitet mit 5 V Versorgungsspannung und zieht bei maximaler Helligkeit bis zu 60 mA, wenn alle Farbkanäle (Rot, Grün, Blau) voll aktiv sind. Wenn alle fünf LEDs gleichzeitig auf voller Helligkeit leuchten, kann der Gesamtstromverbrauch etwa 300 mA (5 × 60 mA) erreichen.
Schnittstellen
Das Board wird über einen 5 V USB-C Anschluss mit Strom versorgt und verfügt über einen integrierten 3,3 V Spannungsregler für den stabilen Betrieb des ESP32 und der Peripherie. Zusätzliche Schnittstellen wie UART, I²C, SPI, FPC und GPIO-Header stehen für externe Erweiterungen zur Verfügung, sodass Entwickler Sensoren, Aktoren oder andere Steuergeräte anschließen können.
Das Modul verfügt außerdem über einen Reset-Knopf, einen Boot-Knopf zum Firmware-Flashen und eine Status-LED für visuelles Feedback während des Betriebs. Das Bild unten zeigt die Rückseite des Moduls mit den Tasten und verschiedenen Schnittstellen:

Pins
Die folgende Tabelle zeigt, welche GPIO-Pins des ESP32-S3 mit welchen Komponenten des Moduls verbunden sind. Diese Informationen benötigst du, wenn du Code für das Modul schreiben möchtest.
| Komponente | Schnittstelle / Funktion | Pin-Belegung |
|---|---|---|
| Display (GC9A01) | SPI | SCLK = 10, MOSI = 11, MISO = -1, DC = 3, CS = 9, RST = 14 |
| Bildschirm-Hintergrundbeleuchtung | GPIO | SCREEN_BACKLIGHT_PIN = 46 |
| Touchscreen (CST816D) | I²C | SDA = 6, SCL = 7, INT = 5, RST = 13 |
| OLED (SSD1306) | I²C | SDA = 38, SCL = 39 |
| RGB LED (WS2812) | Digitaler Ausgang | LED_PIN = 48, LED_NUM = 5 |
| Drehencoder | GPIO | ENCODER_A_PIN = 45, ENCODER_B_PIN = 42, SWITCH_PIN = 41 |
| Stromanzeige | GPIO | POWER_LIGHT_PIN = 40 |
| Test I/O | GPIO | IO4, IO12 |
Technische Spezifikation
Abschließend sind die technischen Spezifikationen des CrowPanel Display-Moduls in der folgenden Tabelle zusammengefasst.
| Spezifikation | Details |
|---|---|
| Mikrocontroller | ESP32-S3R8 Dual-Core Xtensa LX7 @ 240 MHz |
| Speicher | 8 MB PSRAM, 16 MB Flash |
| Display-Typ | 1,28-Zoll rundes IPS TFT |
| Auflösung | 240 × 240 Pixel |
| Farbtiefe | 65 K Farben |
| Betrachtungswinkel | 178 Grad |
| Touch-Schnittstelle | Kapazitiv, I²C-Kommunikation |
| Dreh-Eingabe | Inkrementeller Encoder mit Druckknopf |
| Kommunikationsschnittstellen | SPI, I²C, UART, GPIO |
| Konnektivität | Wi-Fi 802.11 b/g/n, Bluetooth 5.0 LE |
| Stromversorgung | 5 V über USB-C (integrierter 3,3 V Regler) |
| Programmierschnittstelle | USB-C (unterstützt Arduino, ESP-IDF) |
| Zusätzliche Features | Reset- und Boot-Tasten, RGB LED-Streifen |
Installation des ESP32 Core
Wenn dies dein erstes Projekt mit einem Board der ESP32-Serie ist, musst du zuerst den ESP32 Core installieren. Falls ESP32 Boards bereits in deiner Arduino IDE installiert sind, kannst du diesen Abschnitt überspringen.
Öffne zunächst den Preferences-Dialog über „Preferences…“ im „File“-Menü. Es öffnet sich der unten gezeigte Preferences-Dialog.
Unter dem Reiter Settings findest du unten ein Eingabefeld mit der Bezeichnung „Additional boards manager URLs“:

Füge in dieses Feld die folgende URL ein:
https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json
Damit weiß die Arduino IDE, wo sie die ESP32 Core Bibliotheken findet. Als Nächstes installieren wir die ESP32 Boards über den Boards Manager.
Öffne den Boards Manager über „Tools -> Boards -> Board Manager“. Der Boards Manager erscheint in der linken Seitenleiste. Gib „ESP32“ in das Suchfeld oben ein, und du solltest zwei Arten von ESP32 Boards sehen: die „Arduino ESP32 Boards“ und die „esp32 by Espressif“ Boards. Wir wollen die „esp32 libraries by Espressif“. Klicke auf den INSTALL Button und warte, bis der Download und die Installation abgeschlossen sind.

Board auswählen
Zum Schluss müssen wir ein ESP32 Board auswählen. Für das CrowPanel 1.28inch-HMI ESP32 Rotary Display wählen wir das generische „ESP32S3 Dev Module“. Klicke dazu auf das Dropdown-Menü und dann auf „Select other board and port…“:

Es öffnet sich ein Dialog, in dem du „esp32s3 dev“ in die Suchleiste eingibst. Du siehst das Board „ESP32S3 Dev Module“ unter Boards. Klicke darauf, wähle den COM-Port aus, um es zu aktivieren, und bestätige mit OK:

Beachte, dass du das Board per USB-Kabel mit deinem Computer verbinden musst, bevor du einen COM-Port auswählen kannst. Das CrowPanel Display Modul hat zwei Ports, einen USB-Port und einen UART-Port. Du kannst beide zum Programmieren verwenden, für den UART-Port benötigst du jedoch einen USB-zu-TTL-Konverter, siehe unten:

Der einfachere Weg ist, das mitgelieferte USB-Kabel direkt an den mit „USB“ beschrifteten Port anzuschließen, wie unten gezeigt. In diesem Fall benötigst du keinen USB-zu-TTL-Konverter.

Tool-Einstellungen
Unten findest du die Einstellungen, die du für das Board verwenden solltest. Du findest sie im Tools-Menü deiner Arduino IDE.

Wichtig für die Codebeispiele in den folgenden Abschnitten ist, USB CDC on Boot auf „Enabled“ zu setzen und den USB-Modus auf „Hardware CDC and JTAG“. So kannst du Daten über die serielle Schnittstelle senden und empfangen, was du zum Debuggen brauchst.
Codebeispiel: Serielle Schnittstelle
Wir beginnen mit dem Test der seriellen Kommunikation. Öffne deine Arduino IDE, gib den folgenden Code ein und lade ihn auf das CrowPanel Display Modul hoch.
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("Makerguides");
delay(2000);
}
Öffne dann den Serial Monitor, und du solltest alle zwei Sekunden den Text „Makerguides“ sehen. Falls nicht, überprüfe deine Tools-Einstellungen und die Baudrate (115200).
Codebeispiel: RGB LED-Streifen
Als Nächstes testen wir die integrierte RGB-LED. Du musst jedoch zuerst die Adafruit_NeoPixel Bibliothek installieren. Öffne den LIBRARY MANAGER in deiner Arduino IDE, tippe „Adafruit NeoPixel“ in die Suchleiste und installiere die Adafruit NeoPixel Bibliothek von Adafruit:

Das CrowPanel Display Modul hat einen integrierten WS2812 RGB LED-Streifen mit fünf LEDs. Das folgende Beispiel zeigt, wie man den LED-Streifen initialisiert, eine Farbe setzt und die Helligkeit mit der Adafruit NeoPixel Bibliothek schrittweise erhöht.
// ESP32 core: 3.3.2
// Adafruit_NeoPixel: 1.15.2
#include <Adafruit_NeoPixel.h>
#define LED_PIN 48
#define LED_NUM 5
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_NUM, LED_PIN, NEO_GRB + NEO_KHZ800);
void updateBrightness(int brightness) {
strip.setBrightness(brightness);
strip.show();
delay(100);
}
void initLEDs(uint8_t r, uint8_t g, uint8_t b) {
strip.begin();
strip.setBrightness(100);
for (int i = 0; i < LED_NUM; i++) {
strip.setPixelColor(i, strip.Color(r, g, b));
}
strip.show();
}
void setup() {
Serial.begin(115200);
initLEDs(255, 255, 50); // Yellow
}
void loop() {
for(int brightness=5; brightness<255; brightness+=5) {
updateBrightness(brightness);
Serial.printf("Brightness: %d\n", brightness);
}
}
Imports
Das Programm beginnt mit dem Einbinden der Adafruit_NeoPixel Bibliothek, die eine einfache Schnittstelle zur Steuerung von WS2812 LEDs bietet. Diese Bibliothek übernimmt das strikte Timing des einadrigen Kommunikationsprotokolls der LEDs, sodass du dich auf Farb- und Animationslogik konzentrieren kannst, statt auf Timing-Details.
#include <Adafruit_NeoPixel.h>
Konstanten
Zwei Konstanten definieren, wie viele LEDs angeschlossen sind und welcher GPIO-Pin sie steuert. Das CrowPanel verbindet den WS2812-Streifen mit GPIO 48, und der Streifen enthält fünf LEDs.
#define LED_PIN 48 #define LED_NUM 5
Objekterstellung
Als Nächstes wird ein NeoPixel-Streifenobjekt erstellt. Der Konstruktor nimmt drei Parameter: Anzahl der LEDs, Steuerpin und Pixeltyp-Konfiguration. Das Flag NEO_GRB + NEO_KHZ800 gibt an, dass jede LED die Farbfolge GRB (Grün, Rot, Blau) verwendet und mit 800 kHz arbeitet, was der Standardfrequenz für WS2812 LEDs entspricht.
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_NUM, LED_PIN, NEO_GRB + NEO_KHZ800);
Dieses Objekt wird im gesamten Programm verwendet, um die LEDs zu steuern – Farben setzen, Helligkeit anpassen und Datenupdates senden.
Die updateBrightness() Funktion
Diese Hilfsfunktion passt die Helligkeit des LED-Streifens dynamisch an. Die setBrightness() Methode akzeptiert einen Wert zwischen 0 (aus) und 255 (maximale Helligkeit). Nach dem Setzen der Helligkeit muss die show() Funktion aufgerufen werden, um die aktualisierten Daten an die LEDs zu senden.
void updateBrightness(int brightness) {
strip.setBrightness(brightness);
strip.show();
delay(100);
}
Die kurze Verzögerung sorgt für einen sanften, sichtbaren Übergang zwischen den Helligkeitsstufen und erzeugt einen allmählichen Einblendeffekt.
Die initLEDs() Funktion
Bevor du die LEDs steuern kannst, müssen sie initialisiert werden. Die begin() Funktion bereitet den Datenpin für die Kommunikation vor, und setBrightness(100) setzt eine Anfangshelligkeit, um nicht mit voller Intensität zu starten.
Die for-Schleife durchläuft dann alle fünf LEDs und weist ihnen mit setPixelColor() eine Farbe zu. Die strip.Color(r, g, b) Methode wandelt die einzelnen Rot-, Grün- und Blauwerte in das korrekte 24-Bit-Farbformat um, das die LEDs benötigen.
void initLEDs(uint8_t r, uint8_t g, uint8_t b) {
strip.begin();
strip.setBrightness(100);
for (int i = 0; i < LED_NUM; i++) {
strip.setPixelColor(i, strip.Color(r, g, b));
}
strip.show();
}
Schließlich überträgt show() die Farbdaten an alle LEDs, die so gleichzeitig in der gewählten Farbe leuchten. In unserem Fall ist das Gelb.
Setup
Die setup() Funktion läuft einmal, wenn der ESP32 eingeschaltet oder zurückgesetzt wird. Sie startet die serielle Kommunikation mit 115200 Baud, damit Nachrichten im Serial Monitor ausgegeben werden können. Dann ruft sie initLEDs(255, 255, 50) auf, die alle fünf LEDs in einem sanften Gelbton leuchten lässt.
void setup() {
Serial.begin(115200);
initLEDs(255, 255, 50); // Yellow
}
Loop
Die loop() Funktion läuft kontinuierlich nach dem Setup. In diesem Beispiel erhöht sie die Helligkeit schrittweise von 5 bis 255 in Schritten von 5 und ruft jedes Mal updateBrightness() auf. Nach jeder Anpassung wird der aktuelle Helligkeitswert im Serial Monitor ausgegeben.
void loop() {
for(int brightness=5; brightness<255; brightness+=5) {
updateBrightness(brightness);
Serial.printf("Brightness: %d\n", brightness);
}
}
So entsteht eine sanfte Einblend-Animation, die sich wiederholt. Setze die Helligkeit nicht auf null, sonst bleibt der LED-Streifen dunkel, auch wenn du die Helligkeit später änderst. Dann müsstest du die LED-Farben erneut setzen.
Codebeispiel: Drehencoder
Dieser Sketch baut auf dem NeoPixel-Beispiel auf und fügt eine Echtzeit-Helligkeitssteuerung mit einem mechanischen Drehencoder hinzu. Die LEDs nutzen weiterhin die Adafruit NeoPixel Bibliothek für Timing und Farbsteuerung, während der Encoder über eine Interrupt-Service-Routine ausgelesen wird, um eine reaktionsschnelle, ruckfreie Bedienung zu gewährleisten. Das Ergebnis ist ein sanfter, hardwaregesteuerter Helligkeitsregler für den fünf-LED WS2812-Streifen des CrowPanels.
// ESP32 core: 3.3.2
// Adafruit_NeoPixel: 1.15.2
#include <Adafruit_NeoPixel.h>
#define LED_PIN 48
#define LED_NUM 5
#define ENCODER_CLK 45 // A
#define ENCODER_DT 42 // B
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_NUM, LED_PIN, NEO_GRB + NEO_KHZ800);
int brightness = 50; // 0..255
int enc_state = 0;
int old_state = -1;
bool has_changed = true;
void IRAM_ATTR encoder_irq() {
enc_state = digitalRead(ENCODER_CLK);
if (enc_state != old_state) {
brightness += (digitalRead(ENCODER_DT) == enc_state) ? -5 : +5;
brightness = constrain(brightness, 5, 255);
old_state = enc_state;
has_changed = true;
}
}
void updateBrightness() {
strip.setBrightness(brightness);
strip.show();
delay(200);
}
void initLEDs(uint8_t r, uint8_t g, uint8_t b) {
strip.begin();
for (int i = 0; i < LED_NUM; i++) {
strip.setPixelColor(i, strip.Color(r, g, b));
}
updateBrightness();
}
void initEncoder() {
pinMode(ENCODER_CLK, INPUT_PULLUP);
pinMode(ENCODER_DT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), encoder_irq, CHANGE);
}
void setup() {
Serial.begin(115200);
initEncoder();
initLEDs(255, 255, 50);
has_changed = true;
}
void loop() {
if (has_changed) {
has_changed = false;
updateBrightness();
Serial.printf("Brightness: %d\n", brightness);
}
delay(1);
}
Imports
Das Programm verwendet dieselbe NeoPixel-Bibliothek wie zuvor, sodass das timingkritische Signal für WS2812 LEDs vollständig verwaltet wird und du dich auf Eingabelogik und Animation konzentrieren kannst.
#include <Adafruit_NeoPixel.h>
Konstanten
Der LED-Streifen bleibt an GPIO 48 angeschlossen und enthält wie gehabt fünf Pixel. Zwei weitere Konstanten definieren die A- und B-Kanäle des Drehencoders an GPIO 45 und GPIO 42.
#define LED_PIN 48 #define LED_NUM 5 #define ENCODER_CLK 45 // A #define ENCODER_DT 42 // B
Objekte
Das NeoPixel-Objekt ist mit denselben Parametern wie im vorherigen Beispiel konfiguriert. Die GRB-Farbfolge und 800 kHz Signalisierung entsprechen den WS2812-Anforderungen.
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_NUM, LED_PIN, NEO_GRB + NEO_KHZ800);
Statusvariablen
Der Sketch hält einen globalen Helligkeitswert im Bereich 0 bis 255 und verfolgt den aktuellen und vorherigen Zustand des Encoders. Ein boolesches Flag signalisiert der Hauptschleife, dass eine Helligkeitsänderung vorliegt, die dort umgesetzt wird.
int brightness = 50; // 0..255 int enc_state = 0; int old_state = -1; bool has_changed = true;
Die brightness Variable wird absichtlich auf einen moderaten Wert initialisiert, damit die LEDs nicht mit voller Leistung starten. Die Encoder-Zustände sind so gesetzt, dass die erste Flanke korrekt erkannt wird, und has_changed startet auf true, um eine erste Aktualisierung zu erzwingen.
Interrupt-Service-Routine: encoder_irq
Der Encoder wird im Interrupt-Kontext dekodiert, um die UI-Latenz gering zu halten. Die Routine läuft bei beiden Flanken des CLK-Kanals und vergleicht den DT-Kanal, um die Drehrichtung zu bestimmen. Wenn DT gleich CLK ist, wird die Bewegung als eine Richtung interpretiert und fünf Helligkeitsschritte subtrahiert; andernfalls werden fünf Schritte addiert. Die Schrittgröße von fünf ist ein praktischer Kompromiss zwischen feiner Steuerung und Reaktionsfähigkeit.
void IRAM_ATTR encoder_irq() {
enc_state = digitalRead(ENCODER_CLK);
if (enc_state != old_state) {
brightness += (digitalRead(ENCODER_DT) == enc_state) ? -5 : +5;
brightness = constrain(brightness, 5, 255);
old_state = enc_state;
has_changed = true;
}
}
Das IRAM_ATTR Attribut sorgt dafür, dass die Routine im Instruktions-RAM liegt, was Flash-Wartezeiten auf dem ESP32 während Interrupts vermeidet. Der constrain Aufruf begrenzt die Helligkeit auf mindestens 5, um komplett dunkle Ausgabe zu verhindern, und maximal 255. Das Flag has_changed verschiebt die eigentliche LED-Aktualisierung in den Hauptthread, wodurch die ISR kurz und deterministisch bleibt.
Helligkeitsaktualisierung: updateBrightness
Die tatsächlichen LED-Updates werden hier zentral ausgeführt. Die Funktion wendet die aktuelle Helligkeit auf den Streifen an und ruft show auf, um die gepufferten Pixel-Daten zu übertragen. Eine kurze Verzögerung macht aufeinanderfolgende Änderungen sichtbar und verhindert eine Überlastung der LED-Update-Rate.
void updateBrightness() {
strip.setBrightness(brightness);
strip.show();
delay(200);
}
Da die Helligkeit bei NeoPixel ein globaler Multiplikator ist, der beim Senden angewendet wird, aktualisiert dieser Ansatz die Intensität, ohne einzelne Pixel neu zu schreiben.
LED-Initialisierung: initLEDs
Die Initialisierungslogik entspricht dem vorherigen Beispiel, verschiebt die Helligkeit aber an updateBrightness, sodass derselbe Codepfad beim Start und während der Drehbewegungen verwendet wird. Alle fünf Pixel erhalten dieselbe Anfangsfarbe, die du für Statusanzeigen ändern kannst.
void initLEDs(uint8_t r, uint8_t g, uint8_t b) {
strip.begin();
for (int i = 0; i < LED_NUM; i++) {
strip.setPixelColor(i, strip.Color(r, g, b));
}
updateBrightness();
}
Der Aufruf von updateBrightness am Ende stellt sicher, dass die Anfangsfarbe auf dem aktuellen globalen Helligkeitsniveau erscheint.
Encoder-Initialisierung: initEncoder
Die Encoder-Kanäle sind als Eingänge mit internen Pull-ups konfiguriert, da viele Panel-Encoder Open-Collector- oder mechanische Schaltertypen sind. Der Interrupt ist an die CLK-Leitung an beiden Flanken gebunden, sodass jeder Rastpunkt einen Zustandswechsel erzeugt, den die ISR dekodieren kann.
void initEncoder() {
pinMode(ENCODER_CLK, INPUT_PULLUP);
pinMode(ENCODER_DT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), encoder_irq, CHANGE);
}
Die Verwendung von Interrupts an der CLK-Leitung statt Polling in der Schleife verhindert verpasste Schritte bei höheren Drehgeschwindigkeiten und reduziert die CPU-Auslastung. Bei besonders rauschenden Encodern kannst du einfaches Entprellen hinzufügen, indem du Änderungen innerhalb eines Mikrosekunden-Fensters ignorierst oder beide Kanäle nach kurzer Verzögerung erneut abtastest.
Setup
Die serielle Ausgabe wird für Sichtbarkeit initialisiert, der Encoder wird zuerst aktiviert, damit Benutzereingaben sofort erfasst werden, und die LEDs werden mit einem Gelbton eingeschaltet. Das Änderungsflag wird gesetzt, um sicherzustellen, dass der erste Frame an den Streifen gesendet wird, auch wenn der Encoder noch nicht gedreht wurde.
void setup() {
Serial.begin(115200);
initEncoder();
initLEDs(255, 255, 50);
has_changed = true;
}
Loop
Die Hauptschleife ist bewusst minimal gehalten. Sie prüft, ob die ISR eine Helligkeitsänderung signalisiert hat, und wendet diese dann an und gibt sie über die serielle Schnittstelle aus.
void loop() {
if (has_changed) {
has_changed = false;
updateBrightness();
Serial.printf("Brightness: %d\n", brightness);
}
delay(1);
}
Diese Struktur hält zeitkritische, kurze Arbeiten im Interrupt und lässt die aufwändigere LED-I/O im Vordergrund laufen – ein robustes Muster für reaktionsschnellen UI-Code auf dem ESP32.
Codebeispiel: Display
Im nächsten Beispiel steuern wir die Helligkeit des Displays mit dem Drehencoder. Das Bild unten zeigt drei verschiedene Helligkeitswerte (10 %, 50 %, 100 %) für das Display:

Zuerst musst du die Arduino_GFX Bibliothek von moononournation installieren, um das Display steuern zu können. Öffne den LIBRARY MANAGER, tippe „GFX Library for Arduino“ in die Suchleiste, finde die „GFX Library for Arduino“ von Moon und klicke auf INSTALL:

Der folgende Sketch verbindet den Drehencoder mit dem GC9A01 TFT Display über die Arduino_GFX Bibliothek und fügt eine PWM-Hintergrundbeleuchtungssteuerung hinzu. Er erweitert die Encoder-Konzepte aus den vorherigen Beispielen und ermöglicht die Helligkeitssteuerung des Displays mit einem Druckknopf zum Umschalten der Hintergrundbeleuchtung.
// ESP32 core: 3.3.2
// Arduino_GFX_Library: 1.6.2
#include <Arduino_GFX_Library.h>
#define TFT_SCLK 10
#define TFT_MOSI 11
#define TFT_DC 3
#define TFT_CS 9
#define TFT_RES 14
#define TFT_BLK 46
#define LCD_PWR_EN1 1 // LCD_3V3 rail
#define LCD_PWR_EN2 2 // LEDA_3V3 rail
#define ENCODER_CLK 45 // A
#define ENCODER_DT 42 // B
#define ENCODER_BTN 41 // SW (active-LOW)
int brightness = 50; // 0..100 %
bool btn_display = true;
int enc_state = 0;
int old_state = -1;
bool has_changed = true;
Arduino_ESP32SPI *bus = new Arduino_ESP32SPI(
TFT_DC, TFT_CS, TFT_SCLK, TFT_MOSI, GFX_NOT_DEFINED, FSPI, true
);
Arduino_GFX *gfx = new Arduino_GC9A01(bus, TFT_RES, 0 /* rotation */, true /* IPS */);
void IRAM_ATTR encoder_irq() {
enc_state = digitalRead(ENCODER_CLK);
if (enc_state != old_state) {
brightness += (digitalRead(ENCODER_DT) == enc_state) ? 1 : -1;
brightness = constrain(brightness, 0, 100);
old_state = enc_state;
has_changed = true;
}
}
void IRAM_ATTR button_irq() {
if (!digitalRead(ENCODER_BTN)) {
btn_display = !btn_display;
has_changed = true;
}
}
void drawText() {
gfx->setTextSize(2);
gfx->setCursor(60, 55);
gfx->println(F("Makerguides"));
}
void updateBrightness() {
gfx->fillRect(65, 95, 120, 65, WHITE);
gfx->setTextSize(6);
gfx->setCursor(65, 100);
gfx->printf("%3d", brightness);
int duty = map(brightness, 0, 100, 0, 255);
analogWrite(TFT_BLK, btn_display ? duty : 0);
}
void initPower() {
pinMode(LCD_PWR_EN1, OUTPUT);
pinMode(LCD_PWR_EN2, OUTPUT);
digitalWrite(LCD_PWR_EN1, HIGH); // must be HIGH
digitalWrite(LCD_PWR_EN2, HIGH); // must be HIGH
pinMode(TFT_BLK, OUTPUT);
analogWrite(TFT_BLK, 50);
}
void initDisplay() {
delay(20);
gfx->begin();
gfx->fillScreen(WHITE);
gfx->setTextColor(BLACK);
}
void initEncoder() {
pinMode(ENCODER_BTN, INPUT_PULLUP);
pinMode(ENCODER_CLK, INPUT_PULLUP);
pinMode(ENCODER_DT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), encoder_irq, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_BTN), button_irq, CHANGE);
}
void setup() {
Serial.begin(115200);
initPower();
initEncoder();
initDisplay();
drawText();
has_changed = true;
}
void loop() {
if (has_changed) {
has_changed = false;
updateBrightness();
Serial.printf("Brightness: %d%% (display %s)\n",
brightness, btn_display ? "ON" : "OFF");
}
delay(1);
}
Imports
Das Programm nutzt Arduino_GFX für schnelle SPI-Zeichenprimitive und einen GC9A01 Panel-Treiber. Die Bibliothek verbirgt controller-spezifische Befehle und bietet eine einheitliche API für Initialisierung, Farbfüllungen und Textdarstellung.
#include <Arduino_GFX_Library.h>
Konstanten
Pins definieren die SPI-Verbindung zum runden TFT, die Stromversorgungsleitungen für das Panel und die LED-Anode, den PWM-gesteuerten Backlight-Pin sowie die Encoder-Kanäle und den Schalter. Die Helligkeit wird als Prozentwert angegeben, sodass Benutzerfeedback direkt als 0–100 % ausgegeben werden kann.
#define TFT_SCLK 10 #define TFT_MOSI 11 #define TFT_DC 3 #define TFT_CS 9 #define TFT_RES 14 #define TFT_BLK 46 #define LCD_PWR_EN1 1 // LCD_3V3 rail #define LCD_PWR_EN2 2 // LEDA_3V3 rail #define ENCODER_CLK 45 // A #define ENCODER_DT 42 // B #define ENCODER_BTN 41 // SW (active-LOW)
Statusvariablen
Der Laufzeitstatus verfolgt den aktuellen Helligkeitsprozentsatz, ob die Hintergrundbeleuchtung aktiviert ist, den aktuellen Encoder-Zustand und ein Änderungsflag, das der ISR erlaubt, Arbeit für den Hauptthread zu planen. Wie zuvor werden ISRs kurz gehalten und I/O in den Vordergrund verschoben, um Timing-Probleme zu vermeiden.
int brightness = 50; // 0..100 % bool btn_display = true; int enc_state = 0; int old_state = -1; bool has_changed = true;
Display-Bus- und Treiberobjekte
Der Arduino_GFX Stack ist in ein Bus-Objekt und ein Panel-Objekt aufgeteilt. Der Bus kapselt den FSPI-Host des ESP32 mit DC, CS, SCLK und MOSI. Das Panel-Objekt richtet sich an den GC9A01 Controller und weiß, wie ein rundes IPS-Panel initialisiert wird. Die Rotation ist auf null gesetzt, und das letzte boolesche Flag markiert das Panel als IPS, um die korrekte Farb-Inversion und Gamma-Korrektur auszuwählen.
Arduino_ESP32SPI *bus = new Arduino_ESP32SPI( TFT_DC, TFT_CS, TFT_SCLK, TFT_MOSI, GFX_NOT_DEFINED, FSPI, true ); Arduino_GFX *gfx = new Arduino_GC9A01(bus, TFT_RES, 0 /* rotation */, true /* IPS */);
Encoder Interrupt-Service-Routine
Die Encoder-ISR spiegelt die Logik von früher wider, aber die Schrittgröße beträgt ein Prozent pro Flanke für feine Steuerung. Die Routine tastet den CLK-Kanal ab, erkennt eine Flanke, vergleicht DT zur Richtungsbestimmung, aktualisiert den Prozentsatz, begrenzt das Ergebnis und kippt das Änderungsflag.
void IRAM_ATTR encoder_irq() {
enc_state = digitalRead(ENCODER_CLK);
if (enc_state != old_state) {
brightness += (digitalRead(ENCODER_DT) == enc_state) ? 1 : -1;
brightness = constrain(brightness, 0, 100);
old_state = enc_state;
has_changed = true;
}
}
Button Interrupt-Service-Routine
Der Druckknopf des Encoders ist aktiv-low. Die ISR liest den Pin und schaltet ein boolesches Flag, das den Zustand der Hintergrundbeleuchtung repräsentiert. Zeichnen und PWM-Update werden durch Setzen des Änderungsflags in die Hauptschleife verschoben.
void IRAM_ATTR button_irq() {
if (!digitalRead(ENCODER_BTN)) {
btn_display = !btn_display;
has_changed = true;
}
}
Statischen Text zeichnen
Ein kleiner Helfer rendert ein Seitenlabel einmalig beim Start. Textgröße und Cursor sind für ein rundes 240×240 Display positioniert. Beachte, dass Arduino_GFX einen pixelbasierten Cursor verwendet, der sich mit Ausgaben weiterbewegt.
void drawText() {
gfx->setTextSize(2);
gfx->setCursor(60, 55);
gfx->println(F("Makerguides"));
}
Helligkeit und Hintergrundbeleuchtung aktualisieren
Diese Funktion aktualisiert den numerischen Wert auf dem Bildschirm und wendet PWM auf den Backlight-Pin an. Der rechteckige Bereich hinter den Ziffern wird weiß gelöscht, um Geisterbilder beim Zahlenwechsel zu vermeiden. Der Prozentwert wird in einen 8-Bit Duty Cycle umgerechnet, der analogWrite über ESP32 LEDC in Hardware-PWM umgesetzt wird. Ist die Display-Umschaltung aus, wird der Duty Cycle auf null gesetzt.
void updateBrightness() {
gfx->fillRect(65, 95, 120, 65, WHITE);
gfx->setTextSize(6);
gfx->setCursor(65, 100);
gfx->printf("%3d", brightness);
int duty = map(brightness, 0, 100, 0, 255);
analogWrite(TFT_BLK, btn_display ? duty : 0);
}
Stromversorgung initialisieren
Die Logik- und LED-Anoden-Leitungen des Panels werden vor dem Senden von Display-Befehlen aktiviert. Beide Enable-Leitungen werden auf High gesetzt. Der Backlight-Pin wird für PWM konfiguriert und auf niedrige Helligkeit (50) gesetzt, damit der Text sichtbar, aber nicht zu hell ist.
void initPower() {
pinMode(LCD_PWR_EN1, OUTPUT);
pinMode(LCD_PWR_EN2, OUTPUT);
digitalWrite(LCD_PWR_EN1, HIGH); // must be HIGH
digitalWrite(LCD_PWR_EN2, HIGH); // must be HIGH
pinMode(TFT_BLK, OUTPUT);
analogWrite(TFT_BLK, 50);
}
Display initialisieren
Nach einer kurzen Wartezeit für die Stromversorgung wird der GC9A01 Treiber gestartet, der Bildschirm auf Weiß gelöscht und die Textfarbe auf Schwarz gesetzt. Ab hier kann der Sketch beliebige Primitive und Text zeichnen.
void initDisplay() {
delay(20);
gfx->begin();
gfx->fillScreen(WHITE);
gfx->setTextColor(BLACK);
}
Encoder initialisieren
Die Encoder-Kanäle und der Knopf verwenden interne Pull-ups, passend für typische Open-Contact Encoder. Interrupts sind an den CLK-Kanal für Quadratur-Dekodierung und an den Knopf zum Umschalten gebunden. Mit CHANGE werden sowohl Druck- als auch Loslass-Flanken erfasst; die ISR prüft selbst auf den aktiv-low Zustand.
void initEncoder() {
pinMode(ENCODER_BTN, INPUT_PULLUP);
pinMode(ENCODER_CLK, INPUT_PULLUP);
pinMode(ENCODER_DT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), encoder_irq, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_BTN), button_irq, CHANGE);
}
Setup
Das System versorgt das Panel mit Strom, aktiviert die Encoder-Interrupts, initialisiert das Display, zeichnet den statischen Titel und setzt das Änderungsflag, damit der erste Helligkeits- und PWM-Update sofort erfolgt. Serielle Protokollierung ist für die Sichtbarkeit beim Testen aktiviert.
void setup() {
Serial.begin(115200);
initPower();
initEncoder();
initDisplay();
drawText();
has_changed = true;
}
Loop
Im Vordergrund wird geprüft, ob die ISRs ein Update angefordert haben. Ist das der Fall, wird die numerische Helligkeit neu gezeichnet, die Hintergrundbeleuchtung gesetzt und eine Statuszeile mit Prozentwert und Hintergrundbeleuchtungsstatus ausgegeben.
void loop() {
if (has_changed) {
has_changed = false;
updateBrightness();
Serial.printf("Brightness: %d%% (display %s)\n",
brightness, btn_display ? "ON" : "OFF");
}
delay(1);
}
Codebeispiel: Touchscreen
Im letzten Beispiel zeigen wir, wie man Touch-Daten vom CST816D kapazitiven Touch-Controller liest, der im CrowPanel 1.28-inch HMI ESP32 Rotary Display integriert ist. Es werden rote Punkte an den Stellen gezeichnet, an denen der Benutzer den Bildschirm berührt. Siehe das Beispielbild unten:

Der folgende Code verwendet dieselbe Arduino_GFX Display-Pipeline wie zuvor, fügt die Wire-Bibliothek für I²C-Lesezugriffe hinzu und dekodiert die rohen CST816D Touch-Controller-Register in Echtzeit in Bildschirmkoordinaten.
// ESP32 core: 3.3.2
// Arduino_GFX_Library: 1.6.2
#include <Wire.h>
#include <Arduino_GFX_Library.h>
#define TFT_SCLK 10
#define TFT_MOSI 11
#define TFT_MISO -1
#define TFT_DC 3
#define TFT_CS 9
#define TFT_RES 14
#define TFT_BLK 46
#define LCD_PWR_EN1 1 // LCD_3V3 rail
#define LCD_PWR_EN2 2 // LEDA_3V3 rail
#define TOUCH_INT 5
#define TOUCH_SDA 6
#define TOUCH_SCL 7
#define TOUCH_RST 13
Arduino_ESP32SPI *bus = new Arduino_ESP32SPI(
TFT_DC, TFT_CS, TFT_SCLK, TFT_MOSI, GFX_NOT_DEFINED, FSPI, true
);
Arduino_GFX *gfx = new Arduino_GC9A01(bus, TFT_RES, 0 /* rotation */, true /* IPS */);
int i2cRead(uint16_t addr, uint8_t reg_addr, uint8_t *reg_data, uint32_t length) {
Wire.beginTransmission(addr);
Wire.write(reg_addr);
if (Wire.endTransmission(true)) return -1;
Wire.requestFrom((int)addr, (int)length, (int)true);
for (uint32_t i = 0; i < length && Wire.available(); i++) {
*reg_data++ = Wire.read();
}
return 0;
}
int readTouch(int *x, int *y) {
// CST816D @ 0x15, coordinates start at register 0x02
uint8_t data_raw[7] = {0};
if (i2cRead(0x15, 0x02, data_raw, 7) != 0) return 0;
// data_raw[1] bits 7..6 = event (0:down,1:up,2:contact), low nibble high bits of X
int event = data_raw[1] >> 6;
if (event == 2 || event == 0) { // treat contact or down as a valid touch
*x = (int)data_raw[2] + (int)(data_raw[1] & 0x0F) * 256;
*y = (int)data_raw[4] + (int)(data_raw[3] & 0x0F) * 256;
return 1;
}
return 0;
}
void initPins() {
// Power rails for the LCD/backlight
pinMode(LCD_PWR_EN1, OUTPUT);
pinMode(LCD_PWR_EN2, OUTPUT);
digitalWrite(LCD_PWR_EN1, HIGH);
digitalWrite(LCD_PWR_EN2, HIGH);
// Backlight
pinMode(TFT_BLK, OUTPUT);
analogWrite (TFT_BLK, 100);
// Touch
pinMode(TOUCH_INT, INPUT_PULLUP);
pinMode(TOUCH_RST, OUTPUT);
// Reset the CST816D
digitalWrite(TOUCH_RST, LOW);
delay(5);
digitalWrite(TOUCH_RST, HIGH);
delay(50);
Wire.begin(TOUCH_SDA, TOUCH_SCL);
}
void initDisplay() {
delay(20);
gfx->begin();
gfx->fillScreen(WHITE);
gfx->setTextColor(BLACK);
gfx->setTextSize(3);
gfx->setCursor(80, 105);
gfx->print(F("Touch"));
}
void setup(void) {
Serial.begin(115200);
initPins();
initDisplay();
}
void loop() {
static int x, y;
if (readTouch(&x, &y) == 1) {
gfx->fillCircle(x, y, 5, RED);
}
}
Imports
Zwei Bibliotheken werden am Anfang des Programms eingebunden.Wire.h verwaltet die Kommunikation über den I²C-Bus, der für die Kommunikation mit dem Touch-Controller genutzt wird.Arduino_GFX_Library.h steuert die SPI-Kommunikation mit dem GC9A01 runden TFT-Display und ermöglicht einfaches Zeichnen von Text und Formen.
#include <Wire.h> #include <Arduino_GFX_Library.h>
Pin-Definitionen
Dieser Abschnitt definiert alle Pin-Belegungen für Display, Touch-Controller und Stromversorgungsleitungen.
Die SPI-Pins verbinden den ESP32 mit dem GC9A01 TFT-Controller, während die I²C-Pins (TOUCH_SDA und TOUCH_SCL) mit dem CST816D Touch-Chip kommunizieren. Separate Enable-Pins steuern die 3,3 V Leitungen für die LCD-Logik (LCD_PWR_EN1) und die LED-Hintergrundbeleuchtung (LCD_PWR_EN2).
#define TFT_SCLK 10 #define TFT_MOSI 11 #define TFT_MISO -1 #define TFT_DC 3 #define TFT_CS 9 #define TFT_RES 14 #define TFT_BLK 46 #define LCD_PWR_EN1 1 // LCD_3V3 rail #define LCD_PWR_EN2 2 // LEDA_3V3 rail #define TOUCH_INT 5 #define TOUCH_SDA 6 #define TOUCH_SCL 7 #define TOUCH_RST 13
Display-Bus- und Treiberobjekte
Die Arduino_GFX Bibliothek trennt den Display-Treiber in zwei Objekte. Arduino_ESP32SPI definiert die SPI-Bus-Konfiguration für das FSPI-Peripheriegerät des ESP32, inklusive Daten- und Steuerpins. Arduino_GC9A01 repräsentiert den spezifischen Display-Controller und verwaltet Befehle wie Initialisierung, Farbfüllungen und Textdarstellung.
Arduino_ESP32SPI *bus = new Arduino_ESP32SPI( TFT_DC, TFT_CS, TFT_SCLK, TFT_MOSI, GFX_NOT_DEFINED, FSPI, true ); Arduino_GFX *gfx = new Arduino_GC9A01(bus, TFT_RES, 0 /* rotation */, true /* IPS */);
Diese Konfiguration entspricht dem runden 240×240 IPS-Display des CrowPanels.
Die i2cRead() Hilfsfunktion
Diese Funktion bietet eine allgemeine Möglichkeit, ein oder mehrere Register von einem beliebigen I²C-Gerät zu lesen.
Sie startet die Kommunikation mit der angegebenen Geräteadresse, schreibt das zu lesende Register und fordert dann eine Anzahl von Bytes vom Gerät an. Jedes Byte wird im übergebenen Puffer reg_data gespeichert. Falls ein Schritt fehlschlägt, gibt sie -1 zurück, um einen Fehler anzuzeigen.
int i2cRead(uint16_t addr, uint8_t reg_addr, uint8_t *reg_data, uint32_t length) {
Wire.beginTransmission(addr);
Wire.write(reg_addr);
if (Wire.endTransmission(true)) return -1;
Wire.requestFrom((int)addr, (int)length, (int)true);
for (uint32_t i = 0; i < length && Wire.available(); i++) {
*reg_data++ = Wire.read();
}
return 0;
}
Diese Abstraktion hält die readTouch() Funktion sauberer und konzentriert sich auf die Interpretation der Touch-Daten statt auf Bus-Transaktionen.
Touch-Daten lesen mit readTouch()
Der CST816D Touch-Controller liefert Touch-Events und Koordinatendaten über I²C an Adresse 0x15.
Diese Funktion liest sieben Bytes beginnend ab Register 0x02, die Informationen über den aktuellen Touch-Zustand und die Koordinaten enthalten.
Wenn der Event-Code entweder Touch-Down oder Kontakt-Event (Werte 0 oder 2) anzeigt, dekodiert die Funktion die X- und Y-Positionen, indem sie die hohen und niedrigen Bits der Koordinatenregister kombiniert.
Gültige Koordinaten werden über die Zeiger x und y zurückgegeben, und die Funktion gibt 1 zurück, um einen gültigen Touch zu signalisieren.
int readTouch(int *x, int *y) {
uint8_t data_raw[7] = {0};
if (i2cRead(0x15, 0x02, data_raw, 7) != 0) return 0;
int event = data_raw[1] >> 6;
if (event == 2 || event == 0) {
*x = (int)data_raw[2] + (int)(data_raw[1] & 0x0F) * 256;
*y = (int)data_raw[4] + (int)(data_raw[3] & 0x0F) * 256;
return 1;
}
return 0;
}
Diese Register-Auswertung folgt dem CST816D Datenblatt, wo die oberen Bits jedes Koordinatenbytes im unteren Nibble des vorherigen Bytes gespeichert sind.
Stromversorgung und I/O mit initPins()
initialisieren
Bevor Display oder Touch-Controller arbeiten können, müssen die entsprechenden GPIOs konfiguriert werden.TFT_BLKDiese Funktion richtet die LCD-Stromversorgungsleitungen, PWM für die Hintergrundbeleuchtung und die Touch-Interface-Pins ein. Beide LCD-Strom-Enable-Leitungen werden auf High gesetzt, um 3,3 V für die Display-Logik und LEDs bereitzustellen. Der Backlight-Pin (
) wird für PWM konfiguriert und mit einem Duty Cycle von 100 initialisiert, was eine sichtbare Helligkeit ergibt.
void initPins() {
pinMode(LCD_PWR_EN1, OUTPUT);
pinMode(LCD_PWR_EN2, OUTPUT);
digitalWrite(LCD_PWR_EN1, HIGH);
digitalWrite(LCD_PWR_EN2, HIGH);
pinMode(TFT_BLK, OUTPUT);
analogWrite(TFT_BLK, 100);
pinMode(TOUCH_INT, INPUT_PULLUP);
pinMode(TOUCH_RST, OUTPUT);
digitalWrite(TOUCH_RST, LOW);
delay(5);
digitalWrite(TOUCH_RST, HIGH);
delay(50);
Wire.begin(TOUCH_SDA, TOUCH_SCL);
}
Die Touch-Interrupt-Leitung wird als Eingang mit internem Pull-up konfiguriert. Der CST816D Reset-Pin wird für einige Millisekunden auf Low gezogen und dann wieder auf High gesetzt, um den Touch-Controller korrekt neu zu starten. Schließlich wird der I²C-Bus auf den angegebenen SDA- und SCL-Pins initialisiert.
Display initialisieren
void initDisplay() {
delay(20);
gfx->begin();
gfx->fillScreen(WHITE);
gfx->setTextColor(BLACK);
gfx->setTextSize(3);
gfx->setCursor(80, 105);
gfx->print(F("Touch"));
}
Nach einer kurzen Verzögerung zur Stabilisierung der Stromversorgung wird das GC9A01 Display initialisiert. Der Bildschirm wird weiß gelöscht, die Textfarbe auf Schwarz gesetzt und ein „Touch“-Label in der Mitte gezeichnet, um die Bereitschaft anzuzeigen.
Diese Einrichtung schafft eine klare Leinwand, um später im Hauptloop Touch-Indikatoren zu zeichnen.
Setupsetup()Die initPins() Funktion ist einfach. Sie initialisiert die serielle Schnittstelle für Debugging und ruft dann initDisplay() und
void setup(void) {
Serial.begin(115200);
initPins();
initDisplay();
}
auf, um die Hardware vorzubereiten.
An diesem Punkt ist das Display aktiv und der Touch-Controller bereit, Koordinaten zu melden.
LoopreadTouch()Die Hauptschleife prüft kontinuierlich mit der fillCircle() Funktion auf Touch-Eingaben. Wird ein gültiger Touch erkannt, zeichnet sie einen kleinen roten Kreis an den gemeldeten Koordinaten mit der
void loop() {
static int x, y;
if (readTouch(&x, &y) == 1) {
gfx->fillCircle(x, y, 5, RED);
}
}
Funktion aus der Arduino_GFX Bibliothek. Jeder Touch erzeugt einen neuen Punkt, sodass der Benutzer auf dem Bildschirm „zeichnen“ kann.
Diese minimalistische Schleife zeigt, wie reaktionsschnell der CST816D über I²C angesprochen werden kann und wie einfach grafisches Feedback auf dem GC9A01 Display dargestellt werden kann.
Fazit
Dieses Tutorial hat dir Codebeispiele gezeigt, um mit dem CrowPanel 1.28inch-HMI ESP32 Rotary Display zu starten.Elecrows’s Github repo for the 1.28inch-HMI ESP32 Rotary DisplayFür weitere Beispiele siehe Wiki Page. Beachte jedoch, dass viele der dortigen Codebeispiele die ui- und lvgl-Bibliothek verwenden, die ich hier vermieden habe, um die Komplexität gering zu halten.
Wenn du ein ähnliches Displaymodul mit Drehencoder-Ring suchst, schau dir das Matouch 1.28″ ToolSet_Controller an. Es hat keinen RGB-LED-Ring, dafür aber eine Echtzeituhr (RTC) und einen Vibrationsmotor für haptisches Feedback. Und falls du nur ein rundes Display (ohne Drehencoder-Ring) brauchst, könnte das Digital Clock on CrowPanel 1.28″ Round Display Tutorial hilfreich sein.
Außerdem, wenn du mehr über Drehencoder lernen möchtest, schau dir unser How To Interface A Quadrature Rotary Encoder Tutorial an.
Wenn du Fragen hast, hinterlasse sie gerne im Kommentarbereich.
Viel Spaß beim Tüfteln 😉

