#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
const int PIN_RED_LED = 19;
const int PIN_GREEN_LED = 18;
const int PIN_START = 4;
const int PIN_SPRZEGLO = 5;
enum State {
IDLE,
PREPARING,
WAIT_FOR_SPRZEGLO_DOWN,
WAITING_FOR_GREEN,
REACTION_TEST,
EARLY_RELEASE,
SHOW_RESULT
};
State state = IDLE;
unsigned long t0, t1, reactionTime, rndGreen;
// Pomocnicze napisy
const char msgIdle[] PROGMEM = "---GOOMOO#312---";
const char msgPressStart[] PROGMEM = "Press START";
const char msgPrep1[] PROGMEM = "Przygotuj sie...";
const char msgPrep2[] PROGMEM = "Wcisnij sprzeglo";
const char msgHold[] PROGMEM = "Zwolnij sprzeglo";
const char msgEarly1[] PROGMEM = "Za wczesnie";
const char msgEarly2[] PROGMEM = "TASMA!!!";
const char msgResult1[] PROGMEM = "Czas reakcji:";
void setup() {
pinMode(PIN_RED_LED, OUTPUT);
pinMode(PIN_GREEN_LED, OUTPUT);
pinMode(PIN_START, INPUT_PULLUP);
pinMode(PIN_SPRZEGLO, INPUT_PULLUP);
lcd.init();
lcd.backlight();
showIdleScreen();
randomSeed(analogRead(0));
}
void loop() {
bool start = digitalRead(PIN_START) == LOW;
bool sprzeg = digitalRead(PIN_SPRZEGLO) == LOW;
switch (state) {
case IDLE:
if (start) {
digitalWrite(PIN_RED_LED, HIGH);
digitalWrite(PIN_GREEN_LED, LOW);
lcd.clear();
lcd.setCursor(0, 0); lcd.print(msgPrep1);
lcd.setCursor(0, 1); lcd.print(msgPrep2);
state = WAIT_FOR_SPRZEGLO_DOWN;
}
break;
case WAIT_FOR_SPRZEGLO_DOWN:
if (sprzeg) { // sprzęgło wciśnięte
t0 = millis();
lcd.clear();
lcd.setCursor(0, 0); lcd.print(msgHold);
state = PREPARING;
}
break;
case PREPARING:
if (millis() - t0 >= 3000) {
if (!sprzeg) { // puścił przed końcem 3 s
state = EARLY_RELEASE;
break;
}
digitalWrite(PIN_RED_LED, LOW);
digitalWrite(PIN_GREEN_LED, HIGH);
rndGreen = random(1000, 7001);
t1 = millis() + rndGreen;
state = WAITING_FOR_GREEN;
} else if (!sprzeg) { // puścił w trakcie 3 s
state = EARLY_RELEASE;
}
break;
case WAITING_FOR_GREEN:
if (!sprzeg) { // puścił zbyt wcześnie
state = EARLY_RELEASE;
break;
}
if (millis() >= t1) { // czas na pomiar reakcji
digitalWrite(PIN_GREEN_LED, LOW);
t0 = millis();
state = REACTION_TEST;
}
break;
case REACTION_TEST:
if (!sprzeg) { // puścił sprzęgło
reactionTime = millis() - t0;
lcd.clear();
lcd.setCursor(0, 0); lcd.print(msgResult1);
lcd.setCursor(0, 1); lcd.print(String(reactionTime) + " ms");
state = SHOW_RESULT;
}
break;
case EARLY_RELEASE:
digitalWrite(PIN_RED_LED, LOW);
digitalWrite(PIN_GREEN_LED, LOW);
lcd.clear();
lcd.setCursor(0, 0); lcd.print(msgEarly1);
lcd.setCursor(0, 1); lcd.print(msgEarly2);
state = SHOW_RESULT;
break;
case SHOW_RESULT:
if (start) {
showIdleScreen();
state = IDLE;
}
break;
}
}
void showIdleScreen() {
lcd.clear();
lcd.setCursor(0, 0); lcd.print(msgIdle);
lcd.setCursor(0, 1); lcd.print(msgPressStart);
}