4.1 KiB
LED-System (WS2812)
Dateien: hal/ws2812.h, hal/ws2812.cpp, CButton.h, CButton.cpp
Hardware-Treiber (ws2812 HAL)
Dünner Wrapper um Adafruit NeoPixel (bit-bang, kein DMA, kein SERCOM).
| Funktion | Bedeutung |
|---|---|
ws2812_init() |
begin() + clear() + show() |
ws2812_set(idx, r, g, b) |
setPixelColor() – schreibt in RAM-Puffer |
ws2812_fill(r, g, b) |
Alle LEDs gleiche Farbe |
ws2812_show() |
Bit-Bang-Übertragung (~600 µs, Interrupts gesperrt) |
ws2812_clear() |
clear() + show() |
ws2812_show() wird in CMainController::updateLEDs() nur aufgerufen, wenn
mindestens ein Button dirty war oder eine Animation läuft. Bei einer endlos
laufenden Animation wird daher in jedem Loop ein Frame übertragen.
Der Treiber nutzt Adafruit NeoPixel per Bit-Banging; es gibt keinen
DMA-/SERCOM-Ausgabepfad.
2-Schicht-Modell (CButton)
Jeder MX-Button hat zwei LED-Schichten:
override (aktiv wenn set_override() aufgerufen) ← temporär (GUI-Benachrichtigungen)
base (Idle-Farbe aus NVM) ← dauerhaft
Aktive Farbe = override wenn aktiv, sonst base. clear_override() kehrt sofort zu base zurück, ohne base zu verändern.
Animationen
| Animation | Typ | Verhalten | Endbedingung |
|---|---|---|---|
STATIC |
— | Feste Farbe | — |
BLINK |
Helligkeit | erste Hälfte an, zweite Hälfte aus; period_ms = Vollperiode |
endlos |
PULSE |
Helligkeit | Lineares Dreieck 0→255→0 | endlos |
FADE_IN |
Helligkeit | Einmalig schwarz → voll | → STATIC (voll) |
FADE_OUT |
Helligkeit | Einmalig voll → schwarz | → STATIC (base=schwarz) |
COLOR_CYCLE |
Farbe | Hue-Sweep, ignoriert base/override | endlos |
COLOR_FADE |
Farbe | Crossfade from→to | → STATIC (base=to) |
Helligkeits-Animationen (compute_scale): Multiplizieren die aktive Farbe mit einem Skalierungsfaktor 0–255. Formel: (channel * scale) / 255.
Farb-Animationen (compute_rgb): Berechnen RGB direkt; base/override werden nicht verändert (außer bei Abschluss).
Die globale und LED-spezifische Helligkeit werden beim Initialisieren in die
Base-Farbe eingerechnet. COLOR_CYCLE ignoriert diese Base-Farbe und rendert
mit einem festen Faktor von 40 %. Auch CDC-Overrides werden von
COLOR_CYCLE/COLOR_FADE visuell überdeckt, solange die Farbanimation aktiv
ist.
COLOR_CYCLE – Hue-Arithmetik (kein Float)
Hue 0–255 aufgeteilt in 6 Segmente à 43 Einheiten. Innerhalb jedes Segments steigt/fällt ein Kanal linear:
Seg 0: R=255, G steigt (Rot → Gelb)
Seg 1: R fällt, G=255 (Gelb → Grün)
Seg 2: G=255, B steigt (Grün → Cyan)
Seg 3: G fällt, B=255 (Cyan → Blau)
Seg 4: B=255, R steigt (Blau → Magenta)
Seg 5: R=255, B fällt (Magenta → Rot)
Ausgabe wird auf 40 % Helligkeit skaliert (Faktor 102/255) damit die LEDs nicht blenden.
Die Firmware verwendet eine eigene ganzzahlige Hue-Umrechnung und ruft
Adafruit_NeoPixel::ColorHSV() nicht auf.
Für PULSE muss period_ms >= 2 gelten, da der Code durch die halbe Periode
teilt. Configvalidierung lehnt kleinere Werte ab; set_anim() klemmt direkte
interne Aufrufe zusätzlich auf mindestens 2 ms.
COLOR_FADE benötigt set_color_fade(to, period_ms). Beim Laden aus der
Config interpretiert der Controller die gespeicherte Base-Farbe als Ziel und
startet einen einmaligen Fade von Schwarz zu dieser Farbe.
Phasenversatz (Regenbogen-Wellen)
set_anim(COLOR_CYCLE, period, phase_offset_ms): m_anim_start_ms = millis() - phase_offset_ms. Die 20 MX-Buttons werden in init_buttons() gleichmäßig phasenverschoben initialisiert:
uint16_t phase = (mx_idx * period) / 20;
Render-Pipeline
CMainController::updateLEDs()
für jeden CButton:
CButton::render_led()
if !dirty && !is_animating(): return false
rgb = compute_rgb()
ws2812_set(led_index, rgb.r, rgb.g, rgb.b)
dirty = false
return true
if any returned true:
ws2812_show()
dirty wird gesetzt bei: init(), set_base(), set_override(), clear_override(), set_anim(), clear_anim(), Animations-Abschluss.