Count Down Code Options

Hi, new to this and wondering about best count down code for me..

I have 3 players in a game, each has a count down clock with the same value at the start of the game, player 1 presses their button to start their count down while the other two player’s clocks stay the same. Player 2 then presses their button to start their clock counting down, this stops the clock of all other players so only player 2's clock is running and this scenario continues until one players clock is at zero and then its game over.

I have my project working so that it accepts the game time in hours, minutes and seconds, stored separately as variables called gHours, gMinutes and gSeconds. The stage I am at now is giving each player their own clock and then starting and stopping count down using a button interrupt(think I can figure this out)...

I was thinking of just changing the gHours, gMinutes and gSeconds in to a sum of those in seconds only and displaying that but its not really what I want to do, I would much prefer to show HH:MM:SS on the clocks.

I guess the things to note are that it doesn't need to be super accurate as long as a game set to last 10 seconds doesn't take 13 then its fine.

Any suggestions much appreciated

Dexter

First read and understand the BlinkWithoutDelay example, so you understand how to do things without using delay which blocks the code from reacting properly to user input.

Then think about how you can use seconds for the time, instead of hours, minutes and seconds.

Using seconds you have 3 variables - the master time that is entered at the start, and then two "user" times that count down when that user is selected as the "active" user.

Using millis() you can find out when a second has passed, and decrement the active clock variable. Then using some very simple maths you can split that seconds counter back into hours, minutes and seconds (hit: divide and modulus, or divide, multiply and subtract) for displaying.

I am guessing what you are after is a kind of inverse chess clock?

I am guessing what you are after is a kind of inverse chess clock?

Yes that is exactly what I am looking for :slight_smile:

Then think about how you can use seconds for the time, instead of hours, minutes and seconds.

I have considered this and also as you say converting it back to HH:MM:SS when it changes and I want to display the time again every second, I just thought there would be a function or library to do this without me making a mess of it.

First read and understand the BlinkWithoutDelay example

looking at this now, thank you very much indeed

Dexter

Nah, not aware of any libraries or functions for it.

The maths is simple enough.

One hour is 3600 seconds.
One minute is 60 seconds.

Time is (Hours * 3600) + (Minutes * 60) + Seconds.

Hours is Time / 3600.
Minutes is (Time % 3600) / 60.
Seconds is Time % 60.

Interesting project. For best accuracy, I believe you will find you want to keep the time internally in milliseconds and convert to hh:mm:ss for display.

Otherwise, each player will lose some fraction of a second at each button press. (Even a mechanical chess clock keeps track to the tick.)

Good luck with your project,

-br

Thanks guys

Time is (Hours * 3600) + (Minutes * 60) + Seconds.

This gives me a negative value on my display when I reach a certain number size and I am not sure why e.g.
gHours =9

gametime = gHours * 3600
gametime = 32400 printed on display(perfect)

change gHours to 10 and gametime = -29536 on the display

also if I set gHours=9 and gMinutes =lets say 5 it works ok but if I change the gMinutes to a larger number like 9 then it gives me a negative value again

I have gametime declared as an integer but have tried long to, either one should be capable of storing my values though

any ideas?

here is my code example where I declare the variables

int gHours = 0;//stores game time hours of play
int gMinutes = 0;//stores game time minutes of play
int gSeconds = 0;//stores game time seconds of play
long GameTime = 0;

and here is my code when I calculate the value of GameTime

{
gHours = 10;
gMinutes = 0;
gSeconds = 0;           
GameTime = (gHours * 3600) + (gMinutes * 60) + gSeconds;
GameTimeSet =true;
lcdP1.print(GameTime);
}

Try using "unsigned long" instead of "int" - or at least "unsigned int".

you can count down relative easily with my stopwatch class - Arduino Playground - StopWatchClass -

I have implemented something similar that counts down from 99 seconds that you could adapt. Look in the link below (signature block). Hope it is useful.

It would be better to keep track of game time remaining (for each player) in milliseconds, since the arduino has a natural clock at that rate, and compute for display how many hours/minutes/seconds the remaining milliseconds add up to.

-br

I am going to do it in milliseconds

I will keep a GameTime in milliseconds which is the initial game time I will also have P1GameTime, P2GameTime and P3GametTime stored in Milliseconds.

my plan(although so far I am facepalming often) not written in code yet
attachInterrupt (P1pin,P1Press,RISING);
attachInterrupt (P2pin,P2Press,RISING);

P1Press()
{
ActiveTimer = "P1";
}

P2Press()
{
ActiveTimer = "P2";
}

void GameRunning()
unsigned long currentMillis = millis();
//put a while loop in here to check if any counters are at zero if they are someone has won so end game
if(currentMillis - previousMillis > 1000)
{
// save the last time counter changed
previousMillis = currentMillis;

if(ActiveTimer = "P1)
{
//decrease the value of P1GameTime in milliseconds by 1000
//convert P1GameTime in milliseconds to HH:MM:SS
//write to the P1 LCD the converted time
}
else if(ActiveTimer = "P2")
{
//decrease the value of P2GameTime in milliseconds by 1000
//convert P2GameTime in milliseconds to HH:MM:SS
//write to the P2 LCD the converted time
}
}
}

