The problem with delay() is that your code is stuck waiting for the time to elapse. What if you wanted to do something more in that time? There are places where you don’t need to do anything with your processor resource but more often then not, you need to be doing something useful. The IsTime() function introduced lets you use all that time to do more things.
This is the first of two related articles. First we discuss the limitations associated with using delay() type functions and introduces the IsTime() solution. The second article will introduce the PolledTimer library which simplifies things even more.
In the Arduino blink sketch is a basic microcontroller “hello world” example where its perfectly OK to use the delay() method as there really is nothing else to do.
In the loop() function of the “blink” sketch we see delay() used twice to wait for one second each. The digitalWrite() functions are turning on and off an LED between these waits. The result is a flashing LED that is on then off for one second. This makes a perfect “hello world” example as its very clear and easy to understand. delay() is used well here as there is nothing else we want to do with the processor.
But what if we want to do other things? Say for example we are reading the state of a switch or some signal, perhaps a temperature reading that we are watching. We want to flash the warning LED on our gizmo but we also need to keep watching the temperature? One idea might be to delay() some, then turn on the LED and make a measurement to check if we still need to flash, then delay() again, then turn off the LED and do measurement check again. The code below is not real, its just a bit of pseudo code for illustration.
As you can see the code above is much more complicated but there is a good reason for this. The code as been separated into two tasks, checking the temperature and flashing the LED. Also note that there is no delay, instead we have a function called flashTime() that indicates when its time to do a LED change (toggle for flashing).
The flashTime() function could just be a delay() and return true. But it could also check how long its been and return true if more then 1 second has elapsed. If it did that, then the loop() function would cycle very fast, there would be no delay(), instead there would be some code that keeps track of time inside the flashTime() method. You would be checking the temperature very quickly while the LED was flashing. You could do a lot of things in that time.
There are some problems with writing a function like flashTime() for every task you might have. Considering that all these functions would basically be identical except for some timing variables, it should be easy to create one generic function and pass in some variables specific to each task.
My first solution to having a simple method to keep track of timing was the IsTime() function. Later, I made a class with more features which I’ve included in the PolledTimer library discussed later. IsTime() is shown below.
Two parameters are passed to IsTime(). “timeMark” is a pointer to a long integer, where the last time mark value is stored. This is the reference time used to measure against. “timeInterval” is an interval time in milliseconds. Its how long you want to wait before IsTime() returns true.
IsTime() might seem a bit complex but its basically using the Arduino millis() method to get a millisecond time value which starts at 0 and counts up once each millisecond. Since the millisecond value could overflow, IsTime() checks for and deals with that.
Update: An astute visitor points out that the roll over check code is not needed. The math would work regardless as the long int would overflow to the same result. I will make this change to my code library.
Modified Blink Example
Here we add the IsTime() code shown above, a few variables and we rewrite the loop() function to use IsTime() function to control the LED flash. The code snippet below contains only the changed loop function. There are some links after the code to a fully functional code file.
The code comments describe what’s going on in the code. The key here is that we are not using any delay() functions so the loop executes without waiting. We can add other things to the loop now, but we have to use IsTime() rather then delay() as the delay will again stop things from happening and that could include the IsTime() controlled code. This is one of the reasons most multi-tasking operating systems are pre-emptive, but that is too big of a subject to tackle now. This article is already too long…
To add another LED or task to this loop we only need to add the timemark and timeInterval variables for each. Then use the isTime() function again. For example to flash a second LED at a different rate we could do this…
Now we are flashing two LEDs, at different rates, and we still have almost 100% of the processor available to do other things!
- Modified Blink Sketch This is a text file that will open in your browser. Copy this to a new Arduino sketch to run.
- Simular method in the Arduino tutorials
- tmr module in the piconomic library
- Interrupts article at uCHobby
- Wikipedia article on polling
- Another IsTime function
As always, tell us what you think with a comment. We love to read them. Let us know if there are similar articles out there, I might update this article to add more resource links once they are discovered.