# Arduino: How do you reset millis() ?

The quick answer to “How do you reset millis()” is:  You Don’t!  And here’s why:  if you did, it would potentially break most libraries and functions that rely on it.  Generally the reason people want to reset it, is that they are concerned about rollover.  Instead of focusing on resetting millis(), here is how to use it correctly.

Need to brush up on how millis() works?  I’ve got a tutorial on how to effectively multi-task with millis() and another line-by-line tutorial on blink Without delay

Avoiding rollover and checking how much time as passed is done in a single line:

`if ((unsigned long)(millis() - previousMillis) >= interval)`

That single line of code is all that is really needed, to avoid rollover!  Pretty simple, huh?  So let’s go into more detail about how this works and what each of those variables do.

Update Dec 8 2013. I’ve updated the examples below to a more robust implementation.

## What is millis() rollover?

Every millisecond a timer interrupt fires to increment a global variable.  When millis() is called, the value of that variable is returned.  The data type used is an unsigned long which is 4-bytes or 32-bits.  This means the maximum value it can hold is 4,294,967,295.  Convert that many milliseconds into days and you can see the rollover will occur in 49 days.

$frac{4,294,967,295ms}{1000} = frac{4,294,967secs}{60} = frac{71852mins}{60} = frac{1193}{24} = 49dayshuge$

In HEX the maximum value is 0xFFFFFFFF.  Add one more and it “rolls over” to zero.  Hence the name “millis() rollover.”

## Will my Arduino Lock-Up?

Let’s be very clear:  when millis() rolls-over, your Arduino will not lock-up.  In fact the Arduino’s ATmega processors very rarely lock-up.    So no, when the millis() value rolls over to 0, your Arduino won’t lock up and your project won’t explode.  Ok?  [Editor’s Note:  If your project is designed to explode when millis() equals 0, then in that case, it would explode.]

## How to reset millis() to avoid rollover

When it comes down to it, there’s no reason to reset millis().  In fact, it turns out this seemingly trivial task requires changing quite a few things buried deep inside of the Arduino core functions.  The worst part is, if you make those changes you may very well break libraries and other projects!  Instead, all that you need to do is simple subtraction:

```unsigned long currentMillis = millis();
if ((unsigned long)(currentMillis - previousMillis) >= interval) {
```

That if-statement is a simple way to detect when time a predetermined amount of time has past and it handles rollover! With such a simple statement, why bother with trying to reset millis()?

Here’s an extended example of how to handle millis rollover [pastebin]:

```// Interval is how long we wait
// add const if this should never change
int interval=1000;
// Tracks the time since last event fired
unsigned long previousMillis=0;

void setup() {
pinMode(13, OUTPUT);
}

void loop() {
// Get snapshot of time
unsigned long currentMillis = millis();

// How much time has passed, accounting for rollover with subtraction!
if ((unsigned long)(currentMillis - previousMillis) >= interval) {
// It's time to do something!
digitalWrite(13, !digitalRead(13)); // Toggle the LED on Pin 13

// Use the snapshot to set track time until next event
previousMillis = currentMillis;
}
}
```

## Why does this work?

Long story short, it is what happens when do math with unsigned variables. Don’t trust that this will work? Okay, consider the following example using an unsigned char data type which is a single byte or 8 bits.

The maximum the data type can hold in HEX is 0xFF which means in DECimal it is 255.  Let’s select an arbitrary value of decimal 47.  This code will use “counter” to simulate millis(). Every 255 counts it will rollover to zero. Every time we count up 47 steps, we will print the message “Trigger Event!”.

```//Pretend "counter" is "millis"
unsigned char counter = 0;

unsigned char previousCounter = 0;
unsigned int interval=47;

void setup() {
Serial.begin(9600);
delay(5000);  // give enough time to open the serial monitor after uploading
Serial.println("Starting...");
}
void loop() {
for (int x=0; x<1000; x++) { // run through uchar a few times
// ******* simulate millis()
counter++; // simulate millis()
Serial.println(counter);
// ******
unsigned char currentCounter = counter;
if ((unsigned char)(currentCounter - previousCounter) >= interval) { // check for rollover
Serial.println("Trigger Event!");
previousCounter = currentCounter;
}
}
Serial.println("...stopping!");
while(1); // Stop the Serial monitor output
}
```

