Der Matouch 1.28″ ToolSet_Controller ist ein kompaktes ESP32-S3-Entwicklungsboard mit vielen Funktionen. Es verfügt über einen 1,28 Zoll großen runden RGB-Touchscreen mit einem Drehgeber-Ring, Wi-Fi, Bluetooth 5.0 und haptischem Vibrationsfeedback. Außerdem sind eine RTC, ein micro-SD-Kartensteckplatz sowie Anschlüsse für I²C, UART, SPI und GPIO vorhanden.
In dieser Einführung lernst du, wie du das Board für die Programmierung mit der Arduino IDE einrichtest. Zwei Codebeispiele zeigen dir, wie du das Display, den Touchscreen, den Drehgeber und den Motor für haptisches Feedback nutzt.
Lass uns loslegen …
Benötigte Teile
Du benötigst ein Matouch 1.28″ ToolSet_Controller Board von Makerfabs und ein USB-C-Kabel, um das Board zu programmieren und die Codebeispiele auszuprobieren.

Matouch 1.28″ ToolSet_Controller

USB-C-Kabel
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.
Das Matouch 1.28″ ToolSet_Controller
Der Matouch 1.28″ ToolSet_Controller wird vom ESP32-S3 Mikrocontroller angetrieben, der Dual-Core-Verarbeitung sowie Wi-Fi und Bluetooth 5.0 bietet. Im Zentrum befindet sich ein 1,28 Zoll großer runder RGB-IPS-Bildschirm mit einer Auflösung von 240 × 240 Pixeln. Das Display unterstützt kapazitiven Touch für präzise Bedienung. Um das Display herum befindet sich ein Drehgeber-Ring mit Drucktastenfunktion, der intuitive Eingaben wie Scrollen, Lautstärkeanpassung oder Menü-Navigation ermöglicht.

Bauteile des Matouch 1.28″ ToolSet_Controller
Neben Display und Drehgeber integriert das Board einen haptischen Vibrationsmotor, der taktiles Feedback liefert. Eine Echtzeituhr (RTC) sorgt für genaue Zeitmessung, selbst im Deep-Sleep-Modus. Für lokale Datenspeicherung ermöglicht der micro-SD-Kartensteckplatz einfaches Protokollieren von Informationen oder Speichern von Medien.

Das Board misst 60 × 60 Millimeter. Dieses kompakte quadratische Design erleichtert die Integration in Handcontroller, Desktop-Tools und Benutzeroberflächen. Erweiterungen sind über zugängliche Anschlüsse für I²C, UART, SPI und GPIO möglich, um externe Sensoren, Aktuatoren oder andere Module zu verwenden. Die Stromversorgung wird von einem Onboard-System verwaltet, das sowohl USB Type-C als auch externe Batterien unterstützt, jedoch keine Ladeelektronik enthält.
Pinbelegung des Matouch 1.28″ ToolSet_Controller
Das Bild unten zeigt die Pinbelegung des Matouch 1.28″ ToolSet_Controller. Es stehen 15 GPIO-Pins sowie 5V- oder 3,3V-Stromversorgungs-Pins zur Verfügung:

Der Matouch 1.28″ ToolSet_Controller eignet sich hervorragend für Projekte, die eine kleine, aber leistungsfähige Schnittstelle benötigen. Beispielanwendungen sind ein Desktop-Mediacontroller zur Lautstärkeregelung oder zum Wechseln von Titeln, ein Smart-Home-Bedienfeld oder ein Gerätkonfigurationstool.
Technische Spezifikationen
Die folgende Tabelle fasst die technischen Spezifikationen des Boards zusammen.
| Spezifikation | Details |
|---|---|
| Mikrocontroller | ESP32-S3 Dual-Core, Xtensa LX7 |
| Drahtlos | Wi-Fi 802.11 b/g/n, Bluetooth 5.0 |
| Display | 1,28″ rundes RGB IPS, 240 × 240 Pixel, kapazitiver Touch |
| Drehgeber-Eingabe | Drehgeber-Ring mit Drucktastenfunktion |
| Vibration | Haptischer Motor |
| Speicher | Micro-SD-Kartensteckplatz |
| Uhr | Echtzeituhr (RTC) |
| Erweiterung | I²C, UART, SPI, GPIO |
| Stromversorgung | USB Type-C, externe Batterie |
| Abmessungen | 60 × 60 mm |
| Open-Source-Unterstützung | Arduino IDE, Beispielprojekte auf GitHub |
Die Schaltpläne für den Matouch 1.28″ ToolSet_Controller findest du unter folgendem Link:
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 Einstellungen-Dialog über „Preferences…“ im „File“-Menü. Es öffnet sich der unten gezeigte Einstellungen-Dialog.
Unter dem Reiter „Settings“ findest du unten ein Eingabefeld mit der Bezeichnung „Additional boards manager URLs“:

