Hey guys,
I'm just beginning a new project. Its a game where 4 players are given a time, for example 10 seconds, and once the timer starts they have to press a button when they think 10 seconds has passed. The arduino has to display there times and then say who the closest was by lighting up an LED.
I know that coding a simple stopwatch isnt too challenging, so im told, just not sure how to have 4 stopwatches running at the same time and then have arduino interpret the data and pick a winner. Could any of you guys point me in the right direction? Im still trying to learn millis so maybe this is the time to really knuckle down.
Cheers guys
See if you can make heads or tails of this. This code relies on pin interrupts; not all Arduino models have 4 available interrupts (my 2560 does). If yours doesn't, just change it to poll the switches:
//define a limit for waiting for all players, 20-seconds in this case
#define GAME_TIME_LIMIT 20000L
//these are the player button pins
//these were used on a Mega2560
//make sure the pins you use have pin interrupts available
const int PLYR_1_BTN = 2;
const int PLYR_2_BTN = 3;
const int PLYR_3_BTN = 18;
const int PLYR_4_BTN = 19;
unsigned long
MasterTimer,
timePlayer[4];
byte
bPressFlags;
void setup()
{
//we need the serial window for interaction so wait for it
Serial.begin(9600);
while(!Serial);
//set up the buttons as input-pullups. Pushing a button should ground it
pinMode( PLYR_1_BTN, INPUT_PULLUP );
pinMode( PLYR_2_BTN, INPUT_PULLUP );
pinMode( PLYR_3_BTN, INPUT_PULLUP );
pinMode( PLYR_4_BTN, INPUT_PULLUP );
//each button will cause an interrupt on a falling edge (e.g. a press)
//map each button to its own handler
attachInterrupt(digitalPinToInterrupt(PLYR_1_BTN), ISR_PLYR_1, FALLING);
attachInterrupt(digitalPinToInterrupt(PLYR_2_BTN), ISR_PLYR_2, FALLING);
attachInterrupt(digitalPinToInterrupt(PLYR_3_BTN), ISR_PLYR_3, FALLING);
attachInterrupt(digitalPinToInterrupt(PLYR_4_BTN), ISR_PLYR_4, FALLING);
//reset the game and start
ResetGame();
}//setup
void ResetGame( void )
{
Serial.println( "\n\n*** Begin timing!!! ***" );
//we start the master timer here
MasterTimer = millis();
//this byte carries the user button press info
//in bits 0..3
//bit 0 = 1 means player 1 hit his button
//bit 1 = 1 means player 2 hit his button
//bit 2 = 1 means player 3 hit his button
//bit 3 = 1 means player 4 hit his button
//sero it at the start; each ISR will set its own bit
bPressFlags = 0x00;
}//ResetGame
void loop()
{
unsigned long
timeNow;
//let the game run until all four have pressed a button or some arbitrarily long timeout has elapsed
timeNow = millis();
if( ((timeNow - MasterTimer) > GAME_TIME_LIMIT) || (bPressFlags == 0x0F) )
{
ShowResults();
ResetGame();
}//if
}//loop
void ShowResults( void )
{
byte
plyr,
ClosestPlayer;
unsigned long
diff,
ClosestTime;
unsigned long
timeDelta[4];
float
dispTime;
//if no one pressed a button, say so
if( bPressFlags == 0x00 )
{
Serial.println( "No one played the game!" );
}//if
else
{
//ClosestTime will contain the smallest difference between user times and 10-seconds from the MasterTimer
//init with a huge value for comparison reasons
ClosestTime = 10000000L;
//check each player's results
for( plyr=0; plyr<4; plyr++ )
{
Serial.print( "Player " ); Serial.print(plyr+1); Serial.print( " time: " );
//if the player hit his button, a bit will be set in flags
if( bPressFlags & (1<<plyr) )
{
//plyr hit the button...
//find his time difference and make a value we can display to 3-digits (i.e. a float)
timeDelta[plyr] = timePlayer[plyr] - MasterTimer;
dispTime = (float)timeDelta[plyr] / 1000.0;
Serial.println( dispTime, 3 );
}
else
{
//bit wasn't set player hadn't hit his button
Serial.println( "No time recorded. " );
}//else
}//for
//go through and see who won
for( plyr=0; plyr<4; plyr++ )
{
//only players that pressed their buttons are checked
if( bPressFlags & (1<<plyr) )
{
//how close to 10-seconds?
//could be over or under; this is crude but makes it easy
if( timeDelta[plyr] >= 10000 )
diff = timeDelta[plyr] - 10000;
else
diff = 10000 - timeDelta[plyr];
//if the current players time is smaller than the current "closest" time, make that
//the new closest and record the player number
if( diff < ClosestTime )
{
ClosestPlayer = plyr;
ClosestTime = diff;
}//if
}//if
}//for
//print the results
Serial.print( "The winner is player " ); Serial.print( ClosestPlayer + 1 ); Serial.print( " with an error of " );
Serial.println( (float)(ClosestTime / 1000.0), 3 );
}//else
//use the serial console to re-start. Could also use any of the player buttons
Serial.println( "\n\nPress any key to play again." );
//wait for a character, then flush
while( Serial.available() <= 0 );
while( Serial.available() > 0 )
Serial.read();
}//ShowResults
void ISR_PLYR_1( void )
{
//if a button press has already been recorded, just leave (bounce etc)
if( bPressFlags & 0x01 )
return;
//record the player's button press time
timePlayer[0] = millis();
//and set his flag indicating he played
bPressFlags |= 0x01;
}//ISR_PLYR_1
void ISR_PLYR_2( void )
{
if( bPressFlags & 0x02 )
return;
timePlayer[1] = millis();
bPressFlags |= 0x02;
}//ISR_PLYR_2
void ISR_PLYR_3( void )
{
if( bPressFlags & 0x04 )
return;
timePlayer[2] = millis();
bPressFlags |= 0x04;
}//ISR_PLYR_3
void ISR_PLYR_4( void )
{
if( bPressFlags & 0x08 )
return;
timePlayer[3] = millis();
bPressFlags |= 0x08;
}//ISR_PLYR_4
Wow thank you so much blackfin, that is so much more than I was expecting.
Ive scanned through a couple of times and I might check in with a few questions about areas I struggle to understand but I get the principle I think. Im just reading into flags now.
If you made this circuit yourself, do you have any reference images of how you did it? Also Im able to do this with most kinds of LCD/LED screens arnt I, If I adjust the libraries accordingly