When you look at the serial output of that code, make sure you open the serial monitor before it opens itself.  You want to start look at the top of the output right after “Starting”.  The first time through 255, you’ll see a trigger after 47, as expected.  The second time through 255 it’ll be after 26.  The value of 47 was picked in this example because it won’t always be in the same place in the count.  However, it will always be 47 steps after the previous “Trigger.”  That’s how we know this code is accounting for rollover.

## Conclusion

Instead of trying to reset millis(), just use subtraction to handle the millis() time detection and rollover. It is a simple method that won’t involve modifying any code in the Arduino libraries. (This also works with micros() too!)

Also,  if you want to learn more about how to how to use millis to multitask or replace delay(), checkout this tutorial.

Long comments, URLs, and code tend to get flagged for spam moderation. No need to resubmit.

## 57 thoughts on “Arduino: How do you reset millis() ?”

1. sam says:

I don’t understand the “if ((unsigned long)…) part. Why is a declaration in an if statement?

• That isn’t a declaration. It is casting the entire operation to treat all of the variables as unsigned long.

2. Denis says:

Hello. What is wrong with using millis() % interval == 0?

• sdjmchattie says:

Two things might go wrong:

What if the loop isn’t called at least once every millisecond or if it’s called more than once per millisecond? Then you might miss a beat if it took more than a millisecond to process the previous loop and so your condition isn’t satisfied on the next loop. Or if the loop gets called 100 times per millisecond then you perform your action associated with the condition 100 times with no interval at all.

Also, about once every 50 days, millis() rolls over. When millis() reaches 4,294,967,294 it goes back to zero. Let’s say your interval is 10, then you’ll satisfy the condition you’re suggesting at 4,294,967,290 and then, when millis() reaches the number above, only 4 milliseconds later, it resets to zero and satisfies the condition again. That interval wasn’t the 10 milliseconds you wanted so you’ll always have a little odd behaviour once every 50 days. This might not matter, but that’s why you might go out of your way to do it properly.

• As pointed out already, you would get a false fire after rollover.

3. Hannes says:

Thank you Stuart! I owe you one! That was really good education for me. 🙂 Did need to reply here because I cant on last answer.

Cheers
Hannes

4. Hannes says:

Hi guys,

first thank you for the great explanation. Its still kind of easy to understand even for non english and avid programmer. 🙂

I’m unsure how this will end up. Because I take the previousMillis as startMillis to get an “emergency” timeout inside my code if no digitalRead is coming. But if I get a rollover in this code it would take a long time to get back to the Interval. Am I right?

http://pastebin.com/EZt7SLm3

Thanks
Hannes

• Stuart McHattie says:

Hi Hannes. No a rollover won’t make you wait a long time. A very small number (after rollover) minus a very large number (millis before rollover) is another small number because the subtraction also rolls over in the same way. So the time gap will be the same regardless.

Also, your code uses lots of integers as flags. You could use booleans for those.

• Hannes says:

Hi Stuart,

thank you for your great answer.

1.) Sorry still do not get it. Let’s say my “startMillis” = 50, “interval” = 30 the loop does a rollover at 55, then I have next loop a 0-50 = -50 ?

2.) They are “volatile boolean f_done=0” is there a difference when I write false / true or 0 and 1 ?

Cheers
Hannes

• Stuart McHattie says:

Hi Hannes, not to worry it’s a hard concept at first, but you’ve got the right idea. Let’s say the variable rolls over or “overflows” as it’s called at 55 and your last interval ended at 50 like you said.

So you’re doing the subtraction and at 54 you obviously get 4 (54 – 50) as you expected. When the variable rolls over to 5, say, then the subtraction becomes 5 – 50 which is -45 but you can’t have -45 and what you’ve done is underflowed because less than 0 wraps back up to 55 so -45 is actually represented as 10 (-45 + 55) which is the correct number of millis. The interval will be met when the variable reaches 25 and you get 25 – 50 = -25 which is actually 30 (-25 + 55).

Don’t think of the numbers as very small and very big. The numbers wrap around every time they leave the range 0 – 55 so 0 and 55 are only 1 apart from each other.