In dieses Eingabefeld kopiere die folgende URL:
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 von Espressif“ Boards. Wir wollen die „esp32 libraries von Espressif“. Klicke auf die INSTALL-Schaltfläche 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 Matouch 1.28″ ToolSet_Controller 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.
Adafruit GFX Library installieren
Nachdem du den ESP32-Code installiert hast, ist der nächste Schritt die Installation der Arduino_GFX Bibliothek von moononournation, die wir zum Zeichnen auf dem Matouch 1.28″ Display verwenden. Öffne den LIBRARY MANAGER, gib „GFX Library for Arduino“ in die Suchleiste ein, finde die „GFX Library for Arduino“ von Moon und klicke auf INSTALL:

Jetzt ist alles bereit, um tatsächlich Code auf dem Matouch 1.28″ ToolSet_Controller zu schreiben und auszuführen.
Code für Encoder, Motor und Display
In diesem ersten Sketch lernst du, wie du das Display, den Encoder und den Motor für haptisches Feedback nutzt.

Wir verwenden den Encoder-Ring, um die Helligkeit des Displays zwischen 1 % und 100 % zu ändern und zeigen den Helligkeitswert auf dem Display an. Eine kurze Vibration signalisiert, wenn der Ring zu weit gedreht wird (<1 %, >100 %). Schließlich schaltet das Drücken der Encoder-Drucktaste das Display ein oder aus. Das Foto unten zeigt das Display ausgeschaltet, bei 4 % Helligkeit und bei 100 % Helligkeit:

