Für ein aktuelles Projekt benötige ich eine kleine Ampel mit den drei klassischen Farben Rot, Gelb und Grün. Natürlich könnte man dafür einfach drei normale LEDs verwenden – allerdings würden dafür auch drei GPIOs am Mikrocontroller benötigt.
Da ich die verfügbaren Pins möglichst sparsam nutzen möchte, kam mir die Idee, die Ampel selbst aufzubauen und dafür drei WS2812-LEDs zu verwenden. Der große Vorteil dieser LEDs ist, dass sie hintereinander geschaltet und über nur eine einzige Datenleitung angesteuert werden können.
Damit benötigt die komplette Ampel nur einen GPIO am Mikrocontroller. Zusammen mit einem Grove-Anschluss entsteht so eine kompakte Lösung, die sich später schnell an unterschiedliche Boards anschließen und in weitere Projekte integrieren lässt.
Was wird benötigt?
Für den Aufbau der kleinen Grove-Ampel werden nur wenige Bauteile benötigt:
- 3 × 5-mm-WS2812-LEDs*
- 1 × Grove-Buchse*
- 1 × Widerstand* für die Datenleitung, 470 Ω
- etwas Draht, z. B. AWG20*
- eine schmale Lochrasterplatine*
Für den Zusammenbau benötigst du außerdem einen Lötkolben, etwas Lötzinn und einen Seitenschneider.
Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!
Aufbau und Grove-Pinbelegung
Der Aufbau ist recht einfach, da wir für die drei WS2812-LEDs nur eine einzige Datenleitung benötigen.
Am Grove-Anschluss stehen normalerweise zwei Signalleitungen zur Verfügung. Da ich die Ampel später am XIAO Expansion Board betreiben möchte, lohnt sich ein Blick auf die dortige Belegung. Der Grove-Anschluss unten links ist mit VCC, GND, N/A und A0/D0 beschriftet.
Damit ist für die Datenleitung nur A0/D0 nutzbar. Beim Grove-Kabel entspricht das dem gelben Kabel. Die zweite Signalleitung bleibt ungenutzt.
Die Belegung sieht damit so aus:
- Rot: VCC
- Schwarz: GND
- Weiß: nicht verwendet
- Gelb: Datenleitung zu DIN der ersten WS2812-LED
Die drei WS2812-LEDs werden anschließend über DOUT → DIN miteinander verbunden.
Einbaurichtung der WS2812-LEDs
Bei den WS2812-LEDs muss auf die richtige Einbaurichtung geachtet werden. Jede LED besitzt einen Dateneingang (DIN) und einen Datenausgang (DOUT).
Die Datenleitung vom Grove-Anschluss wird mit DIN der ersten LED verbunden. Von dort geht es jeweils über DOUT zur DIN der nächsten LED weiter.
Wichtig ist daher, die Pinbelegung der verwendeten 5-mm-WS2812 vor dem Einlöten kurz zu prüfen, da sie je nach Bauform unterschiedlich angeordnet sein kann.
Warum kein LED-Streifen?
Natürlich könnte man für die Ampel auch einfach ein kurzes Stück WS2812-LED-Streifen verwenden. Technisch wäre das vermutlich sogar die einfachste Lösung.
Für meinen Aufbau wollte ich jedoch eine etwas stabilere und sauberere Variante. Einen Grove-Anschluss direkt an ein kleines Stück LED-Streifen anzulöten ist recht fummelig und mechanisch nicht besonders robust.
Die Lochrasterplatine bietet hier eine stabile Grundlage. Darauf lassen sich die drei LEDs, der Grove-Anschluss und die Verdrahtung sauber befestigen und verlöten. Dadurch entsteht am Ende ein kleines Modul, das sich problemlos an- und abstecken lässt.
Ampel programmieren
Zum Testen der Grove-Ampel können wir die drei WS2812-LEDs nacheinander wie eine echte Ampel schalten.