If you’re already using Boolean that’s great. You should definitely use true and false instead of numbers though. They will be clearer to the reader. When you want to check a Boolean in an if statement, you don’t need to compare with numbers so checking for true is if(variableName) {} and checking for false is if(!variableName) {} where the ! means “not”. This will make your code much more readable.

• Hannes says:

Hi Stuart, thats an amazing logic.

Is this a normal behavior of the long type or just a special case in this one, when an overflow happens?

For the true and false you probably right, I will change it around.

Btw. this code is for a beehive scale project I am building.
https://github.com/HannesOberreiter/bScale

Cheers
Hannes

• Hi Hannes,

This is the normal behaviour for all numeric types. int, long, float, double they all do it. Each type has a finite amount of memory they can take up so there’s a maximum value they can hold. Remember all numbers are stored in memory as 0s and 1s and the largest number is all 1s (not actually true but it’s easier to explain) then when you add 1 to that it’s like when a car with mechanical dials for the mileage goes above the highest number and it rolls over to all 0s which is the smallest number.

The main difference between all the variable types is how many 0s and 1s they have available. Smaller types overflow at a smaller number. Unsigned variable types don’t store negative numbers so overflow to 0. Signed variable types overflow to minus whatever their maximum value is, plus 1. They both have the same range, so an unsigned variable can go to twice the positive number that a signed variable can.

5. Demetri says:

Will doing something like this accomplish the same thing?

/////////////////////////////////////////////////////////////////////////////////

unsigned long time = 0;
int CycleTime = 6000;

time = millis();
time = time + CycleTime;

while(true)
{

if (millis() > time)
{

//DO SOMTHING

time = millis();
time = time + CycleTime;
}

}

/////////////////////////////////////////////////////////////////////////////////

Will doing this on an Arduino Nano cause any problems with memory, as millis() can get quite large?

• Yes it will but it’s not good code because you’re setting up your own permanent loop inside a function that is itself a permanent loop. Let the loop function do the looping and never use while(true) {}.

You also have to repeat yourself with the two lines which update time which you should wither try to avoid or put in to a separate function so you only have to write it out once.

Finally, this uses no more memory no matter how large millis() gets. Try not to think of memory usage based on the size of a number. You only use more memory when you define new variables and you’re not doing that here. I think a long like your time variable uses 32-bits or in other words 4 bytes of memory. It will always use 4 bytes if you put 0, 1, 10 or 60 billion in it so the size of the number is irrelevant. When the number gets too big to fit in 32-bits it will go back to the smallest number that will fit in 32-bits. That’s called an overflow and is why we have to handle the rollover and hence this article.

• I like Demetri’s code. Forget about the while(true), that’s just semantics (he should put the initializing code in the setup{} section, that’s all). But his code does something your’s does not. It will never miss an interval. eg. If interval is say, 1 second to update a RTC value, then if the code further down the line takes up more time than this interval (say 10 seconds), then his code will actually run the event 10 times later when it can.

Just the same, thank you for this explaination. I think it would be more clear if you spelled out what happens on the roll over and show how the unsigned long still comes out larger than the interval. This is the same math I use for following the pointers in a buffer that rolls over.

Hey.. wait a minute, how does he get around the roll over??? Bah, there’s still something not perfect about either of these solutions for the purpose of running a software driven RTC.

6. David says:

Hello

can you explain to me, why this retyping in IF statement is really needed for unsigned long variables? Because your example (your proof) use type uint8_t variables and with this variable type the rollover is really there, but for some reason the rollover is not present for 16 or 32 bit variables (I’m using Atmega328). Here is mine sample code

Serial.begin(9600);

uint8_t a=0, b=1;
Serial.println(a-b); // -1
Serial.println((uint8_t)(a-b)); // 255

uint16_t c=0, d=1;
Serial.println(c-d); // 65535
Serial.println((uint16_t)(c-d)); // 65535

uint32_t e=0, f=1;
Serial.println(e-f); // 4294967295
Serial.println((uint32_t)(e-f)); // 4294967295

I tried to rewrite your proof code with unsigned long variables and I set to “counter” variable near the overflow variable and it works correct even without retyping in IF statement.

thank you

• People who understand the compiler’s rules much better than I have told me it is a good idea. I haven’t proven to myself yet if it is required.

• David says:

Ok I asked about this on arduino forum and looks like your retyping of variable in IF statement is not need, it will work just with simple millis() – previousMillis.