Schau dir zuerst den kompletten Code an, bevor wir die Details besprechen:
#include <Arduino_GFX_Library.h>
#define TFT_BLK 45
#define TFT_RES 21
#define TFT_CS 1
#define TFT_MOSI 2
#define TFT_MISO -1
#define TFT_SCLK 42
#define TFT_DC 46
#define ENCODER_BTN 17
#define ENCODER_CLK 48
#define ENCODER_DT 47
#define MOTOR_PIN 41
int brightness = 50;
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, TFT_MISO, HSPI, true);
Arduino_GFX *gfx = new Arduino_GC9A01(bus, TFT_RES, 0 /* rotation */, true /* IPS */);
void encoder_irq() {
enc_state = digitalRead(ENCODER_CLK);
if (enc_state != old_state) {
brightness = digitalRead(ENCODER_DT) == enc_state ? brightness + 1 : brightness - 1;
}
old_state = enc_state;
has_changed = true;
}
void button_irq() {
btn_display = !btn_display;
has_changed = true;
}
void draw_text() {
gfx->setTextSize(2);
gfx->setCursor(60, 55);
gfx->println(F("Makerguides"));
}
void limit_brightness() {
if (brightness > 100 || brightness < 0) {
digitalWrite(MOTOR_PIN, HIGH);
delay(50);
digitalWrite(MOTOR_PIN, LOW);
}
brightness = constrain(brightness, 0, 100);
}
void update_brightness() {
gfx->fillRect(65, 95, 120, 65, WHITE);
gfx->setTextSize(6);
gfx->setCursor(65, 100);
gfx->printf("%3d", brightness);
int b = map(brightness, 0, 100, 1, 255);
analogWrite(TFT_BLK, btn_display ? b : 0);
}
void init_display() {
gfx->begin();
gfx->fillScreen(WHITE);
gfx->setTextColor(BLACK);
}
void init_pins() {
pinMode(TFT_BLK, OUTPUT);
digitalWrite(TFT_BLK, HIGH);
pinMode(MOTOR_PIN, OUTPUT);
pinMode(ENCODER_BTN, INPUT);
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
attachInterrupt(ENCODER_CLK, encoder_irq, CHANGE);
attachInterrupt(ENCODER_BTN, button_irq, FALLING);
}
void setup(void) {
Serial.begin(115200);
init_pins();
init_display();
draw_text();
}
void loop() {
if (has_changed) {
has_changed = false;
limit_brightness();
update_brightness();
}
}
Imports
Das Programm beginnt mit dem Einbinden der Grafikbibliothek für das runde GC9A01-Display. Dieses Header bringt Display-Treiber, Farbkonstanten wie WHITE, BLACK oder RED sowie Zeichenprimitive mit.
#include <Arduino_GFX_Library.h>
Pin- und Hardware-Konstanten
Benannte Konstanten ordnen den GPIO-Pins des ESP32 aussagekräftige Bezeichnungen zu. Sie definieren den PWM-Pin für die TFT-Hintergrundbeleuchtung, Reset, Chip-Select, SPI-Pins, Display-Daten/Befehl, die Drucktaste und zwei Quadraturkanäle des Drehgebers sowie den Steuerpin des Vibrationsmotors. Die einmalige Definition hier macht den restlichen Code lesbarer.
#define TFT_BLK 45 #define TFT_RES 21 #define TFT_CS 1 #define TFT_MOSI 2 #define TFT_MISO -1 #define TFT_SCLK 42 #define TFT_DC 46 #define ENCODER_BTN 17 #define ENCODER_CLK 48 #define ENCODER_DT 47 #define MOTOR_PIN 41
Globale Zustandsvariablen
Einige globale Variablen halten die aktuelle Helligkeit, den Display-Ein/Aus-Zustand, den letzten und vorherigen Logikpegel des Encoders sowie ein „dirty“-Flag, das der Hauptschleife signalisiert, wenn sich durch einen Interrupt etwas geändert hat. Die Anfangshelligkeit beträgt 50 %, das Display startet aktiviert, und old_state wird mit einem unmöglichen Wert (-1) initialisiert, sodass die allererste Encoder-Auslesung als Änderung erkannt wird.
int brightness = 50; bool btn_display = true; int enc_state = 0; int old_state = -1; bool has_changed = true;
Display-Bus- und Treiber-Objekte
Zwei Objekte richten das Display ein. Arduino_ESP32SPI konfiguriert den SPI-Bus und die Steuerpins für das TFT. Der Konstruktor wählt die DC-, CS-, SCLK-, MOSI- und MISO-Pins, das HSPI-Peripheriegerät und aktiviert DMA für schnellere Übertragungen. Arduino_GC9A01 ist der spezifische Treiber für das 1,28″ runde Panel; er erhält das SPI-Bus-Objekt, den Reset-Pin, die Rotation und das IPS-Flag. Das resultierende gfx-Objekt stellt Zeichenmethoden bereit, die im Sketch verwendet werden.
Arduino_ESP32SPI *bus = new Arduino_ESP32SPI(TFT_DC, TFT_CS, TFT_SCLK,
TFT_MOSI, TFT_MISO, HSPI, true);
Arduino_GFX *gfx = new Arduino_GC9A01(bus, TFT_RES, 0 /* rotation */, true /* IPS */);
Interrupt Service Routine: encoder_irq
Diese ISR wird bei jeder Änderung der CLK-Leitung des Encoders ausgeführt. Sie liest den aktuellen CLK-Pegel und vergleicht ihn mit dem vorherigen. Wenn ein Übergang erkannt wird, prüft sie die DT-Leitung, um die Drehrichtung zu bestimmen: Wenn DT dem neuen CLK-Pegel entspricht, wird die Helligkeit erhöht, sonst verringert. Anschließend merkt sie sich den neuen Zustand und markiert die UI als geändert, damit die Hauptschleife neu zeichnen und die neue Helligkeit anwenden kann. Die Verwendung einer ISR macht den Encoder reaktionsschnell, ohne in loop() zu warten.
void encoder_irq() {
enc_state = digitalRead(ENCODER_CLK);
if (enc_state != old_state) {
brightness = digitalRead(ENCODER_DT) == enc_state ? brightness + 1 : brightness - 1;
}
old_state = enc_state;
has_changed = true;
}
Interrupt Service Routine: button_irq
Diese ISR schaltet, ob das Display an sein soll. Jede fallende Flanke am Druckknopf des Encoders kippt btn_display und setzt ein Flag, damit die Hauptschleife den Bildschirm und die Hintergrundbeleuchtung aktualisiert.
void button_irq() {
btn_display = !btn_display;
has_changed = true;
}
Zeichen-Helfer: draw_text
Dieser Helfer platziert ein festes „Makerguides“-Label nahe der Oberseite des runden Displays. Er setzt eine kleine Textgröße, verschiebt den Cursor und gibt den String aus dem Flash-Speicher (F() Makro) aus.
void draw_text() {
gfx->setTextSize(2);
gfx->setCursor(60, 55);
gfx->println(F("Makerguides"));
}
Logik-Helfer: limit_brightness
Diese Funktion erzwingt den gültigen Helligkeitsbereich und signalisiert haptisch, wenn der Benutzer versucht, ihn zu überschreiten. Liegt der aktuelle Wert außerhalb von [0, 100], wird der Vibrationsmotor kurz aktiviert, um die Grenze anzuzeigen, und der Wert mit constrain in den Bereich zurückgesetzt. Das Motorfeedback erfolgt nur bei Erkennung eines Ausreißers, sodass Endanschläge „brummen“, normale Schritte jedoch nicht.
void limit_brightness() {
if (brightness > 100 || brightness < 0) {
digitalWrite(MOTOR_PIN, HIGH);
delay(50);
digitalWrite(MOTOR_PIN, LOW);
}
brightness = constrain(brightness, 0, 100);
}
UI- und Hintergrundbeleuchtungs-Update: update_brightness
Diese Funktion aktualisiert die numerische Anzeige auf dem Bildschirm und setzt den neuen PWM-Wert für die Hintergrundbeleuchtung. Zuerst wird ein weißes Rechteck über die vorherige Zahl gemalt, um sie sauber zu löschen, dann wird eine größere Textgröße gesetzt, der Cursor positioniert und die Helligkeit als rechtsbündiger dreistelliger Wert ausgegeben. Anschließend wird der Bereich 0–100 % auf den PWM-Bereich 1–255 abgebildet und dieser Wert an den Hintergrundbeleuchtungs-Pin geschrieben. Wenn das Display per Drucktaste ausgeschaltet wurde, wird der Duty Cycle auf null gesetzt, um die Hintergrundbeleuchtung auszuschalten, ohne den gespeicherten Helligkeitswert zu ändern.
void update_brightness() {
gfx->fillRect(65, 95, 120, 65, WHITE);
gfx->setTextSize(6);
gfx->setCursor(65, 100);
gfx->printf("%3d", brightness);
int b = map(brightness, 0, 100, 1, 255);
analogWrite(TFT_BLK, btn_display ? b : 0);
}
Display-Initialisierung: init_display
Beim Start wird der Display-Treiber initialisiert, der Bildschirm auf Weiß gesetzt und die Standardtextfarbe auf Schwarz eingestellt. Diese Schritte garantieren einen definierten Zeichenstatus, bevor UI-Elemente gerendert werden.
void init_display() {
gfx->begin();
gfx->fillScreen(WHITE);
gfx->setTextColor(BLACK);
}
Pin-Initialisierung und Interrupt-Verkabelung: init_pins
Alle GPIO-Modi werden hier konfiguriert. Der Hintergrundbeleuchtungs-Pin wird als Ausgang gesetzt und initial auf High gezogen, damit das Panel beim Start sichtbar ist. Der Motor-Pin wird als Ausgang gesetzt. Die Drucktaste, CLK- und DT-Pins des Encoders sind Eingänge. Beachte, dass der Encoder interne 10K Pull-up-Widerstände hat, sodass INPUT_PULLUP hier nicht nötig ist (auch wenn es in manchen Beispielcodes so erscheint).

