In diesem Beitrag teste ich ein Arduino-Reaktionsspiel mit Claude Code auf einem echten Arduino UNO R3. Die Idee: Claude Code soll den kompletten Arduino-Sketch für ein kleines Reaktionsspiel erstellen, inklusive LED-Signal, Tasterabfrage, zufälliger Wartezeit, Fehlstart-Erkennung und Ausgabe der Reaktionszeit im seriellen Monitor.
Für diesen Beitrag setze ich voraus, dass Claude Code bereits installiert und einsatzbereit ist. Falls du Claude Code noch nicht eingerichtet hast, findest du in meinem Beitrag „Claude Code unter Windows 11 mit WSL installieren – Schritt für Schritt“ eine ausführliche Anleitung zur Installation und Einrichtung.
In diesem Praxistest geht es also nicht darum, Claude Code nur theoretisch auszuprobieren. Der generierte Code soll am Ende auf echter Hardware laufen. Genau deshalb nutze ich einen klassischen Arduino UNO R3, eine grüne LED, einen roten Taster und optional einen Piezo-Buzzer.
Was soll das Arduino-Reaktionsspiel können?
Das Projekt ist bewusst einfach gehalten, eignet sich aber sehr gut für einen Praxistest mit Claude Code. Denn auch bei einem kleinen Arduino-Projekt müssen mehrere Dinge sauber zusammenspielen: die Pinbelegung, die Tasterlogik, die Zeitmessung und die Ausgabe im seriellen Monitor.
Der Ablauf des Reaktionsspiels soll wie folgt funktionieren:
- Nach dem Start wartet der Arduino eine zufällige Zeit zwischen 2 und 6 Sekunden.
- Während dieser Wartezeit darf der Taster nicht gedrückt werden.
- Wird der Taster zu früh gedrückt, soll ein Fehlstart erkannt werden.
- Nach Ablauf der Wartezeit leuchtet die grüne LED.
- Ab diesem Moment wird die Reaktionszeit gemessen.
- Der Nutzer drückt den roten Taster.
- Die gemessene Reaktionszeit wird im seriellen Monitor ausgegeben.
- Danach startet automatisch eine neue Runde.
Gerade die Fehlstart-Erkennung ist hier interessant. Ein einfacher Sketch mit delay() würde zwar die Wartezeit abbilden, könnte während dieser Zeit aber nicht zuverlässig prüfen, ob der Taster bereits gedrückt wurde. Genau an solchen Stellen zeigt sich, ob der von Claude Code erzeugte Sketch wirklich durchdacht ist.
Die Schaltung vorbereiten
Bevor ich Claude Code mit dem Arduino-Sketch beauftrage, muss zuerst die Schaltung festgelegt werden. Diesen Schritt kann mir der KI-Assistent nicht abnehmen, denn Claude Code sieht meine reale Hardware nicht. Er weiß also nicht, wie LED, Taster und Buzzer tatsächlich auf dem Breadboard angeschlossen sind.
Für dieses Projekt verwende ich eine sehr einfache Schaltung:
| Bauteil | Arduino Pin | Hinweis |
|---|---|---|
| Grüne LED | Pin 6 | über Vorwiderstand mit GND verbunden |
| Roter Taster | Pin 2 | gegen GND geschaltet |
| Piezo-Buzzer | Pin 9 | optional |
| GND | Masse | gemeinsame Masse für alle Bauteile |
Besonders wichtig ist der rote Taster. Dieser wird zwischen Pin 2 und GND angeschlossen. Im Arduino-Sketch soll dafür der interne Pullup-Widerstand verwendet werden. Dadurch wird kein zusätzlicher Widerstand für den Taster benötigt.

