#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Pin Definitions
#define RESET_BUTTON_PIN 5
#define LAST_LAP_BUTTON_PIN 6
#define LINE_A_BUTTON_PIN 2
#define LINE_B_BUTTON_PIN 3
#define LINE_C_BUTTON_PIN 4
#define BUZZER_PIN 7
// LCD Settings
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Variables
unsigned long lapStartTime = 0;
unsigned int lapCounter = 0;
unsigned long lapTimes[3] = {0, 0, 0};
int winnerLane = -1;
unsigned long winnerTime = 0;
bool raceStarted = false;
bool stopTimer = false;
bool lastLapButtonReleased = true;
// Button State Variables
bool resetButtonState = false;
bool lastLapButtonState = false;
bool lineAButtonState = false;
bool lineBButtonState = false;
bool lineCButtonState = false;
void setup() {
// Initialize serial communication
Serial.begin(9600);
// Initialize LCD
lcd.begin(16, 2);
lcd.clear();
// Display boot status on LCD
lcd.setCursor(0, 0);
lcd.print("Race Counter Device");
lcd.setCursor(0, 1);
lcd.print("Ready!");
// Set up button pins as inputs
pinMode(RESET_BUTTON_PIN, INPUT);
pinMode(LAST_LAP_BUTTON_PIN, INPUT);
pinMode(LINE_A_BUTTON_PIN, INPUT);
pinMode(LINE_B_BUTTON_PIN, INPUT);
pinMode(LINE_C_BUTTON_PIN, INPUT);
// Set up buzzer pin as output
pinMode(BUZZER_PIN, OUTPUT);
}
void loop() {
// Update button states
updateButtonStates();
// Check if reset button is pressed
if (resetButtonState) {
resetRace();
// Display reset status on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Race Reset!");
raceStarted = false;
stopTimer = false;
}
// Check if last lap button is pressed and released
if (lastLapButtonState && lastLapButtonReleased) {
if (raceStarted) {
stopTimer = true;
}
lastLapButtonReleased = false;
} else if (!lastLapButtonState) {
lastLapButtonReleased = true;
}
// Check if line buttons are pressed
if ((lineAButtonState || lineBButtonState || lineCButtonState) && !raceStarted) {
startRace();
} else if ((lineAButtonState || lineBButtonState || lineCButtonState) && raceStarted) {
handleLapTrigger();
}
// Check if race finished
if (raceStarted && stopTimer) {
stopRace();
displayWinner();
}
}
void updateButtonStates() {
static bool lastResetButtonState = false;
static bool lastLastLapButtonState = false;
static bool lastLineAButtonState = false;
static bool lastLineBButtonState = false;
static bool lastLineCButtonState = false;
// Update reset button state
bool currentResetButtonState = digitalRead(RESET_BUTTON_PIN);
resetButtonState = (currentResetButtonState != lastResetButtonState) && currentResetButtonState;
lastResetButtonState = currentResetButtonState;
// Update last lap button state
bool currentLastLapButtonState = digitalRead(LAST_LAP_BUTTON_PIN);
lastLapButtonState = (currentLastLapButtonState != lastLastLapButtonState) && currentLastLapButtonState;
lastLastLapButtonState = currentLastLapButtonState;
// Update line A button state
bool currentLineAButtonState = digitalRead(LINE_A_BUTTON_PIN);
lineAButtonState = (currentLineAButtonState != lastLineAButtonState) && currentLineAButtonState;
lastLineAButtonState = currentLineAButtonState;
// Update line B button state
bool currentLineBButtonState = digitalRead(LINE_B_BUTTON_PIN);
lineBButtonState = (currentLineBButtonState != lastLineBButtonState) && currentLineBButtonState;
lastLineBButtonState = currentLineBButtonState;
// Update line C button state
bool currentLineCButtonState = digitalRead(LINE_C_BUTTON_PIN);
lineCButtonState = (currentLineCButtonState != lastLineCButtonState) && currentLineCButtonState;
lastLineCButtonState = currentLineCButtonState;
}
void startRace() {
lapStartTime = millis();
lapCounter++;
lapTimes[0] = 0;
lapTimes[1] = 0;
lapTimes[2] = 0;
raceStarted = true;
// Display race start status on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Race Started!");
lcd.setCursor(0, 1);
lcd.print("Lap 1");
}
void handleLapTrigger() {
if (lapCounter > 0) {
unsigned long currentTime = millis() - lapStartTime;
lapTimes[0] = (lineAButtonState || stopTimer) ? currentTime : lapTimes[0];
lapTimes[1] = (lineBButtonState || stopTimer) ? currentTime : lapTimes[1];
lapTimes[2] = (lineCButtonState || stopTimer) ? currentTime : lapTimes[2];
// Increment lap counter
lapCounter++;
// Display lap count on LCD
lcd.setCursor(0, 1);
lcd.print("Lap ");
lcd.print(lapCounter);
}
digitalWrite(BUZZER_PIN, HIGH);
delay(100); // Buzzer beep duration
digitalWrite(BUZZER_PIN, LOW);
}
void stopRace() {
stopTimer = false;
findWinner();
raceStarted = false;
}
void resetRace() {
lapStartTime = 0;
lapCounter = 0;
winnerLane = -1;
for (int i = 0; i < 3; i++) {
lapTimes[i] = 0;
}
lcd.clear();
}
void displayWinner() {
lcd.setCursor(0, 0);
lcd.print("Winner: Lane ");
lcd.print(char('A' + winnerLane));
lcd.setCursor(0, 1);
lcd.print("Time: ");
lcd.print(winnerTime);
lcd.print("ms");
}
void findWinner() {
unsigned long fastestTime = lapTimes[0];
winnerLane = 0;
for (int i = 1; i < 3; i++) {
if (lapTimes[i] < fastestTime) {
fastestTime = lapTimes[i];
winnerLane = i;
}
}
winnerTime = fastestTime;
}