The mistake is your sample code, where you use a byte variable as “timer”. Byte variables are promoted to (signed) int, that is why your sample code actually “rollover”, but that is not case with unsigned long.

If anything, please feel free to write a post here

http://forum.arduino.cc/index.php?topic=414348.0

• I don’t see it as an error, but thanks for the follow up.

7. Hi, this is a great article and makes handling an interval with millis() much more simple than the approach I was previously taking. Something to note is that on line 21 you are setting previousMillis to be currentMillis but this will introduce a very tiny amount of drift in your intervals. If, for example currentMillis – previousMillis is 10002 and the if statement was therefore true, you would perform your action, but will have lost 2 milliseconds from the next interval. I would, instead set previousMillis += interval so that the intervals are kept consistent with real time.

8. The issue i’m seeing with this, is, unless you can accurately place previousmillis before your first time using this method, it will always return true.

example… say you wanted to draw a series of bmp’s on a tft touchscreen with a slight delay between..

//Button
if (p.y > 110 && p.y 250 && p.x = interval){ // here you are saying if currentMillis is greater than 0, it’s true!
bmpDraw(“redbutton.bmp”, 15, 105);
Serial.println(F(“Button Pressed!”));
button = 0;
}
}
}

In this scenario, if this is the first button, then you have no previousmillis set, or it’s still at it’s default setting of 0.. this means the if statement will always return true, as millis() counts from the beginning of the program, you are essentially saying that anything above 0 is true, and millis() will always be above 0

So.. how does one work around this catch 22 type of situation?

• I don’t see this as a problem or a catch-22 at all.

In most situations, the “if (currentMillis…” check that occurs when the program first starts is not a problem. If for some reason this ONE TIME event was an issue, you have two options:

1. Set previousMillis at the end of setup(). It’ll be non-zero.
2. Create a flag that causes the first check to be skipped.

#2 is way overkill in my opinion. Again, I’ve never encountered a situation where the first check was an issue. It only happens once and in most cases you WANT your code to run. The critical timing comes on the 2nd iteration, not the first one.

9. Rinus Boone says:

Thanks for the clear explanation. Just as an extra information: I found that the if statement (line 16 of the first example) goes wrong when the value of ‘interva’l is negative. This happened to me and it took some debugging to find out.

10. // added second
if (((local_time.lastMillis + COUNT_SECOND) actualMillis)) // rollover (1 per 50 days)
{
// how many seconds add
if ((local_time.lastMillis + COUNT_SECOND) < actualMillis)
{
local_time.second += (actualMillis – local_time.lastMillis) / COUNT_SECOND;
local_time.milisecond = (actualMillis – local_time.lastMillis) % COUNT_SECOND;
}
else
{
// rollover
local_time.second++;
local_time.milisecond = 0;
}

local_time.lastMillis = actualMillis;

• Not sure what you are trying to do there. But that looks far more complicated than just using simple twos-complement math.

11. hape says:

hi
if i test your source (the example to explain how it works) i get an error message:
—————————————————————————————————
Arduino: 1.6.5 (Windows 7), Platine: “Arduino Uno”

Build-Optionen wurden verändert, alles wird neu gebaut

millis_timer.ino: In function ‘void loop()’:
millis_timer:13: error: ‘amp’ was not declared in this scope
millis_timer:13: error: ‘lt’ was not declared in this scope
millis_timer:13: error: expected ‘)’ before ‘;’ token
millis_timer.ino:13:31: warning: statement has no effect [-Wunused-value]
millis_timer:13: error: name lookup of ‘x’ changed for ISO ‘for’ scoping [-fpermissive]
millis_timer.ino:13:33: note: (if you use ‘-fpermissive’ G++ will accept your code)
millis_timer:13: error: expected ‘;’ before ‘)’ token
millis_timer:26: error: expected ‘}’ at end of input
‘amp’ was not declared in this scope
————————————————————————————————————–

So i think i have to do anything else than only compile the code?
Any ideas?
thx for your idea
hape

• Yeah, my fault. I changed something in the post and the code got messed up. It is fixed now.

12. Francescomm says:

This works only if the time you are comparing millis() to is not far away in the past. It is a good technique for intervals A-B where both A and B are near enough.

if(millis()-farAwayInThePast>60000) { … }

