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.

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>
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 as 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.
elapsedMillis sinceTest1;
elapsedMillis sinceTest2;
elapsedMillis sinceTest3;

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 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 intead 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 "<=".

The elapsedMillis feature is built into Teensyduino. For non-Teensy boards, it is available as a library.