Dabei wird weiterhin nur eine einzige Datenleitung verwendet. Im folgenden Beispiel zeige ich die Umsetzung einmal mit Arduino C++ und einmal mit MicroPython.
Variante 1: Arduino C++
Für Arduino verwende ich die Bibliothek Adafruit NeoPixel.
#include <Adafruit_NeoPixel.h>
// GPIO für die Datenleitung.
// Beim XIAO ESP32-C6 ist A0/D0 am verwendeten Grove-Anschluss verfügbar.
#define LED_PIN D0
// Anzahl der WS2812-LEDs in der Kette
#define NUM_LEDS 3
// Reihenfolge der LEDs in der Kette von DIN nach DOUT
#define LED_GRUEN 0
#define LED_GELB 1
#define LED_ROT 2
// NeoPixel-Objekt anlegen.
// NEO_GRB beschreibt die übliche Kanalreihenfolge der WS2812.
Adafruit_NeoPixel pixels(
NUM_LEDS,
LED_PIN,
NEO_GRB + NEO_KHZ800
);
// Farben.
// Die Helligkeit ist bewusst reduziert, da die 5-mm-WS2812 sehr hell sind.
uint32_t FARBE_AUS;
uint32_t FARBE_GRUEN;
uint32_t FARBE_GELB;
uint32_t FARBE_ROT;
// Schaltet die drei Ampel-LEDs entsprechend der übergebenen Zustände.
void setzeAmpel(bool rot, bool gelb, bool gruen) {
// Zuerst alle LEDs ausschalten.
pixels.clear();
// Je nach Zustand die gewünschte LED einschalten.
if (rot) {
pixels.setPixelColor(LED_ROT, FARBE_ROT);
}
if (gelb) {
pixels.setPixelColor(LED_GELB, FARBE_GELB);
}
if (gruen) {
pixels.setPixelColor(LED_GRUEN, FARBE_GRUEN);
}
// Änderungen an die LEDs übertragen.
pixels.show();
}
void setup() {
// NeoPixel-Bibliothek initialisieren.
pixels.begin();
// Farben definieren.
// Werte von 0 bis 255 wären möglich.
// Für die kleine Ampel reichen deutlich niedrigere Werte.
FARBE_AUS = pixels.Color(0, 0, 0);
FARBE_GRUEN = pixels.Color(0, 32, 0);
FARBE_GELB = pixels.Color(32, 16, 0);
FARBE_ROT = pixels.Color(32, 0, 0);
// Zu Beginn alle LEDs ausschalten.
pixels.clear();
pixels.show();
}
void loop() {
// Phase 1: Rot für 5 Sekunden
setzeAmpel(true, false, false);
delay(5000);
// Phase 2: Rot und Gelb gleichzeitig für 2 Sekunden
setzeAmpel(true, true, false);
delay(2000);
// Phase 3: Grün für 5 Sekunden
setzeAmpel(false, false, true);
delay(5000);
// Phase 4: Gelb für 2 Sekunden
setzeAmpel(false, true, false);
delay(2000);
// Danach beginnt loop() wieder von vorne.
}
Über LED_PIN wird festgelegt, an welchem GPIO die Datenleitung angeschlossen ist. Die Konstanten LED_GRUEN, LED_GELB und LED_ROT beschreiben die physische Reihenfolge der drei LEDs in der WS2812-Kette.
Mit setzeAmpel() können die drei Zustände anschließend unabhängig voneinander aktiviert werden. Die eigentliche Ampelschaltung bleibt dadurch im loop() übersichtlich.
Variante 2: MicroPython
Mit MicroPython benötigen wir keine zusätzliche Bibliothek. Die Unterstützung für WS2812 ist über das Modul neopixel bereits vorhanden.
from machine import Pin
from neopixel import NeoPixel
from time import sleep
# GPIO für die Datenleitung.
# GPIO0 entspricht beim verwendeten XIAO ESP32-C6 dem Anschluss A0/D0.
PIN_LED = 0
# Anzahl der WS2812-LEDs
NUM_LEDS = 3
# Bei meinen verwendeten LEDs sind Rot und Grün in der internen
# Kanalreihenfolge vertauscht.
#
# Falls die Farben bei deinen LEDs korrekt dargestellt werden,
# kannst du diesen Wert auf False setzen.
ROT_GRUEN_VERTAUSCHT = True
# Reihenfolge der LEDs in der Kette von DIN nach DOUT.
#
# Die erste LED erhält den Index 0,
# die zweite LED den Index 1
# und die dritte LED den Index 2.
LED_GRUEN = 0
LED_GELB = 1
LED_ROT = 2
# NeoPixel-Objekt erstellen.
# Alle drei LEDs hängen an derselben Datenleitung.
np = NeoPixel(
Pin(PIN_LED, Pin.OUT),
NUM_LEDS
)
# Farben werden als Tupel im Format
# (Rot, Grün, Blau) angegeben.
#
# Die Helligkeit ist bewusst niedrig gewählt,
# da die 5-mm-WS2812 bereits bei kleinen Werten sehr hell leuchten.
AUS = (0, 0, 0)
GRUEN = (0, 32, 0)
GELB = (32, 16, 0)
ROT = (32, 0, 0)
# Definition der Ampelphasen.
#
# Aufbau eines Eintrags:
# (
# Name,
# Rot an,
# Gelb an,
# Grün an,
# Dauer in Sekunden
# )
PHASEN = (
("Rot", True, False, False, 5),
("Rot + Gelb", True, True, False, 2),
("Gruen", False, False, True, 5),
("Gelb", False, True, False, 2),
)
def farbe_fuer_led(farbe):
"""
Passt die Reihenfolge der Farbkanäle an.
Manche WS2812-Varianten erwarten intern nicht RGB,
sondern beispielsweise GRB.
Bei den hier verwendeten LEDs werden deshalb
Rot und Grün vertauscht.
"""
r, g, b = farbe
if ROT_GRUEN_VERTAUSCHT:
return (g, r, b)
return farbe
def setze(rot, gelb, gruen):
"""
Schaltet die drei Ampel-LEDs entsprechend
der übergebenen Zustände.
"""
# Rote LED setzen
np[LED_ROT] = farbe_fuer_led(
ROT if rot else AUS
)
# Gelbe LED setzen
np[LED_GELB] = farbe_fuer_led(
GELB if gelb else AUS
)
# Grüne LED setzen
np[LED_GRUEN] = farbe_fuer_led(
GRUEN if gruen else AUS
)
# Änderungen an die LEDs übertragen
np.write()
try:
# Ampelschaltung dauerhaft wiederholen
while True:
# Jede definierte Ampelphase nacheinander durchlaufen
for name, rot, gelb, gruen, dauer in PHASEN:
# Aktuelle Phase über die serielle Konsole ausgeben
print(name, "-", dauer, "s")
# LEDs entsprechend der Phase setzen
setze(rot, gelb, gruen)
# Phase für die definierte Zeit anzeigen
sleep(dauer)
except KeyboardInterrupt:
# Wird das Programm über Strg+C beendet,
# werden alle drei LEDs ausgeschaltet.
setze(False, False, False)
Die MicroPython-Version funktioniert nach demselben Prinzip. Über PHASEN wird festgelegt, welche LEDs eingeschaltet werden und wie lange der jeweilige Zustand aktiv bleibt.
Der zusätzliche Schalter ROT_GRUEN_VERTAUSCHT ist notwendig, falls die verwendeten WS2812 eine andere interne Reihenfolge der Farbkanäle besitzen. Leuchtet beispielsweise Grün statt Rot, kann die Zuordnung darüber korrigiert werden.
Damit lässt sich die selbst gebaute Grove-Ampel sowohl mit der Arduino IDE als auch mit MicroPython direkt testen.
Fazit
Mit drei 5-mm-WS2812-LEDs lässt sich eine kleine Ampel aufbauen, die trotz drei unterschiedlicher Farben nur einen einzigen GPIO benötigt. Durch den Grove-Anschluss und die Lochrasterplatine entsteht daraus ein kompaktes Modul, das sich schnell anstecken und später auch in anderen Projekten wiederverwenden lässt.
Für mein eigentliches Projekt ist damit die Ampel schon einmal erledigt – ohne dafür drei GPIOs zu opfern.
Letzte Aktualisierung am: 27. Oktober 2026





