VersaMCU/doc/02_encoder.md
2026-03-30 19:52:37 +02:00

1.5 KiB
Raw Blame History

Quadratur-Encoder

Dateien: hal/encoder.h, hal/encoder.cpp, config/pins.h

Hardware

4 mechanische Quadratur-Encoder mit je 2 Phasen-Pins (A, B). Pins sind INPUT_PULLUP. Encoder-SW-Tasten laufen nicht durch diesen HAL, sondern durch den Matrix-Scan (COL_0).

Dekodierung

4-State-Lookup-Table über (prev_state << 2) | cur_state:

Zustand = (A << 1) | B  →  4 Bits: 00 / 01 / 10 / 11
LUT[prev<<2 | cur] → +1 (CW), -1 (CCW), 0 (ungültig/Prellen)

Mechanische Encoder erzeugen 4 Flanken pro Raste → Akkumulator zählt Halbschritte. Ein Event wird erst gefeuert wenn |accum| >= 4 (= ein vollständiger Klick).

ISR-Aufbau

8 ISR-Wrapper (je einer pro Pin, da attachInterrupt keinen Parameter unterstützt):

static void isr_enc0_a() { handle_encoder(0); }
static void isr_enc0_b() { handle_encoder(0); }
// ... analog für Encoder 13

attachInterrupt(..., CHANGE) auf beiden Pins jedes Encoders.

handle_encoder()encoder_cb(enc_id, direction)CEventQueue::push(ENC_CW / ENC_CCW)

ISR-Sicherheit

  • s_state[] und s_accum[] sind volatile
  • CEventQueue::push() ist ISR-sicher (atomare Index-Inkremente auf Single-Core-M0+, kein Heap)
  • Der Callback-Pointer s_cb wird einmalig in setup() gesetzt, bevor Interrupts aktiviert werden

Initialisierung

Initialer Zustand von A/B wird beim encoder_init() gelesen damit der erste Interrupt korrekt ausgewertet wird (kein "Phantom-Step" beim Einschalten).