Das bedeutet aber auch, dass die Logik im Code invertiert ist:
pinMode(buttonPin, INPUT_PULLUP);
Ein nicht gedrückter Taster liefert dadurch HIGH. Wird der Taster gedrückt, wird Pin 2 mit GND verbunden und der Arduino liest LOW.
Genau diese Information muss später auch im Prompt für Claude Code stehen. Wenn der KI-Assistent nicht weiß, dass der Taster gegen GND geschaltet ist und mit INPUT_PULLUP verwendet werden soll, kann schnell eine falsche Tasterlogik entstehen.
Die Schaltung ist also die Grundlage für den späteren Code. Erst wenn klar ist, welches Bauteil an welchem Pin angeschlossen ist, kann Claude Code daraus einen passenden Arduino-Sketch erzeugen.
Warum der Prompt möglichst vollständig sein sollte
Bevor ich Claude Code mit der eigentlichen Aufgabe starte, ist ein Punkt besonders wichtig: Der KI-Assistent sollte möglichst alle relevanten Informationen direkt im ersten Prompt erhalten.
Je genauer die Anforderungen beschrieben sind, desto besser kann Claude Code daraus einen passenden Arduino-Sketch erstellen. Das reduziert nicht nur mögliche Fehler, sondern vermeidet auch unnötige Folgeprompts. Jeder zusätzliche Korrekturschritt kostet Zeit, kann frustrierend sein und verbraucht außerdem weitere Token.
Gerade bei Mikrocontroller-Projekten sind Details besonders wichtig. Es reicht nicht zu schreiben, dass ein Taster verwendet wird. Entscheidend ist auch, wie dieser angeschlossen ist. In meinem Fall hängt der rote Taster an Pin 2 gegen GND und soll mit dem internen Pullup-Widerstand des Arduino verwendet werden. Daraus ergibt sich im Code eine wichtige Besonderheit: Ein gedrückter Taster wird als LOW erkannt.
Auch die gewünschte Spiellogik sollte möglichst vollständig beschrieben werden. Claude Code muss wissen, dass es eine zufällige Wartezeit geben soll, dass während dieser Wartezeit ein Fehlstart erkannt werden muss und dass die Reaktionszeit erst ab dem Einschalten der grünen LED gemessen werden darf.
Je sauberer diese Informationen im Prompt stehen, desto größer ist die Chance, dass der erste generierte Sketch bereits nah an einer funktionierenden Lösung ist.
Der Prompt für Claude Code
Nachdem die Schaltung festgelegt ist, kann ich Claude Code mit der eigentlichen Aufgabe beauftragen. Wichtig ist dabei, dass alle relevanten Informationen direkt im Prompt enthalten sind. Dazu gehören nicht nur die gewünschten Funktionen des Spiels, sondern auch die konkrete Pinbelegung und die Art, wie der Taster angeschlossen ist.
Für den ersten Versuch verwende ich folgenden Prompt:
Erstelle einen Arduino-Sketch für einen Arduino UNO R3. Das Projekt ist ein Reaktionsspiel: - grüne LED am digitalen Pin 6 - roter Taster am digitalen Pin 2 gegen GND - der Taster soll mit internem Pullup verwendet werden - optionaler Piezo-Buzzer am digitalen Pin 9 - nach dem Start soll eine zufällige Wartezeit zwischen 2 und 6 Sekunden ablaufen - während der Wartezeit darf der Nutzer den Taster nicht drücken - wenn der Taster zu früh gedrückt wird, soll ein Fehlstart erkannt und im seriellen Monitor ausgegeben werden - nach der Wartezeit leuchtet die grüne LED - ab diesem Moment wird die Reaktionszeit gemessen - wenn der Nutzer den Taster drückt, soll die Reaktionszeit in Millisekunden im seriellen Monitor ausgegeben werden - danach startet eine neue Runde Bitte erstelle den vollständigen Arduino-Code und erkläre kurz, wie er funktioniert.
Mit diesem Prompt bekommt Claude Code alle wichtigen Informationen auf einmal: das verwendete Board, die angeschlossenen Bauteile, die digitale Pinbelegung, die Pullup-Logik des Tasters und den gewünschten Ablauf des Spiels.
Der Begriff „digitaler Pin“ ist hier bewusst gewählt. Der Arduino UNO R3 besitzt neben den digitalen Pins auch analoge Eingänge. Gerade für Einsteiger ist es daher hilfreich, die verwendeten Anschlüsse möglichst eindeutig zu benennen.
Besonders wichtig ist außerdem der Hinweis, dass der Taster gegen GND geschaltet ist und mit INPUT_PULLUP verwendet werden soll. Dadurch muss der Sketch später einen Tastendruck als LOW erkennen. Genau solche Details entscheiden bei Mikrocontroller-Projekten oft darüber, ob der generierte Code direkt funktioniert oder erst nachgebessert werden muss.

