ESP32 – Drehwinkelgeber
Einleitung ESP32 Drehwinkelgeber

Drehwinkelgeber dienen zur Eingabe von Werten über einen Drehknopf. In diesem Artikel betrachte ich den preiswerten KY-04. Prinzipbedingt kann es bei diesen Ausführungen zum Prellen des Ausgangssignals kommen.
Das Programm zur Erfassung der Daten basiert auf einer Interrupt-Routine. Interrupts entkoppeln das Erfassen der Daten des Drehwinkelgebers von der ESP32 loop(). Es ist daher kein Polling notwendig.
Die Entprellung ist relativ aufwendig, da die Drehgeschwindigkeit des Sensors variieren kann und feste Entprellzeiten nicht in allen Situationen möglich sind. Das Programm erfasst die Zykluslänge des CLK-Signals des Drehwinkelgebers.
Ich betreibe den Drehwinkelgeber mit 3,3V. Es gibt verschiedene Hersteller dieses Drehwinkelgebers, die Angaben zur Versorgungsspannung sind im Markt nicht eindeutig; einige schreiben 5V, andere 3,3/5V. Mit 3,3V funktioniert das Bauteil bei mir.
Als ESP32 kommt bei mir das AZ-Delivery ESP32S Dev Kit C zum Einsatz. Die Funktion bei einem ESP8266 werde ich bei Gelegenheit testen.
Bauteile
- AZ-Delivery ESP32S Dev Kit C
- Drehwinkelgeber KY-04
Programm Drehwinkelgeber
//-------------------------------------------------------
// Drehwinkelgeber auf Basis eines ESP32
// 27.1.2025
//-------------------------------------------------------
//
// ESP32 Pin Definitionen
//
#define ROTENC_CLK 17 // CLK des Rotate Sensors
#define ROTENC_DT 16 // DT des Rotate Sensors
//
// Variablen
//
int RotencPosCount; // Rotate Sensor Zählerstand
int RotencPosLast; // Letzter Rotate Sensor Zählerstand
int ClkLast; // Letzter Level Clk
int IrCount = 0; // IRQ Zähler
unsigned long DeBounce=0; // Entprellungszähler
unsigned long DeBounceCycle=0; //
int DeBounceLength = 0; // Zykluszeit
//-------------------------------------------------------
// Interruptroutine zum Drehwinkelgeber
//
void IRAM_ATTR ClkChanged() {
//
// Start Entprellung
//
DeBounce = millis();
while ((millis()-DeBounce) < 2)
;
//
// Flanke High->Low
//
if (digitalRead(ROTENC_CLK) == LOW) {
//
// Entprellung Flanke Low->High
if ((millis()-DeBounceCycle) > DeBounceLength){
//
// Drehrichtung feststellen und +1 oder -1
//
if (digitalRead(ROTENC_DT) == HIGH)
RotencPosCount++;
else
RotencPosCount--;
//
// DEBUG Interrupt Zähler
//
IrCount++;
//
// Start Zykluslänge feststellen
//
DeBounceCycle = millis();
}
}
//
// Flanke Low->High
else
{
//
// Zykluslänge feststellen
//
DeBounceLength = millis()-DeBounceCycle;
}
}
//-------------------------------------------------------
// Setup ESP32
//
void setup() {
//
// Eingangssignale GPIO festlegen
//
pinMode(ROTENC_CLK, INPUT_PULLUP);
pinMode(ROTENC_DT,INPUT_PULLUP);
//
// Zähler und Richtung Reset
//
RotencPosCount = 0;
RotencPosLast = 0;
//
// Debug Baud einstellen
//
Serial.begin (115000);
//
// Start mitteilen
//
Serial.println ("Rotation Encoder Start!");
//
// Intterupt
//
attachInterrupt(ROTENC_CLK, ClkChanged,CHANGE);
}
//-------------------------------------------------------
// Verarbeitungsschleife ESP32
//
void loop() {
//
// Test auf Veränderung der Zählers
//
if (RotencPosLast != RotencPosCount){
//
// Debug Zähler ausgeben
//
// Bei Interruptaktionen kann es zu zeitichen
// Überschneidungen in der Ausgabe kommen. Die Aussage
// der Debuginfo kann fehlerhaft sein!
//
//Serial.print("Rotation Encoder Zähler: ");
Serial.print(IrCount);
Serial.print(" ");
Serial.print(DeBounceLength);
Serial.print(" ");
Serial.println(RotencPosCount);
RotencPosLast = RotencPosCount;
}
}
Aktualisiert: 13.2.2025