#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
const int greenLEDPin = 8;
const int redLEDPin = 9;
const int buttonPin = 2;
const int speakerPin = 10;
const int resetButtonPin = A1;
unsigned long ledOnTime;
bool waitingForReaction = false;
bool isGreen = false;
unsigned long bestTime = 9999; // High initial value
unsigned long worstTime = 0; // Low initial value
void playHappyTune() {
tone(speakerPin, 523, 200); delay(200); // C5
tone(speakerPin, 659, 200); delay(200); // E5
tone(speakerPin, 784, 300); delay(300); // G5
noTone(speakerPin);
}
void playNewBestTune() {
tone(speakerPin, 784, 200); delay(200); // G5
tone(speakerPin, 880, 200); delay(200); // A5
tone(speakerPin, 988, 300); delay(300); // B5
tone(speakerPin, 1047, 400); delay(400); // C6
noTone(speakerPin);
}
void playSadTune() {
tone(speakerPin, 220, 300); delay(300); // A3
tone(speakerPin, 196, 300); delay(300); // G3
tone(speakerPin, 174, 400); delay(400); // F3
noTone(speakerPin);
}
void setup() {
pinMode(greenLEDPin, OUTPUT);
pinMode(redLEDPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(speakerPin, OUTPUT);
pinMode(resetButtonPin, INPUT_PULLUP); // Reset button uses internal pull-up
lcd.begin(16, 2);
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Reaction Tester");
delay(2000);
lcd.clear();
}
void loop() {
if (digitalRead(resetButtonPin) == LOW) {
bestTime = 9999;
worstTime = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Progress Reset!");
tone(speakerPin, 800, 200); delay(250);
tone(speakerPin, 1000, 200); delay(250);
noTone(speakerPin);
delay(2000);
lcd.clear();
return; // Skip the rest of this loop cycle
}
digitalWrite(greenLEDPin, LOW);
digitalWrite(redLEDPin, LOW);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Wait for signal");
delay(random(2000, 4500));
isGreen = random(0, 2) == 1;
if (isGreen) {
digitalWrite(greenLEDPin, HIGH);
} else {
digitalWrite(redLEDPin, HIGH);
}
ledOnTime = millis();
waitingForReaction = true;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("GO!");
bool redLEDTimeoutHandled = false;
while (waitingForReaction) {
unsigned long currentTime = millis();
if (digitalRead(buttonPin) == LOW) {
waitingForReaction = false;
digitalWrite(greenLEDPin, LOW);
digitalWrite(redLEDPin, LOW);
lcd.clear();
if (isGreen) {
unsigned long reactionTime = currentTime - ledOnTime;
bool isNewBest = reactionTime < bestTime;
if (isNewBest) bestTime = reactionTime;
if (reactionTime > worstTime) worstTime = reactionTime;
lcd.setCursor(0, 0);
lcd.print("You: ");
lcd.print(reactionTime);
lcd.print("ms");
lcd.setCursor(0, 1);
lcd.print("B:");
lcd.print(bestTime);
lcd.print(" W:");
lcd.print(worstTime);
delay (1000);
if (isNewBest) {
playNewBestTune();
} else {
playHappyTune();
}
} else {
lcd.setCursor(0, 0);
lcd.print("Wrong LED!");
playSadTune();
}
delay(2000);
lcd.clear();
}
if (!isGreen && !redLEDTimeoutHandled && (currentTime - ledOnTime >= 3000)) {
waitingForReaction = false;
redLEDTimeoutHandled = true;
digitalWrite(redLEDPin, LOW);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Good job!");
delay(1000);
lcd.clear();
}
}
}