I’ve changed around the interrupts, enabling and disabling them, ala DK’s advice. So A only mode shouldn’t record B hits and show goofy things and A vs B should work as hoped for. The first version is A only and the second is A vs B, with the only difference btw the 2 being the initialization of TimerMode. But because I’ve messed with the interrupts you should put each through it’s paces to make sure it all still works as it used to. In A only check that A hits are displayed and the review displays are what you’ve seen before. Also check that B hits do nothing at all now. Check the max number of hits stop the timer and the stop button does as well. I hope I remembered correctly that you’re using pin 2 connected to the shock sensor as A only mode is tied to using that pin (it can be easily changed). For AvsB give it your best beating, I do want to see some simultaneous A and B hits at some point (tie sensor to both pins 2 and 3). How the Arduino handles simultaneous (or nearly so) hits will determine if the interrupt setup is fine as it is or needs changing. Best if we find that out now.
I re-upped the max hits back to 20 as well. I’d put more “clean up” fixes in as well but it’s best not to taunt the coding gods too much.
TimerMode = 0, A only mode
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 9, 8);
// set pin numbers
const int StartPin = 7; // the number of the Start pushbutton pin
const int TargetAPin = 2; // the number of the A targets input pin
const int TargetBPin = 3; // the number of the B targets input pin
const int BuzzerPin = 10; // the number of the buzzer output pin
const int LEDPin = 13; // the number of the LED output pin
const int ScrollPin = 6; // the number of the scroll button input pin
//const int ButtonInPin = A0; // the pin used for the analog buttons
// initialize the constants
const unsigned long MaxTime = 30000; // the max time the timer can run for = 30 secs
const unsigned long WaitTime = 2000; // wait time btw start and timer running = 2 secs plus debounce
const unsigned long DB_delay = 1000; // set a debounce wait time of 1000 msecs
const unsigned long BuzzTime5 = 500; // set the on time for the buzzer, 500 msecs
const unsigned long BuzzTime2 = 200; // set the on time for the buzzer, 200 msecs
const unsigned long BuzzTime10 = 1000; // set the on time for the buzzer, 1000 msecs
const unsigned int FreqHi = 2000; // High frequency of buzzer tone
const unsigned int FreqLo = 1000; // Low frequency of buzzer tone
const byte MaxHits = 20; // Maximum number if hits allowed
// initialize global variables
volatile byte TimerState = 0; // variable for state of timer, running or not running
volatile byte AupDtFlag = 0; // variable indication an A hit has occurred
volatile byte BupDtFlag = 0; // variable indication a B hit has occurred
byte DisplayIndex = 0; // variable for controlling what's displayed
unsigned long StartTime = 0; // variable to hold the start time
unsigned long BuzzTime = 500; // variable to hold the buzzer on time
unsigned int Freq = 2000; // variable for high or low buzzer tone
volatile byte A_count = 0; // variable to hold the number of A hits
volatile byte B_count = 0; // variable to hold the number of B hits
volatile long A_Times[MaxHits]; // array to hold up to MaxHits hit times for target A
volatile long B_Times[MaxHits]; // array to hold up to MaxHits hit times for target B
unsigned long A_splits[MaxHits];
unsigned long B_splits[MaxHits];
long AB_splits[MaxHits];
unsigned long LastTime = 0; // initialize last LCD display time to zero for 1st pass
float A_Hit_Factor = 0;
float B_Hit_Factor = 0;
byte S1 = 0; // Switch 1 init to zero
byte S2 = 0; // Switch 2 init to zero
unsigned int diMin = 0; // Display index mininmim
unsigned int diMax = 99; // Display index maximum
unsigned int TimerMode = 0; // initialize the mode to be single shooter
volatile int secs = 0;
volatile int frac = 0;
void setup()
{
// set up the LCD's number of columns and rows:
lcd.begin(20, 4);
lcd.clear();
lcd.print(" Shot Timer 1 ");
lcd.setCursor(0, 1);
lcd.print(" Initializing ");
delay(3000);
// initialize output pins
pinMode(BuzzerPin, OUTPUT);
pinMode(LEDPin, OUTPUT);
digitalWrite(BuzzerPin, LOW);
digitalWrite(LEDPin, LOW);
// initialize the input pins with internal pullups
pinMode(StartPin, INPUT);
// pinMode(UpPin, INPUT);
//pinMode(DownPin, INPUT);
pinMode(TargetAPin, INPUT);
pinMode(TargetBPin, INPUT);
digitalWrite(StartPin, HIGH);
//digitalWrite(UpPin, HIGH);
//digitalWrite(DownPin, HIGH);
digitalWrite(TargetAPin, HIGH);
digitalWrite(TargetBPin, HIGH);
// for now use pin 6 as button input
pinMode(ScrollPin, INPUT);
digitalWrite(ScrollPin, HIGH);
// opens serial port, sets data rate to 9600 bps
Serial.begin(9600);
// setup ext pins as interrupts
//attachInterrupt(0, ISR_A, FALLING);
//attachInterrupt(1, ISR_B, FALLING);
lcd.setCursor(0, 1);
lcd.print(" Ready ");
}
void loop()
{
if (TimerState) // is timer running
{
// timer is running
// send data to display if there have been any hits
if (AupDtFlag == 1 || BupDtFlag == 1)
{
CalcTimes();
FormatData();
}
// timer is running so now check for any stop conditions
if ((digitalRead(StartPin) == LOW) || ((millis() - StartTime) > MaxTime) || A_count >= MaxHits || B_count >= MaxHits)
{
// stop the timer change the display
StopTimer();
tone(BuzzerPin, FreqLo, BuzzTime10);
// update display just in case last msec hit came in
if (AupDtFlag == 1 || BupDtFlag == 1)
{
CalcTimes();
FormatData();
}
// just for the moment send times to PC for debug
SendTimes();
// delay enough to debounce stop button
delay(DB_delay);
// Change to review-stopped state display based on timer mode
switch (TimerMode)
{
case 1:
//this is for A vs B shooter mode
diMin = 6;
diMax = int(max(A_count,B_count)/4) + diMin - 1; // find how many whole screens
if (max(A_count,B_count) % 4)
{
diMax++ ; // add another screen if partial exists
}
DisplayIndex = diMax; // display will show list of hit times
break;
default:
// the default = single A shooter mode
diMin = 2;
diMax = int(A_count/8) + diMin - 1; // find how many whole screens
if (A_count % 8)
{
diMax++ ; // add another screen if partial exists
}
DisplayIndex = diMax; // display will show list of hit times
}
}
}
else
{
// timer is stopped look for start button or review button pushes
// check for scroll button pushes, change display state as reqd
if (digitalRead(ScrollPin) == LOW)
{
DisplayIndex++; // increment DisplayIndex upon push
if (DisplayIndex > diMax)
{
DisplayIndex = diMin; // wrap around of scrolling action
}
// change to new display
FormatData();
delay(DB_delay);
}
// check to see if start button has been pushed
if (digitalRead(StartPin) == LOW)
{
// start button pushed
// Do the following debug code only to get system running
// This will send message to PC to show button was pushed
Serial.println("Timer is running");
// turn on the LED to show timer is running
digitalWrite(LEDPin, HIGH);
// clear all the prior runs data, reset the display
ClearData();
DisplayIndex = 0;
FormatData();
// delay the Wait Time from start button push
// this delay is for debounce purposes and should stay
delay(DB_delay);
// this delay will change to random later on
delay(WaitTime);
// enable the interrupts based on mode here ATM
// this will change when config mode is added ?
switch (TimerMode)
{
case 1:
//this is for A vs B shooter mode
attachInterrupt(0, ISR_A, FALLING);
attachInterrupt(1, ISR_B, FALLING);
DisplayIndex = 5; // display will show count and time of hits
break;
default:
// the default = single A shooter mode
attachInterrupt(0, ISR_A, FALLING);
DisplayIndex = 1; // display will show count and time of hits
}
// save the starting time of this run
StartTime = millis();
// set state of timer to running
TimerState = 1;
// now buzz the speaker for 0.5 secs
tone(BuzzerPin, FreqHi, BuzzTime5);
}
}
}
void StopTimer()
{
// turn off interrupts
detachInterrupt(0);
detachInterrupt(1);
TimerState = 0;
// turn the LED off to show timer is stopped
digitalWrite(LEDPin, LOW);
}
void ClearData()
{
A_count = 0;
B_count = 0;
for (int i=0; i < MaxHits ; i++)
{
A_Times[i] = 0;
B_Times[i] = 0;
A_splits[i] = 0;
B_splits[i] = 0;
AB_splits[i] = 0;
}
A_Hit_Factor = 0;
B_Hit_Factor = 0;
}
void SendTimes()
// temp routine to send data to serial monitor
{
Serial.println("Timer is stopped");
Serial.println("Here are the times for Shooter A");
Serial.print("Number of hits : ");
Serial.print("\t");
Serial.println(A_count);
Serial.println("A Hit and split times are : ");
int i = 0;
int k = 0;
for (i=0; i < MaxHits ; i++)
{
k = i + 1;
//Serial.print(A_count[k]);
Serial.print("\t");
Serial.print(A_Times[i]);
Serial.print("\t");
Serial.println(A_splits[i]);
}
Serial.println("Here are the times for Shooter B");
Serial.print("Number of hits : ");
Serial.print("\t");
Serial.println(B_count);
Serial.println("B Hit and split times are : ");
for (i=0; i < B_count ; i++)
{
k = i + 1;
//Serial.print(B_count[k]);
Serial.print("\t");
Serial.print(B_Times[i]);
Serial.print("\t");
Serial.println(B_splits[i]);
}
}
void ISR_A()
{
// store the hit time
A_Times[A_count] = millis() - StartTime;
// increment the hit count and array index
++A_count;
// set the Hit flag so other stuff will update
AupDtFlag = 1;
}
void ISR_B()
{
// store the hit time
B_Times[B_count] = millis() - StartTime;
// increment the hit count and array index
++B_count;
// set the Hit flag so other stuff will update
BupDtFlag = 1;
}
void CalcTimes()
{
// routine to calculate all data and declare winner
// not all calcs having meaning for uses of timer
// calculate A splits and cumlative hit factor
if (A_count > 1)
{
for (int i=1; i < A_count ; i++)
{
A_splits[i] = A_Times[i] - A_Times[i-1];
}
}
else
{
A_splits[0] = A_Times[0];
}
A_Hit_Factor = A_Times[A_count - 1]/A_count;
// calculate B splits and cumlative hit factor
if (B_count > 1)
{
for (int i=1; i < B_count ; i++)
{
B_splits[i] = B_Times[i] - B_Times[i-1];
}
}
else
{
B_splits[0] = B_Times[0];
}
B_Hit_Factor = B_Times[B_count - 1]/B_count;
// Calculate A - B times just in case
int Min_count = min(A_count, B_count);
for (int i=0; i < Min_count ; i++)
{
AB_splits[i] = A_Times[i] - B_Times[i];
}
// add more here for A vs B modes
}
void FormatData()
{
AupDtFlag = 0;
BupDtFlag = 0;
// routine to format lines of data to be sent to LCD
// presently assume 4 lines of 20 characters
// switch formatting done based on display state
switch (DisplayIndex)
{
case 1:
//this is for single A shooter mode
// display number of hits so far
lcd.clear();
lcd.print(" A: # hits = ");
if(A_count < 10);
{
lcd.print(' ');
}
lcd.print(A_count);
lcd.setCursor(0, 1);
lcd.print(" Hit time = ");
TimeConvert(A_Times[A_count-1]); // convert hit time to XX.xx format
lcd.setCursor(0, 2);
lcd.print("Split time = ");
TimeConvert(A_splits[A_count-1]); // convert split time
break;
case 2:
// this is A review mode hits 1-8
lcd.clear();
int k = 0;
for (int i=0; i < 4 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print(" ");
lcd.print(i+5);
lcd.print(":");
TimeConvert(A_Times[i+4]); // convert hit time to XX.xx format
}
break;
case 3:
// this is A review mode hits 9-16
lcd.clear();
int k = 0;
for (int i=8; i < 12 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A"); // this will display oddly for hits 9 and 13
if(i == 8)
{
lcd.print(" ");
}
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print(" ");
lcd.print(i+5);
lcd.print(":");
TimeConvert(A_Times[i+4]); // convert hit time to XX.xx format
}
break;
case 4:
// this is A review mode hits 17-20
lcd.clear();
int k = 0;
for (int i=16; i < 20 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
// lcd.print(" ");
// lcd.print(i+5);
// lcd.print(":");
// TimeConvert(A_Times[i+4]); // convert hit time to XX.xx format
}
break;
case 5:
//this is for AvsB shooter mode
// display number of hits so far
lcd.clear();
lcd.print("A: # hits = ");
if(A_count < 10);
{
lcd.print(' ');
}
lcd.print(A_count);
lcd.setCursor(0, 1);
lcd.print("A Hit time = ");
TimeConvert(A_Times[A_count-1]); // convert hit time to XX.xx format
lcd.setCursor(0, 2);
lcd.print("B: # hits = ");
if(B_count < 10);
{
lcd.print(' ');
}
lcd.print(B_count);
lcd.setCursor(0, 3);
lcd.print("B Hit time = ");
TimeConvert(B_Times[A_count-1]); // Now for B times
break;
case 6:
// this is AvsB review mode hits 1-4
lcd.clear();
int k = 0;
for (int i=0; i < 4 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
break;
case 7:
// this is AvsB review mode hits 5-8
lcd.clear();
int k = 0;
for (int i=4; i < 8 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
break;
case 8:
// this is AvsB review mode hits 9-12
break;
lcd.clear();
int k = 0;
for (int i=8; i < 10 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
for (int i=10; i < 12 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
break;
case 9:
// this is AvsB review mode hits 13-16
lcd.clear();
int k = 0;
for (int i=12; i < 16 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
break;
case 10:
// this is AvsB review mode hits 17-20
lcd.clear();
int k = 0;
for (int i=16; i < 20 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
break;
default:
// do the default = 0
lcd.clear();
lcd.print(" Shot Timer v1 ");
lcd.setCursor(0, 1);
lcd.print(" is running ");
lcd.setCursor(0, 2);
lcd.print(" Shooter: ");
lcd.setCursor(0, 3);
lcd.print(" --STANDBY-- ");
}
}
void TimeConvert(long input)
{
// takes the msecs as argument and sets the time for that hit as a XX.xxs string
//time.begin(); // reset Pstring
if (input != 0) // Make sure there's a value...
{
secs = int((input + 5)/1000L); // round msecs into whole secs
frac = int(((input + 5) % 1000L)/10L); // find fractional rounded secs
if (secs < 10)
{
lcd.print(' '); // for sub 10 sec times add leading space
}
lcd.print(secs); // now add whole secs
lcd.print('.'); // now add period
if (frac < 10)
{
lcd.print('0'); // If frac < 10 then pad with a zero
}
lcd.print(frac); // now add fractional secs
lcd.print('s'); // add s to tail
}
else
{
lcd.print = (" "); // If the input variable is zero set time to 6 blank spaces
}
}
TimerMode = 1, A vs B mode
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 9, 8);
// set pin numbers
const int StartPin = 7; // the number of the Start pushbutton pin
const int TargetAPin = 2; // the number of the A targets input pin
const int TargetBPin = 3; // the number of the B targets input pin
const int BuzzerPin = 10; // the number of the buzzer output pin
const int LEDPin = 13; // the number of the LED output pin
const int ScrollPin = 6; // the number of the scroll button input pin
//const int ButtonInPin = A0; // the pin used for the analog buttons
// initialize the constants
const unsigned long MaxTime = 30000; // the max time the timer can run for = 30 secs
const unsigned long WaitTime = 2000; // wait time btw start and timer running = 2 secs plus debounce
const unsigned long DB_delay = 1000; // set a debounce wait time of 1000 msecs
const unsigned long BuzzTime5 = 500; // set the on time for the buzzer, 500 msecs
const unsigned long BuzzTime2 = 200; // set the on time for the buzzer, 200 msecs
const unsigned long BuzzTime10 = 1000; // set the on time for the buzzer, 1000 msecs
const unsigned int FreqHi = 2000; // High frequency of buzzer tone
const unsigned int FreqLo = 1000; // Low frequency of buzzer tone
const byte MaxHits = 20; // Maximum number if hits allowed
// initialize global variables
volatile byte TimerState = 0; // variable for state of timer, running or not running
volatile byte AupDtFlag = 0; // variable indication an A hit has occurred
volatile byte BupDtFlag = 0; // variable indication a B hit has occurred
byte DisplayIndex = 0; // variable for controlling what's displayed
unsigned long StartTime = 0; // variable to hold the start time
unsigned long BuzzTime = 500; // variable to hold the buzzer on time
unsigned int Freq = 2000; // variable for high or low buzzer tone
volatile byte A_count = 0; // variable to hold the number of A hits
volatile byte B_count = 0; // variable to hold the number of B hits
volatile long A_Times[MaxHits]; // array to hold up to MaxHits hit times for target A
volatile long B_Times[MaxHits]; // array to hold up to MaxHits hit times for target B
unsigned long A_splits[MaxHits];
unsigned long B_splits[MaxHits];
long AB_splits[MaxHits];
unsigned long LastTime = 0; // initialize last LCD display time to zero for 1st pass
float A_Hit_Factor = 0;
float B_Hit_Factor = 0;
byte S1 = 0; // Switch 1 init to zero
byte S2 = 0; // Switch 2 init to zero
unsigned int diMin = 0; // Display index mininmim
unsigned int diMax = 99; // Display index maximum
unsigned int TimerMode = 1; // initialize the mode to be A vs B
volatile int secs = 0;
volatile int frac = 0;
void setup()
{
// set up the LCD's number of columns and rows:
lcd.begin(20, 4);
lcd.clear();
lcd.print(" Shot Timer 1 ");
lcd.setCursor(0, 1);
lcd.print(" Initializing ");
delay(3000);
// initialize output pins
pinMode(BuzzerPin, OUTPUT);
pinMode(LEDPin, OUTPUT);
digitalWrite(BuzzerPin, LOW);
digitalWrite(LEDPin, LOW);
// initialize the input pins with internal pullups
pinMode(StartPin, INPUT);
// pinMode(UpPin, INPUT);
//pinMode(DownPin, INPUT);
pinMode(TargetAPin, INPUT);
pinMode(TargetBPin, INPUT);
digitalWrite(StartPin, HIGH);
//digitalWrite(UpPin, HIGH);
//digitalWrite(DownPin, HIGH);
digitalWrite(TargetAPin, HIGH);
digitalWrite(TargetBPin, HIGH);
// for now use pin 6 as button input
pinMode(ScrollPin, INPUT);
digitalWrite(ScrollPin, HIGH);
// opens serial port, sets data rate to 9600 bps
Serial.begin(9600);
// setup ext pins as interrupts
//attachInterrupt(0, ISR_A, FALLING);
//attachInterrupt(1, ISR_B, FALLING);
lcd.setCursor(0, 1);
lcd.print(" Ready ");
}
void loop()
{
if (TimerState) // is timer running
{
// timer is running
// send data to display if there have been any hits
if (AupDtFlag == 1 || BupDtFlag == 1)
{
CalcTimes();
FormatData();
}
// timer is running so now check for any stop conditions
if ((digitalRead(StartPin) == LOW) || ((millis() - StartTime) > MaxTime) || A_count >= MaxHits || B_count >= MaxHits)
{
// stop the timer change the display
StopTimer();
tone(BuzzerPin, FreqLo, BuzzTime10);
// update display just in case last msec hit came in
if (AupDtFlag == 1 || BupDtFlag == 1)
{
CalcTimes();
FormatData();
}
// just for the moment send times to PC for debug
SendTimes();
// delay enough to debounce stop button
delay(DB_delay);
// Change to review-stopped state display based on timer mode
switch (TimerMode)
{
case 1:
//this is for A vs B shooter mode
diMin = 6;
diMax = int(max(A_count,B_count)/4) + diMin - 1; // find how many whole screens
if (max(A_count,B_count) % 4)
{
diMax++ ; // add another screen if partial exists
}
DisplayIndex = diMax; // display will show list of hit times
break;
default:
// the default = single A shooter mode
diMin = 2;
diMax = int(A_count/8) + diMin - 1; // find how many whole screens
if (A_count % 8)
{
diMax++ ; // add another screen if partial exists
}
DisplayIndex = diMax; // display will show list of hit times
}
}
}
else
{
// timer is stopped look for start button or review button pushes
// check for scroll button pushes, change display state as reqd
if (digitalRead(ScrollPin) == LOW)
{
DisplayIndex++; // increment DisplayIndex upon push
if (DisplayIndex > diMax)
{
DisplayIndex = diMin; // wrap around of scrolling action
}
// change to new display
FormatData();
delay(DB_delay);
}
// check to see if start button has been pushed
if (digitalRead(StartPin) == LOW)
{
// start button pushed
// Do the following debug code only to get system running
// This will send message to PC to show button was pushed
Serial.println("Timer is running");
// turn on the LED to show timer is running
digitalWrite(LEDPin, HIGH);
// clear all the prior runs data, reset the display
ClearData();
DisplayIndex = 0;
FormatData();
// delay the Wait Time from start button push
// this delay is for debounce purposes and should stay
delay(DB_delay);
// this delay will change to random later on
delay(WaitTime);
// enable the interrupts based on mode here ATM
// this will change when config mode is added ?
switch (TimerMode)
{
case 1:
//this is for A vs B shooter mode
attachInterrupt(0, ISR_A, FALLING);
attachInterrupt(1, ISR_B, FALLING);
DisplayIndex = 5; // display will show count and time of hits
break;
default:
// the default = single A shooter mode
attachInterrupt(0, ISR_A, FALLING);
DisplayIndex = 1; // display will show count and time of hits
}
// save the starting time of this run
StartTime = millis();
// set state of timer to running
TimerState = 1;
// now buzz the speaker for 0.5 secs
tone(BuzzerPin, FreqHi, BuzzTime5);
}
}
}
void StopTimer()
{
// turn off interrupts
detachInterrupt(0);
detachInterrupt(1);
TimerState = 0;
// turn the LED off to show timer is stopped
digitalWrite(LEDPin, LOW);
}
void ClearData()
{
A_count = 0;
B_count = 0;
for (int i=0; i < MaxHits ; i++)
{
A_Times[i] = 0;
B_Times[i] = 0;
A_splits[i] = 0;
B_splits[i] = 0;
AB_splits[i] = 0;
}
A_Hit_Factor = 0;
B_Hit_Factor = 0;
}
void SendTimes()
// temp routine to send data to serial monitor
{
Serial.println("Timer is stopped");
Serial.println("Here are the times for Shooter A");
Serial.print("Number of hits : ");
Serial.print("\t");
Serial.println(A_count);
Serial.println("A Hit and split times are : ");
int i = 0;
int k = 0;
for (i=0; i < MaxHits ; i++)
{
k = i + 1;
//Serial.print(A_count[k]);
Serial.print("\t");
Serial.print(A_Times[i]);
Serial.print("\t");
Serial.println(A_splits[i]);
}
Serial.println("Here are the times for Shooter B");
Serial.print("Number of hits : ");
Serial.print("\t");
Serial.println(B_count);
Serial.println("B Hit and split times are : ");
for (i=0; i < B_count ; i++)
{
k = i + 1;
//Serial.print(B_count[k]);
Serial.print("\t");
Serial.print(B_Times[i]);
Serial.print("\t");
Serial.println(B_splits[i]);
}
}
void ISR_A()
{
// store the hit time
A_Times[A_count] = millis() - StartTime;
// increment the hit count and array index
++A_count;
// set the Hit flag so other stuff will update
AupDtFlag = 1;
}
void ISR_B()
{
// store the hit time
B_Times[B_count] = millis() - StartTime;
// increment the hit count and array index
++B_count;
// set the Hit flag so other stuff will update
BupDtFlag = 1;
}
void CalcTimes()
{
// routine to calculate all data and declare winner
// not all calcs having meaning for uses of timer
// calculate A splits and cumlative hit factor
if (A_count > 1)
{
for (int i=1; i < A_count ; i++)
{
A_splits[i] = A_Times[i] - A_Times[i-1];
}
}
else
{
A_splits[0] = A_Times[0];
}
A_Hit_Factor = A_Times[A_count - 1]/A_count;
// calculate B splits and cumlative hit factor
if (B_count > 1)
{
for (int i=1; i < B_count ; i++)
{
B_splits[i] = B_Times[i] - B_Times[i-1];
}
}
else
{
B_splits[0] = B_Times[0];
}
B_Hit_Factor = B_Times[B_count - 1]/B_count;
// Calculate A - B times just in case
int Min_count = min(A_count, B_count);
for (int i=0; i < Min_count ; i++)
{
AB_splits[i] = A_Times[i] - B_Times[i];
}
// add more here for A vs B modes
}
void FormatData()
{
AupDtFlag = 0;
BupDtFlag = 0;
// routine to format lines of data to be sent to LCD
// presently assume 4 lines of 20 characters
// switch formatting done based on display state
switch (DisplayIndex)
{
case 1:
//this is for single A shooter mode
// display number of hits so far
lcd.clear();
lcd.print(" A: # hits = ");
if(A_count < 10);
{
lcd.print(' ');
}
lcd.print(A_count);
lcd.setCursor(0, 1);
lcd.print(" Hit time = ");
TimeConvert(A_Times[A_count-1]); // convert hit time to XX.xx format
lcd.setCursor(0, 2);
lcd.print("Split time = ");
TimeConvert(A_splits[A_count-1]); // convert split time
break;
case 2:
// this is A review mode hits 1-8
lcd.clear();
int k = 0;
for (int i=0; i < 4 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print(" ");
lcd.print(i+5);
lcd.print(":");
TimeConvert(A_Times[i+4]); // convert hit time to XX.xx format
}
break;
case 3:
// this is A review mode hits 9-16
lcd.clear();
int k = 0;
for (int i=8; i < 12 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A"); // this will display oddly for hits 9 and 13
if(i == 8)
{
lcd.print(" ");
}
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print(" ");
lcd.print(i+5);
lcd.print(":");
TimeConvert(A_Times[i+4]); // convert hit time to XX.xx format
}
break;
case 4:
// this is A review mode hits 17-20
lcd.clear();
int k = 0;
for (int i=16; i < 20 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
// lcd.print(" ");
// lcd.print(i+5);
// lcd.print(":");
// TimeConvert(A_Times[i+4]); // convert hit time to XX.xx format
}
break;
case 5:
//this is for AvsB shooter mode
// display number of hits so far
lcd.clear();
lcd.print("A: # hits = ");
if(A_count < 10);
{
lcd.print(' ');
}
lcd.print(A_count);
lcd.setCursor(0, 1);
lcd.print("A Hit time = ");
TimeConvert(A_Times[A_count-1]); // convert hit time to XX.xx format
lcd.setCursor(0, 2);
lcd.print("B: # hits = ");
if(B_count < 10);
{
lcd.print(' ');
}
lcd.print(B_count);
lcd.setCursor(0, 3);
lcd.print("B Hit time = ");
TimeConvert(B_Times[A_count-1]); // Now for B times
break;
case 6:
// this is AvsB review mode hits 1-4
lcd.clear();
int k = 0;
for (int i=0; i < 4 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
break;
case 7:
// this is AvsB review mode hits 5-8
lcd.clear();
int k = 0;
for (int i=4; i < 8 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
break;
case 8:
// this is AvsB review mode hits 9-12
break;
lcd.clear();
int k = 0;
for (int i=8; i < 10 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B ");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
for (int i=10; i < 12 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
break;
case 9:
// this is AvsB review mode hits 13-16
lcd.clear();
int k = 0;
for (int i=12; i < 16 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
break;
case 10:
// this is AvsB review mode hits 17-20
lcd.clear();
int k = 0;
for (int i=16; i < 20 ; i++)
{
k = (i % 4)
lcd.setCursor(0,k);
lcd.print("A");
lcd.print(i+1);
lcd.print(":");
TimeConvert(A_Times[i]); // convert hit time to XX.xx format
lcd.print("B");
lcd.print(i+1);
lcd.print(":");
TimeConvert(B_Times[i]); // convert hit time to XX.xx format
}
break;
default:
// do the default = 0
lcd.clear();
lcd.print(" Shot Timer v1 ");
lcd.setCursor(0, 1);
lcd.print(" is running ");
lcd.setCursor(0, 2);
lcd.print(" Shooter: ");
lcd.setCursor(0, 3);
lcd.print(" --STANDBY-- ");
}
}
void TimeConvert(long input)
{
// takes the msecs as argument and sets the time for that hit as a XX.xxs string
//time.begin(); // reset Pstring
if (input != 0) // Make sure there's a value...
{
secs = int((input + 5)/1000L); // round msecs into whole secs
frac = int(((input + 5) % 1000L)/10L); // find fractional rounded secs
if (secs < 10)
{
lcd.print(' '); // for sub 10 sec times add leading space
}
lcd.print(secs); // now add whole secs
lcd.print('.'); // now add period
if (frac < 10)
{
lcd.print('0'); // If frac < 10 then pad with a zero
}
lcd.print(frac); // now add fractional secs
lcd.print('s'); // add s to tail
}
else
{
lcd.print = (" "); // If the input variable is zero set time to 6 blank spaces
}
}