is NOT OK. Or not probably doing what you’d expect.

After 49 days millis() will rollover to zero (ok thanks to unsigned math) and then eventually become equal to farAwayInThePast again, so this condition will evaluate to FALSE for one minute every 49 days.

13. MJ says:

Thank you for the very cool technique … I have a need for exactly this but I just cannot get my head around how it works.

I modified your sketch to uotput the values of currentCounter and previousCunter like so:

` Serial.print(currentCounter); Serial.print(" - "); Serial.print(previousCounter); Serial.print(" = "); Serial.println(currentCounter - previousCounter);`

`And I get output like this:`

`19 19 - 240 = -221 20 20 - 240 = -220 21 21 - 240 = -219 22 22 - 240 = -218 23 23 - 240 = -217 24 24 - 240 = -216 25 25 - 240 = -215 26 26 - 240 = -214 27 27 - 240 = -213 28 28 - 240 = -212 29 29 - 240 = -211 30 30 - 240 = -210 31 31 - 240 = -209 Trigger Event! 32 32 - 31 = 1 33 33 - 31 = 2 34`

`This is obviously after a rollover or 2 ... no how is -209 (the result just above the last trigger event above) >=47?`

`Brain hurts!`

`Thanks :)`

• baldadmin says:

The maximum value a char can hold is 255 because it is 8-bits.

So 209+47 = 256. Can’t store 256 in a variable that can only hold a maximum of 255.

• > This is obviously after a rollover or 2 … no how is -209 (the result just above the last trigger event above) >=47?

Because you need to use unsigned types (eg. byte rather than char). Then it is impossible for them to hold a negative number, and thus the question “how is -209 >= 47?” goes away.

• wen says:

Hi,
I learned to use millis for multitask(RGB LED flashing & MP3 IR remote).I just wanted to control IR remote to select music(RGBLED flashing itself) but the LED stopped flashing when currenttime:2977 & previoustime:2527
Anyone could help me to debug and solve followed issue?Thanks!!
The code was as followed:

```#include
#include
#include
//********************************************************
const int redPin1 = 3;
const int greenPin1 = 5;
const int bluePin1 = 6;
const int redPin2 = 9;
const int greenPin2 = 10;
const int bluePin2 = 11;
unsigned long PreviousTime = 0;
const long interval = 500;
long cmd2[2];
//MP3 mp3;                               // define mp3 class
const int irReceiverPin = 2;           //
//char val;
IRrecv irrecv(irReceiverPin);          //
decode_results results;
//long IRstop=0x00FFA25D;        //
//long IRplay=0x00FF22DD;        //
//long IRmute=0x00FFE21D;        //
//long IRnoise=0x00FF629D;       //
//long IRprevious=0x00FF02FD;    //
//long IRnext=0x00FFC23D;        //
//long IRvolumeup=0x00FF906F;    //
//long IRvolumedown=0x00FFA857;  //
//long IRsingle=0x00FFE01F;      //
//long IRrepeat=0x00FF6897;      //
//long IRcycle=0x00FF9867;       //
//long IRrandom=0x00FFB04F;      //
//long IR1=0x00FF30CF;           // 1
//long IR2=0x00FF18E7;           // 2
//long IR3=0x00FF7A85;           // 3
//long IR4=0x00FF10EF;           // 4
//long IR5=0x00FF38C7;           // 5
//long IR6=0x00FF5AA5;           // 6
//long IR7=0x00FF42BD;           // 7
//extern SoftwareSerial COM_SOFT;
//********************************************************
void setup()
{
Serial.begin(9600);
// first RGB control pins
pinMode(redPin1, OUTPUT);
pinMode(greenPin1, OUTPUT);
pinMode(bluePin1, OUTPUT);
// second RGB control pins
pinMode(redPin2, OUTPUT);
pinMode(greenPin2, OUTPUT);
pinMode(bluePin2, OUTPUT);
// mp3 setting
//   mp3.begin(MP3_SOFTWARE_SERIAL);       // select software serial
//   mp3.volume(0x1F);                     // set volum to the MAX
//    mp3.set_mode(MP3::CYCLE);             // set MP3 Shield CYCLE mode
irrecv.enableIRIn();                  //

}
//********************************************************
void loop()
{
unsigned long CurrentTime = millis();
Serial.print("Current");
Serial.println(CurrentTime);
// wait a second so as not to send massive amounts of data

if (irrecv.decode(&amp;results)) {         //
irrecv.resume();                     //
}
if (CurrentTime - PreviousTime &gt;= interval)
{
PreviousTime = CurrentTime;
Serial.print("PreviousTime");
Serial.println(PreviousTime);
analogWrite(redPin1, random(0,255));
analogWrite(greenPin1, random(0,255));
analogWrite(bluePin1, random(0,255));
analogWrite(redPin2, random(0,255));
analogWrite(greenPin2, random(0,255));
analogWrite(bluePin2, random(0,255));
}
}
```
14. Michael says:

