Go Down

Topic: millis() rollover (Read 9 times) previous topic - next topic

beige

Been searching around to find out what exactly happens to the millis() output after rollover, but I'm not finding anything.


This is the active part of my code, using the DS1307 library to talk to a RTC which currently it's data requested once a second, but since I will be doing more with the program I can't really use a delay, that and I don't like to use delays if at all possible.
The easiest way I can see is to detect the 50 day millis() rollover, but not knowing what happens to the stored number makes that difficult ::)

Code: [Select]
void doClock(){                           // Currently the only thing called from loop()
 if (millis() - checkRTCmillis > 1000) {
   checkRTCmillis = millis();
   
   RTC.get(rtc,true);

   if(rtc[2] < 10){LED.print("0");}
   LED.print(rtc[2]);                    // LED.print uses newsoftserial to talk to a serial LED display

   if(rtc[1] < 10){LED.print("0");}
   LED.print(rtc[1]);
 }
}


Also, since I have a RTC it would be very easy to wait for a bit less than the millis() rollover, then trigger a function to detect when it actually happens, not sure if that would be necessary though.

retrolefty

I too have followed the millis() rollover thing for sometime now. I get how it was changed to a long, so the rollover was increased to 50+ days or so.

What I don't get is the several statements made in various postings that now a programs flow can operate OK through a roll-over? Can some explain this in simple terms, how the edge condition of roll-over can continue without blowing up if statements using it.

Typically one saves a copy of the millis() count as the 'current time' and that is used later when compared to a new millis() count to see if a specific time has elapsed or not. How does the roll-over effect that use of logic?

Lefty

Coding Badly

#2
Dec 08, 2009, 12:11 am Last Edit: Dec 08, 2009, 12:12 am by bcook Reason: 1
It has to do with the way twos-complement arithemetic works.  After my belly is full (it's nearly dinner time), I'll make an attempt at a description.

But, knowing the incredible level of information and support that's provided here, someone will very likely beat me to it...

beige

Glad I'm not the only one. :)

crimony

#4
Dec 08, 2009, 03:10 am Last Edit: Dec 08, 2009, 03:14 am by crimony Reason: 1
Assuming standard operating procedure is that you have a main loop executing, and you want to perform some action periodically.

After you perform the action (straight away the first time through the loop), you save the current millis() and continue. Next time around the loop you read the value of millis() again and subtract the value obtained last time you performed the action. If the subtraction results in a number that is larger than your period then you perform the action again and get the new version of millis(), otherwise you don't.

Assume for the sake of this explanation that millis() is only an 8-bit number (the concept extends to 16- and 32-bit numbers equally well).
Also assume you want your periodic function to run every 30 ms, and that the loop takes 10 ms.

First time through the loop you perform your action and get the value of millis():
Code: [Select]
unsigned char last = millis()
Let's say last = 8. Next time around the loop millis() returns 18, so you do the subtraction:
Code: [Select]
00010010 (18: current)
-00001000 (8: last)
---------
00001010 (10)

this is repeated twice more until millis() returns 38 and then:
Code: [Select]
00100110 (38: current)
-00001000 (8: last)
---------
00011110 (30)

now we would perform the action and last would become 38.
Eventually (after the action had been performed 8 times) last would become 248, then the interesting bits start to happen, the next time through the loop, 10 ms have elapsed so millis() should be 258. 258 cannot be represented in 8 bits, so with rollover millis() would become 2. So now we to the subtraction:
Code: [Select]
00000010 (2: current)
-11111000 (248: last)
---------
00001010 (10)

The arithmetic unit "borrows" a bit (bit 9) and treats the minuend (the number being subtracted from) as if its value was 258 (0x102, 100000001 binary). In other words, inside the CPU the calculation actually looks like this:
Code: [Select]
100000010 (258: current)
-011111000 (248: last)
---------
000001010 (10)

Twice more around the loop and you get this:
Code: [Select]
00010110 (22: current)
-11111000 (248: last)
---------
00011110 (30)

Then you perform your action, set last to 22 and off you go.

Go Up