Schließlich werden Hardware-Interrupts angebunden: Der Encoder-CLK nutzt CHANGE, um sowohl steigende als auch fallende Flanken zu erfassen und so maximale Auflösung zu erreichen, während der Button FALLING verwendet, um einmal pro Tastendruck auszulösen. Diese Einrichtung hält die Hauptschleife einfach und reaktionsschnell.
void init_pins() {
pinMode(TFT_BLK, OUTPUT);
digitalWrite(TFT_BLK, HIGH);
pinMode(MOTOR_PIN, OUTPUT);
pinMode(ENCODER_BTN, INPUT);
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
attachInterrupt(ENCODER_CLK, encoder_irq, CHANGE);
attachInterrupt(ENCODER_BTN, button_irq, FALLING);
}
Setup
Die setup()-Funktion initialisiert die serielle Schnittstelle für Debugging, konfiguriert Pins und Interrupts, bereitet das Display vor und zeichnet das statische Label. Nach setup() ist das Gerät bereit, auf Encoder-Bewegungen und Tastendrücke zu reagieren.
void setup(void) {
Serial.begin(115200);
init_pins();
init_display();
draw_text();
}
Hauptschleife
Die loop() ist bewusst minimal gehalten. Sie reagiert nur, wenn eine ISR das Flag has_changed gesetzt hat. Dann wird das Flag gelöscht, die Helligkeitsgrenzen mit haptischem Feedback durchgesetzt und sowohl die Anzeige als auch der PWM-Wert der Hintergrundbeleuchtung aktualisiert. Dieses Muster vermeidet unnötiges Neuzeichnen und PWM-Schreiben, was die UI flink und stromsparend hält.
void loop() {
if (has_changed) {
has_changed = false;
limit_brightness();
update_brightness();
}
}
Wie der Encoder Helligkeit und Haptik steuert
Der Encoder liefert zwei Rechtecksignale, CLK und DT, deren Phasenlage die Drehrichtung anzeigt. Bei jeder CLK-Flanke vergleicht die ISR DT mit dem neuen CLK-Pegel, um zu entscheiden, ob brightness erhöht oder verringert wird. Dreht der Benutzer über die Enden hinaus, vibriert limit_brightness() den Motor für 50 Millisekunden und begrenzt den Wert auf [0, 100]. Der numerische Wert auf dem Display zeigt immer den begrenzten Wert, während die sichtbare Helligkeit über PWM auf TFT_BLK gesteuert wird, die entweder den gemappten Duty Cycle oder null bei ausgeschaltetem Display liefert.
Code für Touchscreen
Im nächsten Codebeispiel lernst du, wie du den Touchscreen des Displays nutzt. Wir schreiben den Text „Touch“ in die Mitte des Displays und zeichnen einen schwarzen Kreis an die Stelle, an der das Display berührt wird. Das Foto unten zeigt das Controller-Display vor und nach einigen Touch-Ereignissen:

