oh boy... you asked.... it is a long one. pt1/2
#include <Wire.h> // Library for I2C communication
#include <LiquidCrystal_I2C.h> // Library for LCD
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4);
int LEDPIN0[] = {9, 7, 8};
int LEDPIN1[] = {12, 10, 11};
const int pinCount = 3;
const int SLOTS = 2;
int LEDGROUP[SLOTS][pinCount] = {{9, 7, 8}, {12, 10, 11}};
#define MINROUNDTIME 4000// Minimum lap time in milliseconds, lap debounce
byte laserPins[] = {2, 3};// Pins for connecting the laser sensors (D2, D3)
byte pinInterrupts[] = {0, 1};// Interrupt-Numbers for these pins
const int BUTTON1 = 5; //toggle switches
const int BUTTON2 = 6;
int BUTTONSTATE1 = 0; // state of buttons for reset routine
int BUTTONSTATE2 = 0;
int Race = 0; // state of button 5 for race/practice mode selction
int Practice = 0; // state of button 6 for race/practice mode selction
int RaceLaps = 1; // number of laps raced is always =>1
extern volatile unsigned long timer0_millis;
volatile long roundStart[] = {0, 0}; // Start of the last round in milliseconds, volatile because of ISR!
unsigned long raceStart = 0; // exact time in millis light turns green
unsigned long raceTime[] = {0, 0}; // end of race in millis
int raceEnd[] = {0, 0}; // counter to define raceTime only once.
long lapTime[] = {0, 0}; //Lap time of the last lap in milliseconds
long lapRecord[] = {20000, 20000}; // Lap time of the fastest lap in milliseconds
int lapNumber[] = {0, 0}; // Lap Counter
void (* resetFunc) (void) = 0; // program reset function
void timing1() // Interrupt (ISR routines)
{
if (millis() - roundStart[0] > MINROUNDTIME)
roundStart[0] = millis();
}
void timing2()
{
if (millis() - roundStart[1] > MINROUNDTIME)
roundStart[1] = millis();
}
void (*isrFunctions[])() = { timing1, timing2 };
void setup() {
lcd.init();
lcd.backlight();
for (int i = 0; i < SLOTS; i++) // Initialize laser sensors and ISR routines
{
pinMode(laserPins[i], INPUT_PULLUP);
attachInterrupt(pinInterrupts[i], isrFunctions[i], HIGH);
}
for (int i = 0; i < pinCount; i++)
{
pinMode(LEDPIN0[i], OUTPUT);
pinMode(LEDPIN1[i], OUTPUT);
}
pinMode(BUTTON1, INPUT);
pinMode(BUTTON2, INPUT);
lcd.setCursor(6, 0);
lcd.print("Suitcase");
lcd.setCursor(1, 1);
lcd.print("Grand Prix Circuit");
lcd.setCursor(1, 3);
lcd.print("Practice Race");
Practice = digitalRead(BUTTON1); // Choose Race Mode
Race = digitalRead(BUTTON2);
while (Practice == 0 && Race == 0)
{
Practice = digitalRead(BUTTON1);
Race = digitalRead(BUTTON2);
}
delay(100);
lcd.clear();
char buffer [21];
Race = 0; // Choose number of laps if in race mode
while (Practice == 0 && Race == 0) // Same initial button condition - practice never uses this
{
lcd.setCursor(6, 0);
lcd.print("Suitcase");
lcd.setCursor(1, 1);
lcd.print("Grand Prix Circuit");
lcd.setCursor(3, 2);
lcd.print("How Many Laps?");
lcd.setCursor(0, 3);
sprintf(buffer, " Laps=%02d Start", RaceLaps);
lcd.print(buffer);
int BUTTONSTATE1 = digitalRead(BUTTON1);
if (BUTTONSTATE1 == HIGH)
{
RaceLaps++;
}
Race = digitalRead(BUTTON2);
}
lcd.clear();
}
void ProcessLapTimes() //Process lap times
{
static long RoundProcessed[] = {0, 0}; // Start of the penultimate round in milliseconds
long curMillis;
curMillis = millis(); // Note the current status of the millis () function
for (int i = 0; i < SLOTS; i++) // Check all slots for changes in the round start time
{
if (RoundProcessed[i] != roundStart[i]) // New lap since the last loop run
{
lapNumber[i]++; // Lap counter plus 1
lapTime[i] = roundStart[i] - RoundProcessed[i]; // Determine lap time
if (lapTime[i] < lapRecord[i]) // Determine if it was the fastest lap
lapRecord[i] = lapTime[i];
if (lapRecord[i] == lapTime[i]) // if new lapRecord[i] flash red LED
digitalWrite(LEDGROUP[i][1], HIGH);
if (lapTime[i] < lapRecord[!i])
digitalWrite(LEDGROUP[i][2], HIGH);
RoundProcessed[i] = roundStart[i]; // mark this lap time as processed
}
}
}
void ProcessRaceTimes() // Racing Lap processing
{
static long RoundProcessed[] = {0, 0}; // Start of the penultimate round in milliseconds
long curMillis;
curMillis = millis(); // Note the current status of the millis () function
for (int i = 0; i < SLOTS; i++) // Check all slots for changes in the round start time
{
if (RoundProcessed[i] != roundStart[i]) // New lap since the last loop run
{
lapNumber[i]++; // Lap counter plus 1
lapTime[i] = roundStart[i] - RoundProcessed[i]; // Determine lap time
if (lapTime[i] < lapRecord[i]) // Determine if it was the fastest lap
lapRecord[i] = lapTime[i];
if (lapRecord[i] == lapTime[i] && lapTime[i] < lapRecord[!i]) // if fastest race lap flash red LED
digitalWrite(LEDGROUP[i][2], HIGH);
RoundProcessed[i] = roundStart[i]; // mark this lap time as processed
}
}
}
void ShowRaceTimes() // Race Display
{
static long lastUpdate;
long thisLap, thisRecord;
char fullline[20];
char lcdline[10];
int ltime[4];
if (millis() / 500 == lastUpdate) return; // Update display only every 500 ms
lastUpdate = millis() / 500;
snprintf(fullline, sizeof(fullline), "Grand Prix %2d Laps", RaceLaps);
lcd.setCursor(1, 0);
lcd.print(fullline);
for (int i = 0; i < SLOTS; i++)
{
// Lap time and fastest lap time in hundredths of a lap
thisLap = (lapTime[i] + 5) / 10; // lap time
thisRecord = (lapRecord[i] + 5) / 10; // lap time record
ltime[0] = thisLap / 100; // whole seconds
ltime[1] = thisLap % 100; // hundredths of second
ltime[2] = thisRecord / 100; // whole seconds
ltime[3] = thisRecord % 100; // hundredths of second
snprintf(lcdline, sizeof(lcdline), "lap%2d/%2d", lapNumber[i], RaceLaps);
if (i == 0)
{
lcd.setCursor(1, 1);
}
else
{
lcd.setCursor(11, 1);
}
lcd.print(lcdline);
snprintf(lcdline, sizeof(lcdline), "%3d.%02d ", ltime[0], ltime[1]);
if (i == 0)
{
lcd.setCursor(0, 2);
}
else
{
lcd.setCursor(10, 2);
}
lcd.print(lcdline);
snprintf(lcdline, sizeof(lcdline), "rec %2d.%02d", ltime[2], ltime[3]);
if (i == 0)
{
lcd.setCursor(0, 3);
}
else
{
lcd.setCursor(10, 3);
}
lcd.print(lcdline);
}
}
void ShowRaceResults()
{
static long lastUpdate;
long avgLap, thisRecord, totalTime;
char lcdline[10];
int ltime[6];
if (millis() / 500 == lastUpdate) return; // Update display only every 500 ms
lastUpdate = millis() / 500;
lcd.setCursor(1, 0);
lcd.print("Grand Prix Results");
for (int i = 0; i < SLOTS; i++)
{
// total time, avg time and fastest lap in hundredths of a lap
avgLap = ((raceTime[i] / RaceLaps) + 5) / 10; // avg lap time
thisRecord = (lapRecord[i] + 5) / 10; // lap time record
totalTime = (raceTime[i] + 5) / 10;
ltime[0] = avgLap / 100; // whole seconds
ltime[1] = avgLap % 100; // hundredths of second
ltime[2] = thisRecord / 100; // whole seconds
ltime[3] = thisRecord % 100; // hundredths of second
ltime[4] = totalTime / 100;
ltime[5] = totalTime % 100;
snprintf(lcdline, sizeof(lcdline), "tot %2d.%02d", ltime[4], ltime[5]);
if (i == 0)
{
lcd.setCursor(0, 1);
}
else
{
lcd.setCursor(10, 1);
}
lcd.print(lcdline);
snprintf(lcdline, sizeof(lcdline), "avg %2d.%02d", ltime[0], ltime[1]);
if (i == 0)
{
lcd.setCursor(0, 2);
}
else
{
lcd.setCursor(10, 2);
}
lcd.print(lcdline);
snprintf(lcdline, sizeof(lcdline), "rec %2d.%02d", ltime[2], ltime[3]);
if (i == 0)
{
lcd.setCursor(0, 3);
}
else
{
lcd.setCursor(10, 3);
}
lcd.print(lcdline);
}
}