Pages: [1]   Go Down
Author Topic: unsigned long - how to continue counting after 49 days overflow?  (Read 900 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Full Member
***
Karma: 1
Posts: 179
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi there!

I have an arduino board with lcd and I want to display the total arduino running time, since I plugged it into power.

So i am using an unsigned long. What will happen if it overflows? Will the code given below,work after 49 days correctly?

Code:
unsigned long  time= 0;

void loop(){
time=millis();
}
« Last Edit: June 17, 2012, 04:49:06 pm by nathanas » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

In what units? Let's say seconds.

Make another variable, and add to it when 1000+ milliseconds pass. Something like this:

Code:
unsigned long seconds = 0;
unsigned long lastSecond = 0;

void setup () {}

void loop ()
  {
  if (millis () - lastSecond >= 1000)
    {
    seconds++;
    lastSecond += 1000;
    }

  // display seconds

  }  // end of loop

That will work for 49710 days. Should be enough before the battery runs out.

I think that will handle overflow correctly. No doubt someone will say if I am wrong.
Logged

Phoenix, Arizona USA
Offline Offline
Faraday Member
**
Karma: 39
Posts: 5557
Where's the beer?
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't know the answer to your question off the top of my head, and I am not even going to attempt to find out. Instead, I want to encourage you to think about the problem slightly differently:

You have a variable that is holding an incrementing value, and, at some point, will "roll over". You want it to continue counting, though, for a much longer period. So what should you do? How about:

1) Set up -two- variables, both unsigned longs - one called "counter", the other "rollover"
2) Increment counter as normal (however you do that is up to you)
3) When "counter" rolls over (ie, hits its highest number and resets to zero), increment "rollover"
4) Number of count = rollover * max_value + counter

If both are unsigned longs, and you are counting milliseconds, then you'll have about 213503982334 days until it "fails" (even if my math is slightly wrong - believe me, you and possibly humanity itself will be long dead)...
Logged

I will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 200
Posts: 12782
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

No doubt someone will say if I am wrong.

Condition not met.  Consider this post the else-clause.   smiley-cool
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

My example is wrong. It doesn't handle the rollover. Eg. If we were using byte rather than unsigned long, and adding 10 each time and not 1000, consider:

Code:
lastSecond = 250;

lastSecond += 10;

lastSecond is now 4.

The comparison:

Code:
if (millis () - lastSecond >= 10)

would be met for millis() of 251, 252, 253, 254, 255.
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 200
Posts: 12782
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

My example is wrong.

It's correct.

Quote
It doesn't handle the rollover. Eg. If we were using byte rather than unsigned long, and adding 10 each time and not 1000, consider:

 lastSecond = 250;

The only way for this line of code to execute...

 lastSecond += 10;

...is if this condition is true...

 if (millis () - lastSecond >= 10)

...which means millis has to already be 4 or greater.  This is the timeline...


  millis  lastSecond  delta  result
  ------  ----------  -----  -------------------------------------
  255     250          5     condition not met
    0     250          6     condition not met
    1     250          7     "
    2     250          8     "
    3     250          9     "
    4     250         10     condition met; lastSecond incremented
    5       4          1     condition not met
    6       4          2     "


« Last Edit: June 17, 2012, 06:32:55 pm by Coding Badly » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Much as I hate to try to prove myself wrong, try this, which substitutes byte for unsigned long, and "makes up" a one-byte millis:

Code:
#include <Streaming.h>

byte seconds = 0;
byte lastSecond = 0;
byte myMillis = 0;

int count;

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  }

void loop ()
  {
  myMillis++;
 
  if (myMillis - lastSecond >= 10)
    {
    seconds++;
    lastSecond += 10;
    }

  // display seconds

  Serial << "myMillis = " << _DEC (myMillis) << endl;
  Serial << "lastSecond = " << _DEC (lastSecond) << endl;
  Serial << "seconds = " << _DEC (seconds) << endl;
 
  // stop if enough done
  if (count++ > 300)
    while (true) {}
   
  }  // end of loop