Wie zuvor empfehle ich, zuerst den kompletten Code zu überfliegen, bevor wir die Details besprechen:
#include <Wire.h>
#include <Arduino_GFX_Library.h>
#define TFT_BLK 45
#define TFT_RES 21
#define TFT_CS 1
#define TFT_MOSI 2
#define TFT_MISO -1
#define TFT_SCLK 42
#define TFT_DC 46
#define TOUCH_INT 40
#define TOUCH_SDA 38
#define TOUCH_SCL 39
#define TOUCH_RST 18
#define MOTOR_PIN 41
Arduino_ESP32SPI *bus = new Arduino_ESP32SPI(TFT_DC, TFT_CS, TFT_SCLK,
TFT_MOSI, TFT_MISO, HSPI, true);
Arduino_GFX *gfx = new Arduino_GC9A01(bus, TFT_RES, 0 /* rotation */, true /* IPS */);
int read_touch(int *x, int *y) {
byte data_raw[7];
i2c_read(0x15, 0x02, data_raw, 7);
int event = data_raw[1] >> 6;
if (event == 2) {
*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;
}
int i2c_read(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(addr, length, true);
for (int i = 0; i < length; i++) {
*reg_data++ = Wire.read();
}
return 0;
}
void init_pins() {
pinMode(TFT_BLK, OUTPUT);
digitalWrite(TFT_BLK, HIGH);
Wire.begin(TOUCH_SDA, TOUCH_SCL);
pinMode(MOTOR_PIN, OUTPUT);
}
void init_display() {
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);
init_pins();
init_display();
}
void loop() {
static int x, y;
if (read_touch(&x, &y) == 1) {
gfx->fillCircle(x, y, 5, BLACK);
digitalWrite(MOTOR_PIN, HIGH);
delay(20);
digitalWrite(MOTOR_PIN, LOW);
}
}
Imports
Das Programm bindet die I²C-Bibliothek für die Kommunikation mit dem Touch-Controller und dieselbe Grafikbibliothek wie zuvor für das runde GC9A01-Display ein. Die Wire-Bibliothek stellt begin, beginTransmission, write, endTransmission und requestFrom für Registerzugriffe auf I²C bereit, während Arduino_GFX_Library.h den Display-Treiber, Zeichenprimitive und Farbkonstanten enthält.
#include <Wire.h> #include <Arduino_GFX_Library.h>
Pin- und Hardware-Konstanten
Die Display-Pins entsprechen dem vorherigen Sketch und definieren Hintergrundbeleuchtung, Reset, SPI-Chip-Select und Busleitungen sowie den D/C-Pin. Zusätzliche Konstanten definieren Interrupt, SDA, SCL und Reset-Pins des Touch-Controllers. Der Motor-Pin steuert erneut den haptischen Vibrationsmotor. In diesem Sketch sind Touch-Interrupt und Reset-Leitungen definiert, aber nur die I²C-Leitungen werden tatsächlich genutzt.
#define TFT_BLK 45 #define TFT_RES 21 #define TFT_CS 1 #define TFT_MOSI 2 #define TFT_MISO -1 #define TFT_SCLK 42 #define TFT_DC 46 #define TOUCH_INT 40 #define TOUCH_SDA 38 #define TOUCH_SCL 39 #define TOUCH_RST 18 #define MOTOR_PIN 41
Display-Bus- und Treiber-Objekte
Die Display-Einrichtung folgt dem gleichen Muster wie zuvor. Ein Arduino_ESP32SPI-Objekt verbindet das HSPI-Peripheriegerät des ESP32 mit den gewählten Pins und aktiviert DMA, und ein Arduino_GC9A01-Objekt steuert das 1,28″ runde IPS-Panel. Das resultierende gfx-Objekt stellt dieselbe Zeichen-API bereit, die du bereits kennst.
Arduino_ESP32SPI *bus = new Arduino_ESP32SPI(TFT_DC, TFT_CS, TFT_SCLK,
TFT_MOSI, TFT_MISO, HSPI, true);
Arduino_GFX *gfx = new Arduino_GC9A01(bus, TFT_RES, 0 /* rotation */, true /* IPS */);
Touch-Reader: read_touch
Diese Funktion fragt den Touch-Controller über I²C ab, analysiert ein Paket und gibt die Touch-Koordinaten über Zeigerparameter aus. Sie liest zuerst sieben Bytes ab Register 0x02 vom Geräteadresse 0x15. Der Controller kodiert ein „Event“ in den oberen zwei Bits des X-Hoch-Bytes; ein Rechts-Shift um sechs ergibt den Event-Code.
Nur wenn das Event 2 ist, behandelt die Funktion das Paket als gültigen Fingerkontakt und berechnet die Koordinaten. Die X-Position wird gebildet, indem das niederwertige Byte genommen und die unteren vier Bits des Hoch-Bytes mit 256 multipliziert hinzuaddiert werden, was eine typische 12-Bit-Koordinate rekonstruiert; Y wird auf dieselbe Weise aus Hoch- und Nieder-Bytes dekodiert.
Bei gültigem Touch speichert die Funktion x und y über die Zeiger und gibt 1 zurück. Für alle anderen Events wird 0 zurückgegeben.
int read_touch(int *x, int *y) {
byte data_raw[7];
i2c_read(0x15, 0x02, data_raw, 7);
int event = data_raw[1] >> 6;
if (event == 2) {
*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;
}
I²C-Helfer: i2c_read
Dieser Helfer führt eine typische „Register schreiben, dann Daten lesen“-Transaktion aus. Er startet eine Übertragung an die 7-Bit-Adresse, schreibt die Registeradresse und prüft endTransmission. Ein nicht null Ergebnis signalisiert einen Fehler und gibt -1 zurück. Anschließend fordert er die angegebene Anzahl Bytes an und liest sie aus Wire.read() in den Puffer des Aufrufers, bevor er 0 für Erfolg zurückgibt. Dies ist das Low-Level-Element, auf das read_touch für das Abrufen des Touch-Pakets angewiesen ist.
int i2c_read(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(addr, length, true);
for (int i = 0; i < length; i++) {
*reg_data++ = Wire.read();
}
return 0;
}
Pin- und Bus-Initialisierung: init_pins
Die GPIO-Konfiguration entspricht dem vorherigen Sketch für Hintergrundbeleuchtung und Motor. Der Hintergrundbeleuchtungs-Pin wird als Ausgang gesetzt und auf High gezogen, damit der Bildschirm sofort sichtbar ist. Der Motor-Pin wird als Ausgang für haptische Impulse konfiguriert. Der I²C-Bus wird auf den definierten SDA- und SCL-Pins mit Wire.begin(TOUCH_SDA, TOUCH_SCL) gestartet, das die alternativen ESP32-Pins für den Touch-Controller auswählt. Es wird kein Touch-Interrupt angebunden; dieser Sketch verwendet stattdessen einfaches Polling.
void init_pins() {
pinMode(TFT_BLK, OUTPUT);
digitalWrite(TFT_BLK, HIGH);
Wire.begin(TOUCH_SDA, TOUCH_SCL);
pinMode(MOTOR_PIN, OUTPUT);
}
Display-Initialisierung: init_display
Die Display-Inbetriebnahme folgt den gleichen Schritten wie zuvor. Der gfx-Treiber wird gestartet, der Bildschirm auf Weiß gesetzt und die Textfarbe auf Schwarz eingestellt. Ein freundliches „Touch“-Label wird mittig mit größerer Textgröße angezeigt, um die erwartete Interaktion zu signalisieren. Das F()-Makro hält den Literal wieder im Flash-Speicher.
void init_display() {
gfx->begin();
gfx->fillScreen(WHITE);
gfx->setTextColor(BLACK);
gfx->setTextSize(3);
gfx->setCursor(80, 105);
gfx->print(F("Touch"));
}
Setup
Der Startvorgang ähnelt dem vorherigen Sketch. Die serielle Schnittstelle wird zum Debuggen geöffnet, Pins und I²C-Bus werden initialisiert, und das Display wird vorbereitet und beschriftet. Nach setup ist das Gerät bereit, Touches abzufragen und Feedback zu zeichnen.
void setup(void) {
Serial.begin(115200);
init_pins();
init_display();
}
Loop
Die Hauptschleife fragt kontinuierlich den Touch-Controller ab und reagiert sofort, wenn ein gültiger Kontakt gemeldet wird. Die Variablen x und y sind static deklariert, sodass ihr Speicher über Iterationen erhalten bleibt und read_touch über die Zeiger schreiben kann.
Wenn read_touch 1 zurückgibt, wird an den gemeldeten Koordinaten ein gefüllter schwarzer Kreis mit Radius fünf Pixel gezeichnet, um den Tap zu markieren. Ein kurzer 20-Millisekunden-Impuls aktiviert den Vibrationsmotor, um haptische Bestätigung des Touches zu geben.
void loop() {
static int x, y;
if (read_touch(&x, &y) == 1) {
gfx->fillCircle(x, y, 5, BLACK);
digitalWrite(MOTOR_PIN, HIGH);
delay(20);
digitalWrite(MOTOR_PIN, LOW);
}
}
Bezug zum vorherigen Sketch
Die Display-Erstellung, Initialisierung, Zeichen-API und Motorsteuerung folgen exakt den gleichen Mustern wie zuvor. Statt Encoder-Interrupts und einem has_changed-Flag fragt dieser Sketch den Touch-Controller über I²C ab und löst bei jedem gültigen Fingerkontakt haptisches Feedback aus, statt bei einem Helligkeits-Endanschlag.
Die Hintergrundbeleuchtung ist einfach aktiviert und nicht PWM-gesteuert, da hier kein Helligkeitszustand vorliegt. Die Touch-Interrupt- und Reset-Pins sind definiert, aber nicht genutzt; ein externer Interrupt auf TOUCH_INT könnte das Gerät zwischen Touches schlafen lassen, während TOUCH_RST einen Hardware-Reset des Touch-IC ermöglichen würde.
Fazit
In diesem Tutorial hast du gelernt, wie du mit dem Matouch 1.28″ ToolSet_Controller startest. Die beiden Codebeispiele rund um Display, Touchscreen, Drehgeber und haptisches Feedback sollten dir den Einstieg in dein eigenes Projekt erleichtern.
Wir haben in diesem Tutorial Wi-Fi, Bluetooth 5.0, die SD-Karte oder die RTC-Unterstützung nicht behandelt. Beispiele dazu findest du auf Makerfabs’s Github repo for the Matouch display.. Wenn du mehr über Drehgeber lernen möchtest, schau dir unser How To Interface A Quadrature Rotary Encoder Tutorial an.
Die quadratische Basis des Matouch 1.28″ ToolSet_Controllerkann für manche Anwendungen etwas groß sein. Wenn du ein ähnliches Display mit Drehgeber, aber runder Basis suchst, schau dir das CrowPanel 1.28inch-HMI ESP32 Rotary Display an. Und falls du nur ein rundes Display (ohne Drehgeber-Ring) brauchst, könnte das Digital Clock on CrowPanel 1.28″ Round Display Tutorial hilfreich sein.
Ansonsten kannst du gerne Fragen im Kommentarbereich hinterlassen.
Viel Spaß beim Tüfteln 😉

