I’ve got a project where I need to keep the device running for months at a time without becoming unstable. I’m using millis() to keep a timer so actions happen on a schedule (default every 5 seconds).
unsigned long timer = 0;
int pollRate = 5; // in seconds
void setup()
{
analogReference(EXTERNAL);
timer = millis();
}
void loop()
{
if(millis() - timer >= (pollRate * 1000))
{
// Do my stuff
timer = millis();
}
}
I read that millis() will run on for about 50 days before it rolls over to 0. What is the best way to avoid trouble when it rolls over to 0? The best solution I can come up with is to add code like this into loop()
unsigned long timer;
unsigned long lastTimer;
loop()
{
if(millis() - timer >= 5000)
{
// stuff
lastTimer = timer;
timer = millis();
if(timer < lastTimer)
{
// do something to correct the rollover
}
}
}
It would be best to simply make sure that milli() is greater than timer.
If it is , use your normal processing, if not, subtract timer from the maximum value for milli() and then add that difference and the current milli() value.
It may not be an issue at all if you think through the wacky computer math.
An unsigned long allows you to count from 0 to 4,294,967,294.
Suppose that at time 4,294,967,293 (note the last digit is a 3) your millis is greater than the current time by 5 seconds. You snag that value as your ‘timer’ value. Now one millisecond later, millis() returns 4,294,967,294. Your difference is only one ms so you loop again. Next time millis() returns 0. Now what is the value of (0-4,294,967,293) using unsigned long math? It happens to be 1! Next iteration the difference will be 1, then 2, etc.
Coding the test the way you did actually solves your problem without any fuss. My only recomendation is to write the code like this:
void loop()
{
now = millis();
if(now - timer >= (pollRate * 1000))
{
// Do my stuff
timer = now;
}
}
The issue is that it is possible that the two times you called millis() before could return different values and you would drift over time. It also saves an extra subroutine call but at the expense of a new 4 byte variable.
fll-freak:
It may not be an issue at all if you think through the wacky computer math.
An unsigned long allows you to count from 0 to 4,294,967,294.
Suppose that at time 4,294,967,293 (note the last digit is a 3) your millis is greater than the current time by 5 seconds. You snag that value as your ‘timer’ value. Now one millisecond later, millis() returns 4,294,967,294. Your difference is only one ms so you loop again. Next time millis() returns 0. Now what is the value of (0-4,294,967,293) using unsigned long math? It happens to be 1! Next iteration the difference will be 1, then 2, etc.
Coding the test the way you did actually solves your problem without any fuss. My only recomendation is to write the code like this:
void loop()
{
now = millis();
if(now - timer >= (pollRate * 1000))
{
// Do my stuff
timer = now;
}
}
The issue is that it is possible that the two times you called millis() before could return different values and you would drift over time. It also saves an extra subroutine call but at the expense of a new 4 byte variable.
Gah. I hadn’t thought about that. A rollover isn’t likely to do harm. Good call on the variable for millis().
Not sure what happend, but you can count from 0 to 4,294,967,295 not …4 as i wrote above. But the whole rounder math things still works. Now it onl works for the way you wrote the test. If instead you computed a target time to compare ‘now’ against, it would not work.
fll-freak:
Not sure what happend, but you can count from 0 to 4,294,967,295 not …4 as i wrote above. But the whole rounder math things still works. Now it onl works for the way you wrote the test. If instead you computed a target time to compare ‘now’ against, it would not work.
Wait, you’re saying that
void loop()
{
now = millis();
if(now - timer >= (pollRate * 1000))
{
// Do my stuff
timer = now;
}
}
won’t work? but taking out now = millis() and using millis() in the if will? That doesn’t make any sense the way I see it.
timer roll-over can be simple… don’t use the timer itself. Use a function that reads the timer and computes the distance in ticks from a tick count passed to the function, and the current timer, accounting for the modulo roll-over. It’s just a couple lines of code using unsigned types.