Hi, I always use this code for doing stuff at a certain interval. I guess people do this especially when reading sensors, as this helps mimic “parallelization” and it spares cycles / power. The opposite, inefficient ways would be to just do the digital/analog readings every time, in every loop, but that would be consuming a lot of CPU cycles and would be very inefficient, and if you also have input readings (like buttons) in the loop, the Arduino won’t respond as it should to those button presses.

Here’s the code I use:

unsigned long lastCheckedTime = 0;
unsigned int CHECK_INTERVAL = 1000; // sensors check / reading interval

`void loop() { if (lastCheckedTime == 0) { // if this is the first loop, force a sensors check this cycle lastCheckedTime = millis() - CHECK_INTERVAL; } if (millis() - lastCheckedTime >= CHECK_INTERVAL) { doSomething(); lastCheckedTime = millis(); } } `
My questions are:
– Does my code already account for millis rollover?
– Do I need the currentMillis variable from your example code? Isn’t millis() returning an “unsigned long”, do I need to explicitly type cast it so the rollover would be handled?
– Is the explicit typecast “(unsigned long)(currentMillis – previousMillis)” really needed? If both operands are of the same type, “unsigned long”, wouldn’t the result be an “unsigned long”? Typecasting is good for ie operations with mixed “float” and “int” variables, but is it needed in this case?

And an observation:
The way you save the last checked time (“previousMillis = currentMillis”) changes the time reference for the next interval. In my code, the next interval starts when the doSomething() function finishes (because of the line “lastCheckedTime = millis()”). In your code, doSomething() would be triggered more often and it could be a problem if it is a time consuming function.

• Does my code already account for millis rollover?

Yes

Do I need the currentMillis variable from your example code? Isn’t millis() returning an “unsigned long”, do I need to explicitly type cast it so the rollover would be handled?

Time is more accurate this way. Each time you call millis(), enough time may have elapsed to cause the value to change. So you call it once, and use that reference until its time to check again.

Is the explicit typecast “(unsigned long)(currentMillis – previousMillis)” really needed?

This depends on who you ask. I’ve done experiments where I explicitly tested with and without the typecasting. For example, I set an unsigned long to 0xFFFF FFFE, and watched what happened manually. I found that it did not matter. Far more experienced programmers told me my experiment wasn’t valid, but couldn’t explain how and that typecasting was necessary. Since I haven’t wanted to sit around for 49 days to prove them wrong, I continue to do it just in case.

In your code, doSomething() would be triggered more often and it could be a problem if it is a time consuming function.

Well, for one, you would need to verify that your doSomething() finishes within your internal. That’s the responsibility of you, the programmer.

Second, your code will have unpredictable timing intervals, depending on what doSomething() does. If it takes 100ms one time and 1000ms next time, your intervals will occur 900ms later than expected.

If you want consistent, reliable timing intervals, you only use one time reference per iteration. Your code can lead to unpredictable intervals.

Think of it this way. If you are boiling an egg in water. It needs to be in there for 10 minutes, but your timer only operates on 1 minute intervals. So you look at the clock and it says “8:01”. You set your timer and go wash your hands. When the timer goes off you look at the clock and it says 8:02. So you reset the timer and go take out the trash. You repeat this process each time your timer goes off until the clock says 8:11. The idea is when the timer goes off, that’s when you reset it. This method ensures we check once per minute.

