Introduction

You need to worry about this if your arduino is going to be powered for more than 49 days, if not below are good practices to follow when using millis() function that avoid overflow.

If you do things right, you don’t have to worry about millis() overflow. The trick is to handle overflow.

What is millis() function?

millis() function return the time in millisecond since arduino was powered up. Sometimes also refered as arduino time in forums. this function returns unsigned long integer which is a 32 bit number which can hold up 0 to 4,294,967,295 (2^32 – 1). The maximum number will reach after 49.710 days (2^32/1000/60/60/24) after it will roll back to zero. Nothing really happens when this timer rolls over, the processor doesn’t reset not lock up, the timer will still keep on ticking just like it was before overflow. You might be tempted to reset the millis() timer so things are more in your control, well you can but there is no reason to do so, you might break some libraries. If you are making a clock it is not recommended to use this function for time keeping, rather use RTC unless you want to set time every time when power cycles which defeats the purpose of a clock.

Lets look at bad way of using millis() function

Directly comparing two time stamps

unsigned long t1 = millis(); delay(5000); unsigned long t2 = millis(); if (t2 > t1) { //do something } 1 2 3 4 5 6 unsigned long t1 = millis ( ) ; delay ( 5000 ) ; unsigned long t2 = millis ( ) ; if ( t2 > t1 ) { //do something }

Now above will always be true, but not if during the delay the millis() overflows.

Other method is to compare duration.

Example of Adding(Not recommended)

unsigned long startTime = millis (); unsigned long whenToStop = startTime + 60000; if (millis () >= whenToStop){ // do something } 1 2 3 4 5 6 unsigned long startTime = millis ( ) ; unsigned long whenToStop = startTime + 60000 ; if ( millis ( ) >= whenToStop ) { // do something }

This will work most of the time, but not when overflow occurs, lets say millis() overflows in 30 seconds, the condition will become true and instead of waiting 60 seconds, it will stop waiting as soon as timer overflows.

Using Subtraction(Recommended)

unsigned long startTime = millis (); unsigned long interval = 60000; ... if (millis () - startTime >= interval) { // do something } 1 2 3 4 5 6 7 8 9 unsigned long startTime = millis ( ) ; unsigned long interval = 60000 ; . . . if ( millis ( ) - startTime >= interval ) { // do something }

The above code will work every time even if the timer overflows, the reason is because of how binary arithmetic works.

Now if you want to test your code at millis() overflow either wait 49 days which you probably won’t or use below code can be used to set the millis timer with a high value so it will overflow in couple of seconds.

This code is purely for testing purpose only.

#include <util/atomic.h> void setMillis(unsigned long ms) { extern unsigned long timer0_millis; ATOMIC_BLOCK (ATOMIC_RESTORESTATE) { timer0_millis = ms; } } 1 2 3 4 5 6 7 8 9 #include <util/atomic.h> void setMillis ( unsigned long ms ) { extern unsigned long timer0_millis ; ATOMIC _ BLOCK ( ATOMIC_RESTORESTATE ) { timer0_millis = ms ; } }

Sketch for testing millis() overflow

#include <util/atomic.h> void setMillis(unsigned long ms){ extern unsigned long timer0_millis; ATOMIC_BLOCK (ATOMIC_RESTORESTATE) { timer0_millis = ms; } } const int ledPin = 13; // the number of the LED pin // Variables will change : int ledState = LOW; // ledState used to set the LED // Generally, you shuould use "unsigned long" for variables that hold time // The value will quickly become too large for an int to store unsigned long previousMillis = 0; // will store last time LED was updated long start; const long interval = 6000; // interval at which to blink (milliseconds) void setup(){ // set the digital pin as output: pinMode(ledPin, OUTPUT); Serial.begin(115200); } void loop(){ setMillis(4294963295); //max value 4294967295 start = millis(); while (millis() - start <= interval){ //millis will overflow in this loop digitalWrite(ledPin, HIGH); delay(100); digitalWrite(ledPin, LOW); delay(100); Serial.println(millis()); } delay(2000); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <util/atomic.h> void setMillis ( unsigned long ms ) { extern unsigned long timer0_millis ; ATOMIC _ BLOCK ( ATOMIC_RESTORESTATE ) { timer0_millis = ms ; } } const int ledPin = 13 ; // the number of the LED pin // Variables will change : int ledState = LOW ; // ledState used to set the LED // Generally, you shuould use "unsigned long" for variables that hold time // The value will quickly become too large for an int to store unsigned long previousMillis = 0 ; // will store last time LED was updated long start ; const long interval = 6000 ; // interval at which to blink (milliseconds) void setup ( ) { // set the digital pin as output: pinMode ( ledPin , OUTPUT ) ; Serial . begin ( 115200 ) ; } void loop ( ) { setMillis ( 4294963295 ) ; //max value 4294967295 start = millis ( ) ; while ( millis ( ) - start <= interval ) { //millis will overflow in this loop digitalWrite ( ledPin , HIGH ) ; delay ( 100 ) ; digitalWrite ( ledPin , LOW ) ; delay ( 100 ) ; Serial . println ( millis ( ) ) ; } delay ( 2000 ) ; }

Same technique should be used for micros() function which records microsecond since arduino was powered. It wraps around rather quickly in 71.58 minutes.

Resources:

http://www.gammon.com.au/millis

http://playground.arduino.cc/Code/TimingRollover

http://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover

Featured Photo credit:http://www.freepik.com/free-vector/time-and-clocks-icons_761530.htm