Reaktionsspiel mit Arduino bauen: LED-Reaktionstester mit Touch-Sensor & OLED-Highscore
Wie schnell bist du wirklich? Eine LED leuchtet nach einer zufälligen Wartezeit auf – und du musst so schnell wie möglich tippen. Der Arduino misst deine Reaktionszeit auf die Millisekunde genau und zeigt sie samt Highscore auf dem OLED. In diesem Tutorial baust du dieses kleine Suchtspiel Schritt für Schritt und lernst dabei die wichtigsten Bausteine guter Arduino-Programme: Zufallszahlen, präzises Timing mit millis(), sauberes Entprellen und eine faire Fehlstart-Erkennung.
Warum ein Reaktionsspiel das perfekte Lernprojekt ist
Ein Reaktionstester sieht simpel aus, steckt aber voller Konzepte, die du in fast jedem größeren Projekt wieder brauchst. Du erzeugst eine zufällige Wartezeit, misst eine Zeitspanne exakt, liest einen Taster sauber ein und gibst das Ergebnis lesbar aus. Genau diese Kette – Ereignis auslösen, Zeit messen, Eingabe erfassen, Ergebnis anzeigen – ist das Rückgrat unzähliger Anwendungen. Und ganz nebenbei hast du am Ende ein Spiel, mit dem du deine Freunde herausfordern kannst.
💡 Das lernst du: Zufallszahlen mit random() richtig initialisieren, Zeit ohne delay() messen, einen kapazitiven Touch-Sensor als prellfreien Auslöser nutzen und Fehlstarts (zu früh getippt!) sauber abfangen.
So funktioniert das Spiel
Der Ablauf ist schnell erklärt: Nach dem Start wartet der Arduino eine zufällige Zeit zwischen zwei und fünf Sekunden. Dann schaltet er die LED ein und startet im selben Moment einen Timer mit millis(). Sobald du den Touch-Sensor berührst, stoppt der Timer – die Differenz ist deine Reaktionszeit in Millisekunden. Tippst du schon bevor die LED leuchtet, erkennt der Arduino den Fehlstart und zeigt eine Warnung statt einer Zeit. Der beste Wert wird als Highscore gespeichert und auf dem OLED angezeigt.
ℹ️ Zum Vergleich: Ein durchschnittlicher Mensch reagiert auf ein optisches Signal in etwa 200–250 ms. Alles unter 180 ms ist richtig schnell. Mit deinem selbstgebauten Tester findest du es genau heraus.
Das brauchst du
Warum ein Touch-Sensor statt eines Tasters? Der TTP223 gibt ein sauberes digitales HIGH-Signal aus und prellt nicht mechanisch – ideal, wenn es auf Millisekunden ankommt. Du kannst aber genauso einen Taster verwenden, dann kümmert sich das Entprellen im Code um saubere Signale.
1Verkabelung
Die LED bekommt ihren 220-Ω-Vorwiderstand, der Touch-Sensor eine Signalleitung, und das OLED teilt sich den I2C-Bus.
| Bauteil / Pin | Arduino UNO | Hinweis |
|---|---|---|
| LED Anode (+) | D9 über 220 Ω | langes Bein |
| LED Kathode (−) | GND | kurzes Bein |
| TTP223 SIG | D2 | Signalausgang |
| TTP223 VCC / GND | 5V / GND | Versorgung |
| OLED SDA / SCL | A4 / A5 | I2C-Bus |
| OLED VCC / GND | 5V / GND | Versorgung |
ℹ️ Warum der 220-Ω-Widerstand? Eine LED direkt an einen Pin zu hängen zerstört sie – der Vorwiderstand begrenzt den Strom. Wie man den passenden Wert berechnet, steht ausführlich im Tutorial zum LED-Vorwiderstand.
2Zufallszahlen richtig erzeugen
Damit die Wartezeit jedes Mal anders ist, brauchst du echten Zufall. Ein häufiger Anfängerfehler: random() ohne randomSeed() aufzurufen – dann kommt nach jedem Reset dieselbe Zahlenfolge. Der Trick ist, den Zufallsgenerator mit dem Rauschen eines offenen Analogpins zu füttern:
const int LED = 9;
void setup() {
Serial.begin(115200);
pinMode(LED, OUTPUT);
// A0 haengt frei in der Luft -> zufaelliges Rauschen als Startwert
randomSeed(analogRead(A0));
}
void loop() {
long wartezeit = random(2000, 5000); // 2 bis 5 Sekunden
Serial.print("Warte "); Serial.print(wartezeit); Serial.println(" ms");
delay(wartezeit);
digitalWrite(LED, HIGH);
delay(500);
digitalWrite(LED, LOW);
delay(1000);
}
💡 Warum funktioniert das? Ein nicht angeschlossener Analogeingang fängt elektrisches Rauschen aus der Umgebung ein. Dieser praktisch unvorhersehbare Wert ist ein perfekter Startwert (Seed) für den Zufallsgenerator – so ist jede Runde anders.
3Reaktionszeit messen mit millis()
Jetzt der Kern des Spiels. Wir merken uns mit millis() den Moment, in dem die LED angeht, und die Differenz zum Tippen ist die Reaktionszeit. millis() liefert die Millisekunden seit dem Start – ideal für Zeitmessungen, ohne das Programm mit delay() zu blockieren.
const int LED = 9;
const int TOUCH = 2;
void setup() {
Serial.begin(115200);
pinMode(LED, OUTPUT);
pinMode(TOUCH, INPUT);
randomSeed(analogRead(A0));
}
void loop() {
Serial.println("Achtung...");
digitalWrite(LED, LOW);
delay(random(2000, 5000));
digitalWrite(LED, HIGH);
unsigned long start = millis(); // Timer startet
// warten bis der Sensor beruehrt wird
while (digitalRead(TOUCH) == LOW) {
// nichts tun, nur warten
}
unsigned long reaktion = millis() - start; // Differenz = Reaktionszeit
digitalWrite(LED, LOW);
Serial.print("Deine Zeit: ");
Serial.print(reaktion);
Serial.println(" ms");
delay(2000);
}
ℹ️ Warum unsigned long? millis() liefert einen sehr großen Zahlenwert (er zählt bis über 4 Milliarden). Nur unsigned long ist groß genug – ein normales int würde überlaufen und falsche Zeiten liefern. Mehr dazu im millis()-Tutorial.
4Fehlstart erkennen & Highscore auf dem OLED
Ein faires Spiel muss Schummeln verhindern: Wer tippt, bevor die LED leuchtet, bekommt einen Fehlstart statt einer Traumzeit. Dazu prüfen wir den Sensor schon während der Wartephase. Zum Schluss bringen wir alles aufs OLED-Display und merken uns den Bestwert. Installiere dafür die Bibliotheken Adafruit GFX und Adafruit SSD1306.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 display(128, 64, &Wire, -1);
const int LED = 9;
const int TOUCH = 2;
unsigned long highscore = 999999;
void zeige(String zeile1, String zeile2) {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0); display.print("REAKTIONSTEST");
display.setTextSize(2);
display.setCursor(0, 22); display.print(zeile1);
display.setTextSize(1);
display.setCursor(0, 52); display.print(zeile2);
display.display();
}
void setup() {
pinMode(LED, OUTPUT);
pinMode(TOUCH, INPUT);
randomSeed(analogRead(A0));
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
zeige("Bereit?", "Warte auf LED...");
}
void loop() {
digitalWrite(LED, LOW);
zeige("Achtung", "gleich...");
// Wartephase: Fehlstart abfangen
unsigned long ziel = millis() + random(2000, 5000);
while (millis() < ziel) {
if (digitalRead(TOUCH) == HIGH) {
zeige("FEHLSTART!", "Zu frueh getippt");
delay(2000);
return; // Runde neu starten
}
}
digitalWrite(LED, HIGH);
unsigned long start = millis();
while (digitalRead(TOUCH) == LOW) { }
unsigned long reaktion = millis() - start;
digitalWrite(LED, LOW);
if (reaktion < highscore) highscore = reaktion;
zeige(String(reaktion) + " ms", "Best: " + String(highscore) + " ms");
delay(3000);
}
💡 So funktioniert die Fehlstart-Erkennung: Statt stumpf zu warten, prüfen wir in der Wartephase permanent den Sensor. Wird er berührt, bevor die Zeit abgelaufen ist, brechen wir die Runde mit return ab und zeigen den Fehlstart. Niemand kann mehr durch Dauerdrücken schummeln.
Ausbauideen
- Mehrspieler-Duell: Zwei LEDs und zwei Touch-Sensoren – wer zuerst tippt, gewinnt die Runde.
- Highscore dauerhaft speichern: Schreibe den Bestwert ins EEPROM, dann bleibt er auch nach dem Ausschalten erhalten.
- Schwierigkeitsgrade: Verkürze die LED-Leuchtdauer mit jeder Runde – wer zu langsam ist, fliegt raus.
- Menü mit Drehgeber: Mit einem OLED-Menü und Rotary Encoder wählst du zwischen Einzel- und Mehrspielermodus.
Troubleshooting
⚠️ Immer dieselbe Wartezeit nach Reset: Es fehlt randomSeed() oder A0 ist belegt. Nutze einen wirklich freien Analogpin als Seed-Quelle.
⚠️ Reaktionszeit ist immer 0 oder sehr klein: Der Sensor liefert dauerhaft HIGH. Prüfe die Verdrahtung; manche TTP223-Module haben einen Lötjumper für Dauer- oder Impulsmodus.
⚠️ LED leuchtet gar nicht: Anode und Kathode vertauscht oder Vorwiderstand vergessen. Das lange Bein ist der Pluspol.
⚠️ OLED bleibt schwarz: Adresse 0x3C prüfen und ob SDA/SCL an A4/A5 hängen – zur Not mit einem I2C-Scanner.
🚀 Dein Reaktionsspiel-Starterpaket
Alle Bauteile für dieses Projekt im Shop:
- UNO R3 Entwicklungsboard – die Steuerzentrale
- TTP223 Touch-Sensor – der Auslöser
- 3mm LED-Sortiment und Widerstands-Set – Signal & Vorwiderstand
- 1,3 Zoll OLED-Display – Zeit & Highscore
- Breadboard 400 Kontakte und Dupont-Jumperkabel
Fazit
Aus einer LED, einem Touch-Sensor und ein paar Zeilen Code ist ein süchtig machendes Reaktionsspiel geworden. Wichtiger als das Spiel selbst sind die Techniken dahinter: Du weißt jetzt, wie man mit randomSeed() echten Zufall erzeugt, mit millis() Zeiten auf die Millisekunde misst und mit einer cleveren Wartephase sogar Fehlstarts abfängt. Diese Bausteine wirst du in vielen weiteren Projekten wiedersehen.
Jetzt bist du dran: Bau es nach, fordere deine Freunde heraus und erweitere es zum Mehrspieler-Duell. Viel Spaß – und schnelle Finger!