For those of you who have done any work with an Arduino, you have probably run across a document or video that discourages the use of the "delay" function to introduce timing breaks in your program. There is good reason to avoid its use for all but the most simplistic of programs. The main reason is that it stops everything else while the delay completes. That's known as a "blocking" function.
In this lesson, we will discuss how to use the "millis" function to get around the blocking behavior of the "delay" function. We will look at a Class that encapsulates the use of "millis" to create a general timing mechanism for your programs. Then we will extend this idea to generate an event class that will call a particular function after a timer has elapsed. These classes do not make use of interrupts or anything that qualifies as a trick. It's all straightforward and useable.
To get started, let's take a look at the classic example of how the "delay" function is used in the "blink" sketch. The program turns on an LED, delays for 1 second, turns the LED off, delays for another second and then repeats the whole thing. It looks something like this: (note -- this is a snippet not the whole program)
The "delay" function takes as an argument the delay time in milliseconds (1000ms = 1 second). The function does not return to execute the next statement until that amount of time has elapsed. When it does, the LED is turned off and the next delay begins. After that we reach the end of the loop and the whole thing starts again. Very simple.
But suppose you want to also monitor a push button so that when it is pressed, the blinking LED stops? Since most of the time is used waiting for the delays to complete, there is little opportunity to check for a button press. We need a way to continue running the program without blocking with the "delay" function.
Enter the "millis" function. When an Arduino program starts running, a millisecond timer also begins. The "millis" function is used to retrieve the number of milliseconds since the program started. In the "setup" function, millis will return the value 0. So to determine if a second has passed, you first record the current time and then periodically check to see if the difference of that recorded time minus the new current time is 1000 or more. That's the whole story.
We can modify the "blink" sketch to make use of this technique as follows:
Note that the "millis" function returns an unsigned long value. That's a 32 bit unsigned integer that can store enough milliseconds to last about 50 days. There are some applications that may require that when the millisecond timer wraps around (back to 0), that this be accounted for and dealt with. And there are ways to deal with that eventuality. But we are not concerned with that in this discussion. If you want to run something longer than 50 days you can look up how that's done.
Next time we will look at how we can build a general millisecond timer class that will make use of the millis function to work out more time based activities.
As always, questions and comments are welcome.
-- Leo