Im letzten Beitrag und im dazugehörigen YouTube-Video habe ich gezeigt, welche ESP32-Mikrocontroller über kapazitive Touch-Pins verfügen und wie sich diese Pins grundsätzlich auswerten lassen. Dabei wurde deutlich, dass der ESP32 keinen festen „Touch“-Zustand liefert, sondern einen Messwert, der im eigenen Code interpretiert werden muss.
In diesem Beitrag gehen wir einen Schritt weiter. Anhand eines praxisnahen Beispiels zeige ich, wie sich Touch-Pins gezielt als Bedienelemente einsetzen lassen: zum Umschalten zwischen Zuständen, zum Zählen von Schritten und zur Steuerung eines Servomotors. Ziel ist es, Touch nicht nur als Ersatz für einen Taster zu verstehen, sondern als flexible Eingabequelle, mit der sich logische Abläufe und Bewegungen zuverlässig steuern lassen.
Hinweis zum verwendeten Board
In diesem Beitrag verwende ich den Wemos D1 R32, der dem Arduino-UNO-Formfaktor entspricht, intern jedoch mit einem ESP-WROOM-32 ausgestattet ist. Dadurch lassen sich Schaltungen besonders übersichtlich aufbauen, während gleichzeitig alle ESP32-spezifischen Funktionen – einschließlich der kapazitiven Touch-Pins – zur Verfügung stehen.
Die gezeigten Schaltungen und Beispiele sind jedoch nicht auf dieses Board beschränkt. Du kannst sie ebenso mit einem ESP-WROOM-32D oder vergleichbaren ESP32-Development-Boards umsetzen. Die Programmierung bleibt dabei identisch, lediglich die Pinbelegung kann je nach Board leicht variieren.
Praxisbeispiel: LEDs per Touch umschalten
Um das Prinzip kapazitiver Touch-Eingaben praxisnah zu demonstrieren, beginnen wir mit einem einfachen, aber sehr aussagekräftigen Beispiel:
Per Touch wird zwischen zwei LEDs umgeschaltet – ähnlich wie bei einem klassischen Taster, jedoch ohne mechanisches Bauteil.
Dabei geht es nicht nur darum, ein Touchevent zu erkennen, sondern vor allem darum, einen internen Zustand zu verwalten. Genau hier liegt der entscheidende Unterschied zwischen einem einmaligen Schalten und einer echten Bedienlogik.
Aufbau der Schaltung
Für die kleine Schaltung benötigst du:
- einen ESP32** zbsp. ESP-WROOM-32* oder Wemos D1 R32*
- zwei 5mm LEDs* inkl. Vorwiderstand*,
- einen 50kOhm Drehpotentiometer*,
- diverse Breadboardkabel*, sowie
- ein 400 Pin Breadboard*
Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!
** Achtung: nicht jeder ESP32 verfügt über Touchpins, die ESP32-C3/S3 und H2 zbsp. haben diese Pins nicht!
Hinweis zum ESP-WROOM-32
Je nach größe des ESP-WROOM-32(D) benötigst du zwei 400 Pin Breadboards. Dieser passt je nach Modell nicht immer auf eines drauf!
Programmieren des wechselschaltens der LEDs in der Arduino IDE
Wie ein Touchevent am ESP32 grundsätzlich ausgewertet wird, habe ich bereits im Beitrag „Kapazitiver Touch mit dem ESP32 – so einfach geht’s“ ausführlich erläutert. In diesem Beispiel bauen wir darauf auf und erweitern den Code gezielt um eine zweite LED sowie eine einfache Zustandslogik.
Anstatt den Touch-Wert direkt zum Schalten der LEDs zu verwenden, merken wir uns den aktuellen Zustand in einer Variablen. Jede gültige Berührung führt dann zu einem Wechsel dieses Zustands, wodurch abwechselnd eine der beiden LEDs eingeschaltet wird. Auf diese Weise entsteht ein klassisches Wechselschalt-Verhalten, wie man es von einem Taster kennt.
Da der ESP32 sehr schnell arbeitet, würde eine einzelne Berührung ohne weitere Maßnahmen mehrfach erkannt werden. Um das zu vermeiden, speichern wir zusätzlich den Zeitstempel des letzten gültigen Touchevents. Erst wenn seitdem ein definierter Zeitraum vergangen ist, wird ein neues Event akzeptiert. Dieses Zeitfenster gibt dem Benutzer die Möglichkeit, den Draht oder die Touchfläche loszulassen, bevor ein weiterer Zustandswechsel ausgelöst wird.
Durch diese Kombination aus Statusvariable und Zeitfenster lässt sich ein Touchevent zuverlässig als einmaliger Schaltimpuls interpretieren – eine wichtige Grundlage für alle weiteren Touch-basierten Steuerungen.
// GPIO-Pin für die blaue LED
#define ledBlauPin 18
// GPIO-Pin für die grüne LED
#define ledGruenPin 19
// Touch-Pin T0 des ESP32 (GPIO04)
#define touchPin 4
// Analoger Eingang für das Drehpotentiometer
#define rotaryResistorPin 35
// Erwarteter Wertebereich des Touch-Pins
// (abhängig vom Aufbau und der Touchfläche)
const int TOUCH_MIN_VALUE = 0;
const int TOUCH_MAX_VALUE = 1600;
// Wertebereich des ADC beim ESP32 (12 Bit)
const int ANALOG_MIN_VALUE = 0;
const int ANALOG_MAX_VALUE = 4096;
// Variablen für aktuelle Messwerte
int touchValue; // aktueller Touch-Messwert
int resistorValue; // Rohwert des Drehpotentiometers
int value; // gemappter Schwellwert für das Touchevent
// Statusvariable für das Umschalten der LEDs
// false -> grüne LED aktiv
// true -> blaue LED aktiv
bool active = false;
// Pause in Millisekunden zwischen zwei gültigen Touchevents
// dient als einfache Entprellung
const int PAUSE = 500;
// Zeitstempel der letzten gültigen Aktion
unsigned long lastAction = 0;
void setup() {
// Serielle Schnittstelle zur Ausgabe der Messwerte
Serial.begin(115200);
// LED-Pins als Ausgänge konfigurieren
pinMode(ledBlauPin, OUTPUT);
pinMode(ledGruenPin, OUTPUT);
// Initialzustand:
// grüne LED an, blaue LED aus
digitalWrite(ledGruenPin, !active);
}
void loop() {
// Aktuellen Touch-Messwert auslesen
touchValue = touchRead(touchPin);
// Aktuellen ADC-Wert des Drehpotentiometers auslesen
resistorValue = analogRead(rotaryResistorPin);
// Debug-Ausgaben im seriellen Monitor
Serial.print("Touch-Value: ");
Serial.println(touchValue);
Serial.print("Resistor-Value: ");
Serial.println(resistorValue);
// Potentiometer-Wert auf den Touch-Wertebereich abbilden
// So wird der Schwellwert zur Laufzeit einstellbar
value = map(
resistorValue,
ANALOG_MIN_VALUE,
ANALOG_MAX_VALUE,
TOUCH_MIN_VALUE,
TOUCH_MAX_VALUE
);
Serial.print("mapped-Value: ");
Serial.println(value);
// Aktuelle Laufzeit in Millisekunden abfragen
unsigned long currentMillis = millis();
// Prüfen:
// 1. Liegt ein Touchevent vor? (Touch-Wert unter Schwellwert)
// 2. Wurde die Pause seit der letzten Aktion eingehalten?
if (touchValue < value && (currentMillis > (lastAction + PAUSE))) {
// Zeitstempel der letzten Aktion aktualisieren
lastAction = currentMillis;
// Status umschalten (Toggle)
active = !active;
// LEDs entsprechend des neuen Status schalten
digitalWrite(ledBlauPin, active);
digitalWrite(ledGruenPin, !active);
}
// Kleine Pause zur Beruhigung der Messwerte
delay(50);
}
Nächstes Praxisbeispiel: Servomotor per Touch steuern
Nachdem wir Touch als „Schalter“ genutzt haben, gehen wir jetzt einen Schritt weiter und steuern einen Servomotor über kapazitive Touch-Pins. Dafür verwende ich zwei Touchpins: einer steht für „vor“, der andere für „zurück“. So lässt sich die Position des Servos schrittweise verändern – ideal, wenn man keine Taster einsetzen möchte.
Die beiden LEDs bleiben dabei im Projekt, bekommen aber eine neue Aufgabe: Sie dienen als visuelles Feedback, damit du sofort siehst, ob gerade ein Touchevent erkannt wurde. So kannst du die Touch-Auswertung unabhängig vom Servo testen und erkennst auf einen Blick, ob die Eingabe zuverlässig ausgelöst wurde.
Aufbau der Schaltung
Für die Schaltung verwende ich zusätzlich einen Servomotor vom Typ SG90. Dieser hat den Vorteil, dass er sich direkt über den Mikrocontroller versorgen und ansteuern lässt, ohne dass eine separate Stromquelle erforderlich ist. Für einfache Bewegungen und kleinere Lasten ist der SG90 daher ideal geeignet und besonders einsteigerfreundlich.
Es gibt jedoch auch größere Servomotoren, beispielsweise Modelle für 12 V, mit denen sich deutlich höhere Kräfte und größere Lasten bewegen lassen. Diese können grundsätzlich ebenfalls mit der gezeigten Schaltung angesteuert werden, benötigen jedoch zwingend eine separate Stromversorgung, da der Mikrocontroller den erforderlichen Strom nicht liefern kann.
Zum Testen habe ich die Enden der Breadboardkabel mit Alufolie versehen, um eine größere Touchfläche zu erzeugen. Nach der Feinjustierung des Schwellwerts über das Drehpotentiometer funktioniert die Touch-Erkennung damit zuverlässig und reproduzierbar.
Programmierung der Touchsteuerung für den Servomotor in der Arduino IDE
Wie du einen Servomotor am ESP32 in der Arduino IDE steuerst habe ich dir bereits im Beitrag ESP32 programmieren – Servomotor steuern ausführlich erläutert.
// Servo-Library für den ESP32
#include <ESP32Servo.h>
// GPIO-Pins für die LEDs
#define ledBlauPin 18
#define ledGruenPin 19
// Touch-Pins für Servo-Steuerung
// touchUpPin -> Servo vorwärts bewegen
// touchDownPin -> Servo rückwärts bewegen
#define touchUpPin 12
#define touchDownPin 4
// Analoger Eingang für das Drehpotentiometer (Schwellwert)
#define rotaryResistorPin 35
// GPIO-Pin für den Servomotor
#define servoPin 14
// Erwarteter Wertebereich des Touch-Pins
// (abhängig vom Aufbau und der Touchfläche)
const int TOUCH_MIN_VALUE = 0;
const int TOUCH_MAX_VALUE = 1600;
// Wertebereich des ADC beim ESP32 (12 Bit)
const int ANALOG_MIN_VALUE = 0;
const int ANALOG_MAX_VALUE = 4096;
// Variablen für aktuelle Messwerte
int touchUpValue; // Touch-Wert für "Servo vor"
int touchDownValue; // Touch-Wert für "Servo zurück"
int resistorValue; // Rohwert des Drehpotentiometers
int value; // gemappter Schwellwert für Touch-Erkennung
// Pause in Millisekunden zwischen zwei gültigen Touchevents
// dient als einfache Entprellung
const int PAUSE = 500;
// Zeitstempel der letzten gültigen Touch-Aktionen
unsigned long lastActionTouchUp = 0;
unsigned long lastActionTouchDown = 0;
// Aktuelle Servo-Position (0–180 Grad)
int servoPos = 0;
// Schrittweite für jede Touch-Aktion
const int SERVO_STEPS = 5;
// Servo-Objekt
Servo servo;
void setup() {
// Serielle Schnittstelle für Debug-Ausgaben
Serial.begin(115200);
// LED-Pins als Ausgänge konfigurieren
pinMode(ledBlauPin, OUTPUT);
pinMode(ledGruenPin, OUTPUT);
// Servo-Grundkonfiguration
// 50 Hz ist Standard für Servos
servo.setPeriodHertz(50);
// Servo an GPIO-Pin anbinden
// Pulsbreite: 500 µs (0°) bis 3000 µs (180°)
servo.attach(servoPin, 500, 3000);
// Servo in Startposition fahren
servo.write(servoPos);
}
void loop() {
// Merker, ob sich die Servo-Position geändert hat
bool servoPosChanged = false;
// Touch-Wert für "Servo vor" auslesen
touchUpValue = touchRead(touchUpPin);
Serial.print("touchUpValue: ");
Serial.println(touchUpValue);
// Touch-Wert für "Servo zurück" auslesen
touchDownValue = touchRead(touchDownPin);
Serial.print("touchDownValue: ");
Serial.println(touchDownValue);
// Potentiometer-Wert auslesen
resistorValue = analogRead(rotaryResistorPin);
// Potentiometer-Wert auf den Touch-Wertebereich abbilden
// -> Schwellwert ist zur Laufzeit einstellbar
value = map(
resistorValue,
ANALOG_MIN_VALUE,
ANALOG_MAX_VALUE,
TOUCH_MIN_VALUE,
TOUCH_MAX_VALUE
);
// Aktuelle Laufzeit abfragen
unsigned long currentMillis = millis();
// -----------------------------
// Touch "UP" → Servo vorwärts
// -----------------------------
if (touchUpValue < value &&
(currentMillis > (lastActionTouchUp + PAUSE))) {
Serial.println("UP");
// Zeitstempel aktualisieren
lastActionTouchUp = currentMillis;
// Blaue LED kurz aufleuchten lassen (visuelles Feedback)
digitalWrite(ledBlauPin, HIGH);
delay(75);
digitalWrite(ledBlauPin, LOW);
// Servo-Position erhöhen, aber max. 180°
if (servoPos < 180) {
servoPos = servoPos + SERVO_STEPS;
servoPosChanged = true;
}
}
// -----------------------------
// Touch "DOWN" → Servo zurück
// -----------------------------
if (touchDownValue < value &&
(currentMillis > (lastActionTouchDown + PAUSE))) {
Serial.println("DOWN");
// Zeitstempel aktualisieren
lastActionTouchDown = currentMillis;
// Grüne LED kurz aufleuchten lassen (visuelles Feedback)
digitalWrite(ledGruenPin, HIGH);
delay(75);
digitalWrite(ledGruenPin, LOW);
// Servo-Position verringern, aber min. 0°
if (servoPos > 0) {
servoPos = servoPos - SERVO_STEPS;
servoPosChanged = true;
}
}
// Servo nur dann bewegen, wenn sich die Position geändert hat
if (servoPosChanged && servoPos >= 0 && servoPos <= 180) {
Serial.print("Servo-Position: ");
Serial.println(servoPos);
servo.write(servoPos);
}
// Kurze Pause zur Stabilisierung der Touch-Messwerte
delay(50);
}
Fazit und Ausblick
Mit den gezeigten Beispielen hast du gesehen, dass sich die kapazitiven Touch-Pins des ESP32 weit über einfache Ein/Aus-Schaltungen hinaus einsetzen lassen. Durch die Kombination aus Schwellwerten, Zeitfenstern und Zustandslogik wird Touch zu einem vielseitigen Bedienelement – vom LED-Umschalter bis zur schrittweisen Motorsteuerung.
In weiteren Beiträgen lassen sich diese Konzepte problemlos erweitern, etwa um:
- mehrstufige Touch-Menüs
- kombinierte Touch- und Sensoreingaben
- oder Touch-Steuerungen für Displays und Aktoren
Touch ist damit weniger „Spielerei“, sondern ein ernstzunehmendes Eingabekonzept für kompakte ESP32-Projekte.
Letzte Aktualisierung am: 03. Februar 2026