Output:

Code:
myMillis = 1
lastSecond = 0
seconds = 0


... blah blah ...

lastSecond = 250
seconds = 25
myMillis = 251
lastSecond = 250
seconds = 25
myMillis = 252
lastSecond = 250
seconds = 25
myMillis = 253
lastSecond = 250
seconds = 25
myMillis = 254
lastSecond = 250
seconds = 25
myMillis = 255
lastSecond = 250
seconds = 25
myMillis = 0
lastSecond = 250
seconds = 25
myMillis = 1
lastSecond = 250
seconds = 25
myMillis = 2
lastSecond = 250
seconds = 25
myMillis = 3
lastSecond = 250
seconds = 25
myMillis = 4
lastSecond = 250
seconds = 25
myMillis = 5
lastSecond = 250
seconds = 25
myMillis = 6
lastSecond = 250
seconds = 25
myMillis = 7
lastSecond = 250
seconds = 25
myMillis = 8
lastSecond = 250
seconds = 25
myMillis = 9
lastSecond = 250
seconds = 25
myMillis = 10
lastSecond = 250
seconds = 25
myMillis = 11
lastSecond = 250
seconds = 25
myMillis = 12
lastSecond = 250
seconds = 25
myMillis = 13
lastSecond = 250
seconds = 25
myMillis = 14
lastSecond = 250
seconds = 25
myMillis = 15
lastSecond = 250
seconds = 25
myMillis = 16
lastSecond = 250
seconds = 25
myMillis = 17
lastSecond = 250
seconds = 25
myMillis = 18
lastSecond = 250
seconds = 25
myMillis = 19
lastSecond = 250
seconds = 25
myMillis = 20
lastSecond = 250
seconds = 25
myMillis = 21
lastSecond = 250
seconds = 25
myMillis = 22
lastSecond = 250
seconds = 25
myMillis = 23
lastSecond = 250
seconds = 25
myMillis = 24
lastSecond = 250
seconds = 25
myMillis = 25
lastSecond = 250
seconds = 25
myMillis = 26
lastSecond = 250
seconds = 25
myMillis = 27
lastSecond = 250
seconds = 25
myMillis = 28
lastSecond = 250
seconds = 25
myMillis = 29
lastSecond = 250
seconds = 25
myMillis = 30
lastSecond = 250
seconds = 25
myMillis = 31
lastSecond = 250
seconds = 25
myMillis = 32
lastSecond = 250
seconds = 25
myMillis = 33
lastSecond = 250
seconds = 25
myMillis = 34
lastSecond = 250
seconds = 25
myMillis = 35
lastSecond = 250
seconds = 25
myMillis = 36
lastSecond = 250
seconds = 25
myMillis = 37
lastSecond = 250
seconds = 25
myMillis = 38
lastSecond = 250
seconds = 25
myMillis = 39
lastSecond = 250
seconds = 25
myMillis = 40
lastSecond = 250
seconds = 25
myMillis = 41
lastSecond = 250
seconds = 25
myMillis = 42
lastSecond = 250
seconds = 25
myMillis = 43
lastSecond = 250
seconds = 25
myMillis = 44
lastSecond = 250
seconds = 25
myMillis = 45
lastSecond = 250
seconds = 25
myMillis = 46
lastSecond = 250
seconds = 25

Once we reach lastSecond = 250, seconds gets stuck on 25.
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 200
Posts: 12782
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


  if ( (byte)(myMillis - lastSecond) >= (byte)(10) )

...otherwise the operation is promoted to int.  Type-casting is not necessary for unsigned long because there is no promotion.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

So I was right all along? How does that work?
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 200
Posts: 12782
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

So I was right all along?

That's what I've been saying.

Quote
How does that work?

Don't ask me.  You're the one who convinced yourself you were wrong.
Logged

Pages: [1]   Go Up
Jump to: