Projekt I07 - Drehgeber mit Taster und Interrupts
Beginner-Projekte B01-B08 abgeschlossen, Grundlagen von digitalRead() und Zustandsvariablen bekannt
Der KY-040 Rotary Encoder
Inkrementeller Drehgeber mit integriertem Taster. Liefert Quadratur-Signale zur Richtungserkennung - perfekt fuer Menusteuerung!
Typ: Inkrementeller Encoder (relativ, nicht absolut)
Aufloesung: 20 Rastpunkte pro Umdrehung
Logik: Aktiv LOW (interne Pull-Ups im Modul)
Nur Pin 2 (INT0) und Pin 3 (INT1) koennen Hardware-Interrupts ausloesen. Daher CLK an Pin 2!
Bei jedem Rastpunkt aendert sich nur EIN Bit - das verhindert Fehlzaehlungen bei Uebergaengen.
Drehung RECHTS: Drehung LINKS:
CLK βββ βββββ CLK ββββ βββ
βββββ βββ βββββ
DT βββββ ββββ DT ββ βββββ
βββββ β βββββ
Bei CLK-Flanke: Bei CLK-Flanke:
CLK != DT -> ++ CLK == DT -> --
Trick: Bei jeder CLK-Aenderung pruefen: Sind CLK und DT unterschiedlich? Dann Rechtsdrehung!
Verbindungen zum Arduino
Arduino Uno KY-040
βββββββββββββ βββββββββ
β β β CLK ββββ Pin 2 (INT0)
β Pin 2 ββββΌβββββββββ€ DT ββββ Pin 3
β Pin 3 ββββΌβββββββββ€ SW ββββ Pin 4
β Pin 4 ββββΌβββββββββ€ + ββββ 5V
β β β GND ββββ GND
β 5V βββββββΌβββββββββ€ β
β GND ββββββΌβββββββββ β
βββββββββββββ βββββββββ
CLK muss an einen Interrupt-Pin! Nur Pin 2 und 3 koennen beim Uno Hardware-Interrupts.
// I07: Rotary Encoder (KY-040)
// Encoder-Pins (CLK auf Pin 2 fuer Interrupt)
#define CLK_PIN 2 // Clock (A) - Interrupt-faehig!
#define DT_PIN 3 // Data (B)
#define SW_PIN 4 // Switch (Taster)
// WICHTIG: volatile fuer Variablen in ISR!
volatile int counter = 0;
volatile bool encoderMoved = false;
void setup() {
Serial.begin(9600);
// Pins als Input mit Pull-Up
pinMode(CLK_PIN, INPUT_PULLUP);
pinMode(DT_PIN, INPUT_PULLUP);
pinMode(SW_PIN, INPUT_PULLUP);
// Interrupt auf CLK-Pin bei jeder Aenderung
attachInterrupt(digitalPinToInterrupt(CLK_PIN),
encoderISR, CHANGE);
}Teilt dem Compiler mit: Diese Variable kann sich jederzeit aendern (durch Interrupt). Verhindert Optimierungen!
CHANGE = bei jeder Flanke (HIGHβLOW und LOWβHIGH). Andere: RISING, FALLING, LOW.
// ISR = Interrupt Service Routine
// Wird bei jeder CLK-Flanke automatisch aufgerufen!
void encoderISR() {
// Richtung bestimmen durch Vergleich CLK mit DT
if (digitalRead(CLK_PIN) != digitalRead(DT_PIN)) {
counter++; // Rechtsdrehung
} else {
counter--; // Linksdrehung
}
encoderMoved = true;
}
// Merke: ISR soll SCHNELL sein!
// - Kein Serial.print() in der ISR
// - Kein delay() in der ISR
// - Nur Flag setzen, Rest im loop()Bei Rechtsdrehung aendert sich CLK bevor DT folgt - beim Lesen sind sie unterschiedlich. Bei Linksdrehung sind beide zum Lesezeitpunkt gleich. Einfach aber effektiv!
// Entprellzeit in Millisekunden
#define DEBOUNCE_TIME 50
unsigned long lastButtonTime = 0;
bool buttonPressed = false;
void checkButton() {
unsigned long currentTime = millis();
if (digitalRead(SW_PIN) == LOW) { // Taster gedrueckt
if (!buttonPressed) {
if (currentTime - lastButtonTime > DEBOUNCE_TIME) {
buttonPressed = true;
lastButtonTime = currentTime;
// Aktion bei Tastendruck
counter = 0;
Serial.println("*** RESET ***");
}
}
} else {
buttonPressed = false; // Taster losgelassen
}
}Mechanische Taster "prellen" beim Druecken - sie schalten mehrfach schnell ein/aus. Die 50ms Wartezeit filtert diese Stoerimpulse.
Simulation in Wokwi
Probiere diese Aufgaben aus
Steuere die Helligkeit einer LED mit PWM (0-255). Encoder dreht = heller/dunkler.
Blaettere durch ein Menue auf dem LCD. Encoder = navigieren, Taster = auswaehlen.
RGB-LED steuern: Encoder waehlt Farbwert, Taster wechselt zwischen R/G/B Kanal.
Encoder steuert Servo-Position von 0 bis 180 Grad. Praezise Positionierung!
Du beherrschst jetzt Hardware-Interrupts
Schnelle Reaktion mit attachInterrupt()
Sichere ISR-Variablen
Zuverlaessige Tastereingabe
I08: IR-Fernbedienung - Infrarot-Signale empfangen und dekodieren