Now, let’s look at how your code works. You look at the clock and it says 8:01 and you wash your hands (this is your doSomething()). Washing your hands takes about a minute, so the clock now says 8:02 when you finally set the timer (previousMillis = millis()). This means for 2 minutes your timing code wasn’t being checked. The first check happens at 8:03. You decide to take out the trash (that’s your doSomething() this time) which takes you 6 minutes. You come back and start the timer again (thats your previousMillis() = millis()). Problem is, now the time is 8:08 and the timer won’t off until 8:09. This method might work most of the time. But in this case your time checking is entirely inconsistent because your reference point for each cycle is moving around.

You need to only check millis() once per iteration otherwise you’ll have a lot of jitter in your timing.

• podro says:

dears,
sorry
nothinkg of this in discus is not working
try simulate
replace “doSomething();” by “digitalWrite(13, !digitalRead(13));” to see flashing
run the program and see led
as you can see is flashing as expected.

then replace “millis()” by “(millis() & 0x0fff)” – to simulate roll out every 4096ms.

you can see how it blinking now?

normally the same will happend also with original source but rollout will happed every 49days.
how to make any timer to prevent this problem if my app is running longer then 49days?

15. Clive says:

Thanks for this technique. Quick question (and a warning that my programming skills are very poor, as will become painfully obvious): usng your example code can I declare currentMillis at the top, rather than in the loop? I’d need to use the value of currentMillis in other functions and of course it’ll be out of scope if I declare it in the loop as per your example. So for example putting this at the top:

unsigned long previousMillis=0;
unsigned long currentMillis;

and in the main loop replacing:
unsigned long currentMillis = millis();
with:
currentMillis = millis();

compiles and runs fine but I wasn’t sure if I’d broken some core concept of this approach in doing so. If so I guess I can always assign a global variable to the value of currentMillis, but I was intrigued to know if my ‘solution’ does actually work. All advice very welcome.

• Your “solution” works because in this example code it doesn’t matter if currentMillis is global or not.

currentMillis() needs to be in-scope wherever you need to use it. The idea is to capture the current millis() count and then do something with it immediately.

I’m not sure I understand why another part of your program would need to know the “current” value of millis… since it is very unlikely to be “current” anymore.

• Clive says:

OK, thanks. So if I define my question rather more tightly, ie “Does the way that variables are declared affect your technique for avoiding rollover?” the answer is “no, it doesn’t matter provided the relevant variables are in-scope”, right? I understand that there may be other consequences depending on the particular application, but that’s in the hands of the user.

To answer your question, I write my loops the other way round to your example, eg

if ((unsigned long)(currentMillis – previousMillis) < interval) {
call function to do stuff before the interval time is over
call another function to do more stuff before the interval time is over
}

The functions may use currentMillis for a range of purposes, eg to calculate the %age of the interval which has elapsed, etc. For my purposes the fact that the value of currentMillis is frozen for the duration of the loop iteration isn't an issue.

• Ahhh okay, got it now.

Your first statement is correct: How you declare the variables “doesn’t matter” from a functional point of view.

Now that I see what you’re doing, I take back my previous “why?” statement. Makes sense, I wasn’t being open minded enough there!

• Clive says:

No problem, would be boring if we all approached things the same way! I use the (currentmillis – previousMillis) approach all the time. Up to now I’d relied on trapping the rollover with something like ‘if (currentMillis < previousMillis) reset everything in sight and hide under the table with your fingers in your ears' but your solution is much more elegant, so many thanks for sharing it. I'll be rewriting my code to include it. I'll probably keep the 'if (currentMillis < previousMillis) reset' in there as well as it'll make me feel better…

16. I want to nitpick one thing you said:

And here’s why: if you did, it would potentially break most libraries and functions that rely on it.

But don’t the same problems happen when millis naturally rolls over? So while it may require some planning if you did it manually, it is still the same issue.

I personally would love if I could reset millis. I have a project I am designing where the attiny I am using syncs back to its host at least once a week. When it does, it gets a refreshed seconds since the epoch to calculate the current time. If I could reset the millis count when I do this (without resetting the CPU) then would simplify my code greatly. It isn’t like it is horrible right now, but it would clean things up nicely.

Now I do not recommend anyone do this, but it would be as simple as resetting three variables found in wiring.c.

Instead it is probably better to set up the watchdog timer to go off every second and increment a counter. So even if you are in low power sleep you can maintain time without a lot of current draw.

• Sorry, but I don’t agree with your points. Libraries that use millis() will use the practice of store the current time and compare to a future time.

