Skip to content
Gambit120 edited this page Feb 11, 2022 · 8 revisions

Using elapsedMillis & elapsedMicros

These special variable types automatically increase as time elapses. It's easy to check if a certain time has elapsed, while your program performs other work or checks for user input.

Interval variable type

When using a variable to set or store your delay intervals, you need to keep in mind how big a number the various variables, else there may be overflow, and the interval not be what you intend, or may not work at all! A 16 bit int (i.e. Arduino Uno, Mega) will roll over if use a number bigger than 32,767 - or 32.7 seconds! What it rolls over to depends upon whether you are using a signed or unsigned data type. A signed data type will roll over to the most negative number that data type can store - i.e. -32,768 for a 16 bit unsigned int. If it is a unsigned data, such as an 16bit unsigned int, it can store a number as large as 65,535, and will roll over to 0. If you need a larger delay than 65,536 milliseconds (65.5 seconds), you will need to use an unsigned long, which will allow for delays of up to 49.7 days! Check out the Arduino Reference documentation on variables for more information on this topic.

Responsiveness To User Input

When using delay(), your code can not respond to user input while the delay is happening. In this example, a pushbutton has quick response, but a task is performed every 2.5 seconds.

#include <Bounce.h>
#include <elapsedMillis.h>

Bounce myButton = Bounce(2, 10); // pushbutton on pin 2
elapsedMillis sincePrint;

void setup() 
{
    Serial.begin(9600);
    pinMode(2, INPUT_PULLUP);
}
void loop() 
{
    myButton.update();
    if (myButton.fallingEdge()) 
    {
        Serial.println("Button Press"); 
    }
    if (myButton.risingEdge()) 
    {
        Serial.println("Button Release");
    }
    if (sincePrint > 2500) // "sincePrint" auto-increases
    {      
        sincePrint = 0;
        Serial.println("Print every 2.5 seconds");
    }
}

Repeating Multiple Tasks At Regular Intervals

You can repeat a task at regular intervals by checking if enough time has elapsed since the task was performed last. In this example, 3 lines are printed, each at its own interval. Computing the correct delay() numbers for this sequence would be difficult!

// create elapsedMillis outside loop(), to
// retain its value each time loop() runs.
#include <elapsedMillis.h>

elapsedMillis sinceTest1;
elapsedMillis sinceTest2;
elapsedMillis sinceTest3;

void setup() 
{
    Serial.begin(9600);
}

void loop() 
{
    if (sinceTest1 >= 1000) 
    {
        sinceTest1 = sinceTest1 - 1000;
        Serial.println("Test1 (1 sec)");
    }
    if (sinceTest2 >= 2700) 
    {
        sinceTest2 = sinceTest2 - 2700;
        Serial.println("             Test2 (2.7 sec)");
    }
    if (sinceTest3 >= 1300) 
    {
        sinceTest3 = sinceTest3 - 1300;
        Serial.println("                            Test3 (1.3 sec)");
    }
}

In this example, each interval is substracted from the elapsed time, which automatically adjusts for any latency. Imagine if the Serial.println() for Test1 takes more than 4 ms, and during that time sinceTest2 increases to 2704. Because 2700 is substracted, it will start over at 4, so the next Test2 may print 4 ms early, aligned to the original schedule.

If you do not care about maintaining the original schedule, or the time between events must not be less than intended, you would set the variable back to zero instead of substracting.

Timeout Waiting For Input

When waiting for input, especially data from a computer, usually it's good to give up after a "timeout". Using elapsedMillis makes this easy.

void loop()     // each time loop() runs,
{                
    elapsedMillis waiting;     // "waiting" starts at zero
    while (waiting < 1000) 
    {
        if (Serial.available()) 
        {
            char c = Serial.read();
            Serial.print("got char = ");  // do something with c
            Serial.println(c);
            waiting = 0;           // reset waiting back to zero
        }
    }
    
    Serial.println("waited 1 second, no data arrived");  
}

When elapsedMillis is created as a local variable (inside the function), it automatically starts at zero each time the function executes.

Avoid Timing Pitfalls

Both elapsedMillis and elapsedMicros can increase by more than 1 count. Therefore, equality compare "==" is never a good approach. Such a program may usually work, but could fail on rare and random circumstances. Checking should always be done with ">" or "<" or ">=" or "<=".

System Time: millis() & micros()

Internally, elapsedMillis and elapsedMicros use millis and micros. They handle roll over automatically, and are much easier to use.

Acknowledgements

The initial content for this page was directly based (read copied) from the Teensyduino Delay and Timing Functions reference page, mainly due to the fact that this is a port of that functionality for the Arduino platform.