does this make any sense? is it a solid plan? at this moment in time I cant get my interrupt working(not used them before), I am sure it will come.

Thanks very much for the interest in my project and all the advice

Dexter

It's a good plan. A couple of observations that may save you some trouble:

You don't need interrupts for the buttons. It's sufficient to poll them in loop(). So, save yourself the trouble.

Your problem lends itself well to the use of arrays, specifically an array of time remaining values, one for each player. If you learn how to use arrays to represent the data, you can write your logic once instead of having a P1, P2, and P3 block. Your activeTimer could be used as the array index to select which player's time is the current one counting down. A little searching and reading up will pay for itself in code you don't have to duplicate and debug.

-br

Hi, Thanks for all your help, I got the code for the count down working barring a very small amount require to pad out less than 10 values in hours minutes and seconds with a zero, but I will hopefully figure that out tomorrow. I also need to make my code more efficient there seems to be a few lines where I am using more clock cycles than required.

billroy as you say I did not need the interrupts and just polled the switches for changes during the loop. I did however end up using seconds instead of milliseconds, the reason for this was that if I checked for a changes every millisecond the effect on the LCD was that it blinked with changes constantly and using the seconds does not appear to have a negative effect.

Next up is adding some beeps for the last 10 seconds of the count down and a two tone siren at the end of the game(just for fun) So I think I am maybe 72 hours away from a completed fully tested prototype which is just superb. After which I plan to look at moving for the Arduino to a PCB based micro controller and interconnects between the LCD's and buttons which I want to be modular using DB9 connectors. Eventually I hope to have 1 LCD and keyboard for user interface in a module with the Micro controller and 4 modular LCD's and buttons which connect into the micro controller "main unit"

Thanks again

Dexter

dexter101:
Hi, Thanks for all your help, I got the code for the count down working barring a very small amount require to pad out less than 10 values in hours minutes and seconds with a zero, but I will hopefully figure that out tomorrow.

I'll give you a hint: sprintf().

I’ll give you a hint: sprintf().

Thanks for this, but I am getting tied up with it, I don’t think I understand what it is actually doing, I thought it was simply placing a variable of what ever type into a string?

void PadGameTIme(long ActiveGameTime)
{
char buffer[2];
String zero = “0”;
String strGhours = " ";
String strGminutes = " ";
String strGseconds = " ";

gHours = ActiveGameTime /3600;
gMinutes = (ActiveGameTime %3600) /60;
gSeconds = ActiveGameTime % 60;
if (gHours <10)
{
strGhours = zero + gHours;
}
else if (gHours >=10)
{
strGhours = sprintf(buffer, “%lu”, gHours);
}

if (gMinutes <10)
{
strGminutes = zero + gMinutes;
}
else if (gMinutes >=10)
{
strGminutes = sprintf(buffer, “%n”, gMinutes);
}

if (gSeconds <10)
{
strGseconds = zero + gSeconds;
}
else if (gSeconds >=10)
{
strGseconds = sprintf(buffer, “%f”, gSeconds);
}
PaddedGameTime = strGhours + colon + strGminutes + colon + strGseconds;

}

The sprintf lines give me the following error

DexASBv1:247: error: invalid conversion from ‘int’ to ‘const char*’
DexASBv1:247: error: initializing argument 1 of ‘String& String::operator=(const char*)’

the gHours, gMinutes and GSeconds are declared as long variables, I thought he issue might have been the syntax fo %d, %LU etc so I just tried them all and got the same error message

Any ideas?

     strGhours = sprintf(buffer, "%lu", gHours);

Somebody needs a clue (or an ass-kicking). Lose the damned Strings. Act like a big boy and learn how to use strings.

Thanks for your response and the threat of an ass kicking, very helpfull and big boyish of you! I read the sticky on how to use the forum and didn’t see anything in there about having to meet the PaulS standard of ability and coding before posting, perhaps you could link to this so that no one else gets an answer like this from you.

Google, I'm sure, told you what sprintf() returns. That was the clue needed.

You've certainly had the opportunity to read about all the issues that using String causes. Persistence in using that class on a limited memory system is what deserves the other.

I appreciate what you are saying now, the strings are not working very well(I was until not aware there was a problem)

Is there a solution to printing on the LCD in one line?

I have read through the Arduino Stopwatch project and the end result is what I want to achieve backwards, but is printing to the LCD position by position in a loop really the best option?

my c coding is very limited(2weeks since i started this project) I have done a bit of VB in the past and having been making some comparisons incorrectly.

Thanks

Dexter

but is printing to the LCD position by position in a loop really the best option?

At the end, that is how it happens. What matters is what else is happening while that character by character printing is happening. If you format, using sprintf(), which creates a string, so there is need to use a String, too, then you can print all the characters at once, so nothing happens between the characters.

If you do it character by character, you may, or may not, be doing lots of stuff between characters.