Files
VersaMCU/doc/02_encoder.md
T

57 lines
2.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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] → Roh-Vorzeichen, 0 (ungueltig/Prellen)
```
Mechanische Encoder erzeugen 4 Flanken pro Raste → Akkumulator zählt Halbschritte.
Ein Event wird erst gefeuert wenn `|accum| >= 4` (= ein vollständiger Klick).
Die VersaPad-PCB-Verdrahtung liefert das Quadratur-Vorzeichen gegenueber der sichtbaren Drehrichtung invertiert. Deshalb bleibt die LUT konventionell, aber der HAL dreht das Vorzeichen vor dem Callback mit `ENCODER_DIRECTION_SIGN = -1`. Nach aussen gilt weiterhin:
- `direction = +1` -> `ENC_CW`
- `direction = -1` -> `ENC_CCW`
## ISR-Aufbau
8 ISR-Wrapper (je einer pro Pin, da `attachInterrupt` keinen Parameter unterstützt):
```cpp
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`
- Der Callback-Pointer `s_cb` wird einmalig in `setup()` gesetzt, bevor Interrupts aktiviert werden
- ISR-Wrapper führen nur Dekodierung und Queue-Push aus; sie rufen kein USB,
NVM, LED-Rendering oder `delay()` auf
Wichtig: Die Queue wird zusätzlich vom Matrixcallback im Loop beschrieben.
Ein Encoderinterrupt kann diesen Push unterbrechen. Die Implementierung ist
damit nicht streng Single-Producer und besitzt für diesen Fall aktuell keinen
Interruptschutz. Details:
[09_known_limitations.md](09_known_limitations.md).
## Initialisierung
Initialer Zustand von A/B wird beim `encoder_init()` gelesen damit der erste Interrupt korrekt ausgewertet wird (kein "Phantom-Step" beim Einschalten).