#include <TM1637Display.h>
// ======== ADJUSTABLE PARAMETERS ========
const uint8_t RELAY_PIN = 8; // Pin driving relay (and LED)
const uint8_t VIBE_PIN = 2; // Pin reading vibration sensor
const uint8_t DISPLAY_CLK = 3; // TM1637 CLK pin
const uint8_t DISPLAY_DIO = 4; // TM1637 DIO pin
const bool logicFlagRelay = HIGH; // Relay trigger logic: HIGH = on, LOW = off
const bool logicFlagVibe = LOW; // Vibration sensor logic: HIGH = triggered, LOW = not
const uint16_t FLASH_COUNT = 3; // Number of “get ready” flashes
const uint16_t FLASH_ON_MS = 1000; // Flash on duration (ms)
const uint16_t FLASH_OFF_MS = 1000; // Flash off duration (ms)
const uint16_t RANDOM_MIN_MS = 5000; // Minimum random delay before start (ms)
const uint16_t RANDOM_MAX_MS = 10000; // Maximum random delay before start (ms)
// const uint16_t REACT_TIMEOUT = 5000; // Max wait for vibration (ms)
const uint16_t DISPLAY_TIME = 10000; // How long to show reaction time (ms)
// ======== GLOBAL OBJECTS & VARIABLES ========
TM1637Display display(DISPLAY_CLK, DISPLAY_DIO);
// Forward declarations
void flashReady();
uint32_t waitForTrigger(uint32_t timeout);
void setup() {
Serial.begin(9600);
pinMode(RELAY_PIN, OUTPUT);
pinMode(VIBE_PIN, INPUT_PULLUP);
digitalWrite(RELAY_PIN, !logicFlagRelay); // Ensure relay off at start
display.setBrightness(0x0f); // Max brightness
display.showNumberDec(0, true); // Clear display
randomSeed(analogRead(A0)); // Seed RNG
Serial.println("Start the Game");
}
void loop() {
// 1) “Get ready” flashes
flashReady();
// 2) Random delay before light turns on
uint32_t delayTime = random(RANDOM_MIN_MS, RANDOM_MAX_MS);
Serial.print("Current Random Time:");
Serial.println(delayTime);
unsigned long cTime = millis();
delay(delayTime);
Serial.print("Actual Wait Time:");
Serial.println((millis() - cTime)/1000);
// 3) Turn on LED/relay and start timing
digitalWrite(RELAY_PIN, logicFlagRelay);
// 4) Wait for vibration or timeout
uint32_t reactionTime = waitForTrigger(5000);
// 5) Turn off LED/relay
digitalWrite(RELAY_PIN, !logicFlagRelay);
uint32_t startTime = millis();
// 6) If triggered in time, display reaction; else, just loop
if (reactionTime > 0) {
// Display time in ms on 4‑digit display (clamp to 9999)
display.showNumberDec(reactionTime, true);
fastFlash(); // Fast flash the led
delay(DISPLAY_TIME);
display.showNumberDec(0, true); // Clear
}
delay(3000); // Wait for 3 second before starting again
// Loop back for next round
}
// ======== FUNCTIONS ========
// Flashes the relay/LED FLASH_COUNT times to signal “get ready”
void flashReady() {
Serial.println("Start Flashing to make user ready");
for (uint8_t i = 0; i < FLASH_COUNT; i++) {
digitalWrite(RELAY_PIN, logicFlagRelay);
delay(FLASH_ON_MS);
digitalWrite(RELAY_PIN, !logicFlagRelay);
delay(FLASH_OFF_MS);
}
}
void fastFlash() {
Serial.println("Fast Flash");
for (uint8_t i = 0; i < FLASH_COUNT; i++) {
digitalWrite(RELAY_PIN, logicFlagRelay);
delay(300);
digitalWrite(RELAY_PIN, !logicFlagRelay);
delay(300);
}
}
// Returns reaction time in ms if sensor triggered within timeout, else 0
uint32_t waitForTrigger(uint32_t timeout) {
uint32_t start = millis();
while (millis() - start < timeout) {
bool sensorState = digitalRead(VIBE_PIN);
if (sensorState == logicFlagVibe) {
// Trigger detected
return millis() - start;
}
}
// Timeout, no trigger
return 0;
}