Resetting millis() completely breaks that.

There is absolutely no reason to reset millis. Comparing a timer to a previous value is the right way to handle “roll over.”

• Please name these libraries.

I just went on a tour of several and the ones I found that stored millis did so in local variable. None of those functions would be suitable for use in a interrupt handler so the odds of them getting confused by an external change to millis is essentially nonexistent.

But you know what else I found, none of them were doing anything to handle milli rollover. So why is it ok if the get confused because of that, and not if it is though an external change?

And even if there are some libraries that have a problem with it, then they should simply document it and leave me the developer to make the choice of how to handle that. It isn’t like we don’t have to deal with that right now with things like interrupt handles, timers, etc.

To me — without hard evidence of heavily used libraries that would fail in the way you mention — your argument feels like an inversion of the Improbability Factor antipattern.

• Good feedback and you are entitled to your opinions. Mine is that there is no good reason to reset millis().

• Fair enough, though I wouldn’t mind if your clarified the opening paragraph to this post as the situation isn’t as dire as it implies. Perhaps “if you did, it would potentially break those libraries and functions that save millis() a global variable”

Since our last exchange I have scanned more libraries (around 30 in total), and I have yet to find one that would break with a reset. What I have found is that NONE of them detect and handle rollover at all (where delta time is calculated). And that is the real problem. All of of those libraries will fail in one way or another if rollover happens.

• So just to add some actual data, I did a detailed analysis of the Arduino/Wiring codebase, along with the standard libraries that come shipped with the Arduino IDE.

There is only one class that stores millis in a global variable to later comparison, and that is Stream. Carefully reading the code however shows that the four functions that take advantage of that (findUntil(), parseInt(), parseFloat(), and readBytes()) would not be vulnerable to resetting millis between Stream operations.

The only way that it could cause problems is if millis were reset in a interrupt handler, which I don’t think anyone is suggesting.

I am not trying to pile on, I just think we were both talking hypothetically and some hard data would be useful.

17. Bruce says:

It seems to me that this code simply transfers the roll-over problem from the millis() function to the waitUntil variable. The waitUntil variable holds 4294967295 values which means that for an interval of 1000 it will run out after 49.7 days. What am I missing?

• First roll-over isn’t a “problem”. It is just how millis() works.

In order to detect roll-over, it doesn’t matter what the actual maximum value either waitUntil can hold or millis() can return. The key is that they both need have the same limit. By setting the interval, even if roll-over occurs, you can detect if “interval” number of ticks have occurred.

The only limitation becomes you can’t detect more than the amount you can hold in waitUntil or millis() can return, which is 49 days. As long as your “interval” is less than 49 days, you’ll never know how many times roll-over have occurred (and you probably won’t care.)

18. Michael Wyraz says:

The code above works fine but has the disadvantage that if some processing takes too long time, the “work” next time is executed more than one time without delay.

Example:
interval=1000, waitUntil=3000, millis()=3000.
now some processing takes 5 seconds
interval=1000, waitUntil=4000, millis()=8000.
now the condition returns true until “waitUntil” reaches 8000.

So it’s better to add interval to waitUntil until the condition is false.

• James says:

Good point. While the delay will be (most likely) deterministic, it will be longer than expected. I’ll look at modifying the examples.

19. Code here and on Pastebin has been updated to the correct rollover code. Sorry for the mix-up.

20. Deskwizard says:

I’ll have a look into this, this looks like EXACTLY what I needed! 🙂

Big thanks !

21. As far as I understand your code, it will not work on a rollover. Let’s look at the case, where `counter` is close to rolling over (`counter = 250`) and `waitUntil` equals `counter`. `waitUntil` will be set to `waitUntil + interval == 250 + 47`. Because of rolling over, `waitUntil` will become `250 + 47- 256 = 41`. When the for loop checks the if condition the next time, `counter` will be 251 and the condition will give true (251 – 41 == 210 and 210 >= 0), although the wanted delay of 47 wasn’t followed.

Please correct me if I’m wrong.

• You’re right. The code as posted is incorrect. It was from an earlier revision of the post when I mixed up “correct” versus “incorrect” way. Recent reload my wp database and I forgot to update it.

Should be more along the lines of ” if ((counter – start_time) >= interval) { // check for rollover”