Blick auf den erzeugten Code
Quellcode – reaction_game.ino
const int LED_PIN = 6;
const int BUTTON_PIN = 2;
const int BUZZER_PIN = 9;
const unsigned long ROUND_PAUSE_MS = 1500;
void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT);
Serial.begin(9600);
randomSeed(analogRead(A0)); // unbenutzter Analogpin liefert Rauschen als Seed
Serial.println("Reaktionsspiel gestartet!");
}
void loop() {
playRound();
}
void playRound() {
Serial.println("Naechste Runde: warten, nicht druecken...");
digitalWrite(LED_PIN, LOW);
noTone(BUZZER_PIN);
unsigned long waitTime = random(2000, 6001); // 2-6 s
unsigned long waitStart = millis();
while (millis() - waitStart < waitTime) {
if (digitalRead(BUTTON_PIN) == LOW) {
handleFalseStart();
return; // Runde abbrechen, naechste Runde beginnt sofort neu
}
}
// Startsignal
digitalWrite(LED_PIN, HIGH);
tone(BUZZER_PIN, 1000, 100);
unsigned long reactionStart = millis();
while (digitalRead(BUTTON_PIN) == HIGH) {
// auf Tastendruck warten
}
unsigned long reactionTime = millis() - reactionStart;
digitalWrite(LED_PIN, LOW);
Serial.print("Reaktionszeit: ");
Serial.print(reactionTime);
Serial.println(" ms");
waitForRelease();
delay(ROUND_PAUSE_MS);
}
void handleFalseStart() {
Serial.println("Fehlstart! Zu frueh gedrueckt.");
tone(BUZZER_PIN, 300, 200);
waitForRelease();
}
void waitForRelease() {
// verhindert, dass ein gehaltener Taster sofort die naechste Runde ausloest
while (digitalRead(BUTTON_PIN) == LOW) {
delay(10);
}
delay(50); // Entprellung
}
Der von Claude Code erzeugte Sketch ist grundsätzlich sauber aufgebaut. Die Pins für LED, Taster und Buzzer werden am Anfang als Konstanten definiert:
const int LED_PIN = 6; const int BUTTON_PIN = 2; const int BUZZER_PIN = 9;
Danach werden die Pins im setup() entsprechend eingerichtet. Besonders wichtig ist dabei der Taster:
pinMode(BUTTON_PIN, INPUT_PULLUP);
Damit wird der interne Pull-up-Widerstand des Arduino aktiviert. Der Taster muss also zwischen dem digitalen Pin D2 und GND angeschlossen werden. Im Ruhezustand liest der Arduino dadurch HIGH, beim Drücken des Tasters LOW.
Der Ablauf des Spiels ist ebenfalls gut nachvollziehbar: Zuerst wartet der Arduino eine zufällige Zeit zwischen zwei und sechs Sekunden. Wird der Taster in dieser Wartezeit zu früh gedrückt, erkennt der Sketch einen Fehlstart. Erst nach Ablauf der Wartezeit wird das Startsignal über LED und Buzzer ausgegeben. Anschließend misst der Arduino die Zeit bis zum Tastendruck und gibt die Reaktionszeit im seriellen Monitor aus.
Für ein erstes Reaktionsspiel ist der Code damit gut geeignet. Er ist verständlich, übersichtlich und erfüllt die wichtigsten Anforderungen: zufällige Wartezeit, Fehlstart-Erkennung, Startsignal und Ausgabe der Reaktionszeit.
Warum der Taster an D2 angeschlossen ist
Der Taster ist in meinem Aufbau bewusst am digitalen Pin D2 des Arduino UNO R3 angeschlossen. Das ist nicht zufällig gewählt, denn D2 gehört beim UNO R3 zu den Pins, die externe Interrupts unterstützen. Neben D2 ist auch D3 ein solcher Interrupt-Pin.
Im von Claude Code erzeugten Sketch wird diese Möglichkeit allerdings noch nicht genutzt. Der Taster wird klassisch mit digitalRead() innerhalb einer while-Schleife abgefragt:
while (digitalRead(BUTTON_PIN) == HIGH) {
// auf Tastendruck warten
}
Für dieses einfache Reaktionsspiel ist das vollkommen ausreichend und besonders für Einsteiger gut nachvollziehbar. Der Arduino wartet an dieser Stelle so lange, bis der Taster gedrückt wird. Danach wird die Reaktionszeit berechnet und im seriellen Monitor ausgegeben.
Technisch gesehen verschenkt der Code hier aber eine interessante Möglichkeit. Da der Taster an D2 angeschlossen ist, könnte der Tastendruck auch über einen Interrupt erkannt werden. Dadurch müsste der Arduino nicht aktiv in einer Schleife auf den Tastendruck warten, sondern könnte währenddessen andere Aufgaben erledigen.
Eine fortgeschrittene Variante könnte beispielsweise mit attachInterrupt() arbeiten:
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonPressedISR, FALLING);
Da der Taster im Sketch mit INPUT_PULLUP verwendet wird, liegt der Eingang im Ruhezustand auf HIGH. Beim Drücken wird der Pin mit GND verbunden und wechselt auf LOW. Deshalb wäre hier FALLING der passende Interrupt-Modus.
Für die erste Version des Spiels ist die blockierende Abfrage also kein Fehler, sondern eine einfache und verständliche Lösung. Gleichzeitig zeigt dieser Punkt sehr gut, wo man den Code später weiterentwickeln könnte. Claude Code liefert eine funktionierende Grundlage, aber die technische Einordnung und Optimierung bleibt weiterhin Aufgabe des Entwicklers.
Erweiterung: OLED-Display für die Reaktionszeit
Nachdem das Reaktionsspiel mit LED, Taster und Buzzer grundsätzlich funktioniert, erweitere ich die Schaltung im nächsten Schritt um ein OLED-Display. Dadurch wird die Reaktionszeit nicht mehr nur im seriellen Monitor ausgegeben, sondern direkt am Projekt angezeigt.
Verwendet wird ein 1,3-Zoll-OLED-Display mit SH1106-Treiberchip, welches per I2C angeschlossen ist. Beim Arduino UNO R3 werden dafür die Pins A4 für SDA und A5 für SCL verwendet.
Die neue Aufgabe für Claude Code lautet:
Ich habe die Schaltung um ein OLED-Display erweitert. Dieses ist via I2C angeschlossen und hat die Auflösung von 1,3". Die Ansteuerung erfolgt via SH1106 Treiberchip. Erweitere mir den bestehenden Code um die Funktion, dass die aktuellen Millisekunden auf dem Display angezeigt werden und bei Drücken des Tasters das Ergebnis dort angezeigt wird. Nach 3 Sekunden läuft ein Timer von 5 Sekunden herunter bis die neue Runde startet. Der Timer soll ebenso angezeigt werden.
Claude Code hat daraufhin den bestehenden Sketch erweitert und die Bibliotheken Wire.h, Adafruit_GFX.h und Adafruit_SH110X.h eingebunden. Außerdem wurde eine Displayausgabe für die laufende Reaktionszeit, das Endergebnis und den Countdown bis zur nächsten Runde ergänzt.
Der Ansatz war grundsätzlich richtig. Der erzeugte Code ließ sich auch kompilieren, jedoch blieb das OLED-Display in meinem ersten Test dunkel. Auf dem Display wurde also nichts angezeigt.
Fehleranalyse: OLED separat testen
An dieser Stelle zeigt sich sehr gut, warum KI-generierter Code immer praktisch geprüft werden muss. Statt direkt an der Schaltung oder am gesamten Sketch zu zweifeln, habe ich zunächst ein kleines Testprogramm in der Arduino IDE erstellt.
Damit wollte ich prüfen, ob das OLED-Display grundsätzlich funktioniert, ob die I2C-Adresse stimmt und ob die verwendete SH110X-Bibliothek korrekt arbeitet.
Der einfache Testsketch sah so aus:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
delay(250);
display.begin(SCREEN_ADDRESS, true);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 20);
display.println("OLED OK");
display.display();
delay(2000);
}
void loop() {
}
Nach dem Upload erschien auf dem OLED-Display die Ausgabe „OLED OK“. Damit war klar: Das Display selbst, die Verkabelung, die I2C-Adresse 0x3C und die Bibliothek funktionieren.
Das Problem lag also nicht an der Hardware, sondern an der Art, wie Claude Code die Display-Initialisierung im erweiterten Sketch umgesetzt hatte.
Claude Code mit dem funktionierenden Beispiel korrigieren lassen
Im nächsten Schritt habe ich Claude Code nicht einfach allgemein geschrieben, dass das Display nicht funktioniert. Stattdessen habe ich dem Werkzeug den funktionierenden Minimaltest als Referenz gegeben.
Das ist ein wichtiger Punkt: Je konkreter die Rückmeldung ist, desto besser kann Claude Code den Fehler eingrenzen.
Der Korrektur-Prompt lautete sinngemäß:
Das OLED-Display funktioniert grundsätzlich. Dieser Minimaltest zeigt korrekt "OLED OK" auf dem Display an. Bitte passe den bestehenden Reaktionsspiel-Sketch so an, dass exakt diese funktionierende OLED-Initialisierung verwendet wird. Wichtig: - Verwende die gleiche Display-Deklaration: Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); - Verwende im setup(): delay(250); display.begin(SCREEN_ADDRESS, true); display.clearDisplay(); - Zeige direkt nach dem Start kurz "OLED OK" an. - Entferne die problematische if-Abfrage um display.begin(). - Behalte die bestehende Logik mit LED an Pin 6, Taster an Pin 2, Buzzer an Pin 9 und Reaktionszeitmessung bei. - Die Reaktionszeit soll während der Messung live auf dem OLED angezeigt werden. - Nach Tastendruck soll das Ergebnis 3 Sekunden angezeigt werden. - Danach soll ein 5-Sekunden-Countdown bis zur nächsten Runde auf dem OLED angezeigt werden.
Nach dieser Korrektur hat Claude Code den Sketch angepasst. Anschließend funktionierte das Programm wie gewünscht: Während der Reaktionsphase wird die Zeit auf dem OLED angezeigt, nach dem Tastendruck erscheint die gemessene Reaktionszeit und danach läuft ein Countdown bis zur nächsten Runde herunter.
Erkenntnis aus diesem Schritt
Dieser Schritt ist für mich einer der spannendsten Punkte im Projekt. Claude Code hat die Erweiterung um das OLED-Display grundsätzlich verstanden und den Code in die richtige Richtung erweitert. Trotzdem funktionierte der erste erzeugte Sketch in der Praxis nicht direkt.
Erst durch den eigenen Minimaltest konnte ich die Fehlerquelle eingrenzen. Danach konnte Claude Code mit einer konkreten Rückmeldung und einem funktionierenden Referenzbeispiel den bestehenden Sketch erfolgreich korrigieren.
Genau hier zeigt sich der eigentliche Nutzen von Claude Code im Entwicklungsalltag: Das Werkzeug kann Code erzeugen, erweitern und anpassen. Die praktische Prüfung auf echter Hardware bleibt aber weiterhin meine Aufgabe. Besonders bei Mikrocontroller-Projekten reicht es nicht, dass ein Sketch kompiliert. Er muss auch mit der realen Schaltung, dem verwendeten Display und der eingesetzten Bibliothek funktionieren.
Fazit
Der Praxistest zeigt: Claude Code kann bei Arduino-Projekten sehr gut unterstützen, wenn die Aufgabe und die Hardware sauber beschrieben werden. Der erste Sketch für das Reaktionsspiel mit LED, Taster, Buzzer und serieller Ausgabe war bereits eine brauchbare Grundlage.
Spannend wurde es bei der Erweiterung um das OLED-Display. Der von Claude Code erzeugte Code kompilierte zwar, funktionierte aber nicht direkt auf der echten Hardware. Erst ein eigener Minimaltest zeigte, dass Display, Verkabelung und Bibliothek korrekt waren. Mit diesem funktionierenden Beispiel konnte Claude Code den Sketch anschließend erfolgreich korrigieren.
Die wichtigste Erkenntnis: Claude Code kann Code erzeugen, erweitern und verbessern, ersetzt aber nicht den Test auf realer Hardware. Gerade bei Mikrocontroller-Projekten bleiben Schaltung, Pinbelegung, Bibliotheken und praktische Kontrolle entscheidend.
Für mich ist das Reaktionsspiel ein gelungenes Beispiel dafür, wie Claude Code im Maker-Bereich eingesetzt werden kann: nicht als Ersatz für eigenes Verständnis, sondern als Werkzeug, das die Entwicklung beschleunigen und beim Nachbessern unterstützen kann.
Letzte Aktualisierung am: 09. Juli 2026
