2. Timers Using elapsedMillis
Lets start at the end with the two working examples that don't have problems. These working
examples are based on elapsedMillis by Paul Stoffregen, one for a repeating timer and one for
a once off timer.
Follow those two examples are working alternatives that don't use the elapsedMillis library.
First install the elapsedMillis library. Downloaded the elapsedMillis.zip file.
Unzip this file to your Arduino/libraries directory (open the IDE File->preferences window
to see where your local Arduino directory is).
Some times the instructions for How to Install a Library - Automatic installation work, but
not always. Unzipping the file manually is safest.
A Repeating Timer using elapsedMillis
This is a simple example of a repeating timer
#include <elapsedMillis.h>
// see warning above about FioV3
int led = 13;
// Pin 13 has an LED connected on most Arduino boards.
// if using Arduino IDE 1.5 or above you can use pre-defined
// LED_BUILTIN instead of 'led'
//
elapsedMillis timer0;
#define interval 1000
// the interval in mS
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
timer0 = 0; // clear the timer at the end of startup
}
void loop() {
if (timer0 > interval) {
timer0 -= interval; //reset the timer
int ledPin = digitalRead(led);
// read the current state and write the opposite
digitalWrite(led, !ledPin);
}
}
The code above loop() continues to run without being stuck waiting for the delay to expire.
During each pass of the loop(), a timeout interval is compared to a free running timer.
When the timer exceeds the value of the interval the desired action is taken (in this example
change the state of the LED) and the timer is reset.
3. The reason for using
timer0 -= interval; //reset the timer
is that it allows for the possibility that the timer just happened to be incremented
between testing it
if (timer0 > interval) {
and resetting it
timer0 -= interval; //reset the timer
or if there is some other delay the prevents the main loop from running every milli-
second. (See the Adding a Loop Montor below)
Using timer0 -= interval; also gives you the option of varying the timing
interval.
Another point is to clear timer0 at the end of startup(), using
timer0 = 0;
This ensures the timer is accurate at the start of the loop(), even if startup() takes some time
to execute.
A Once Off Timer using elapsedMillis
If you only want the timer to fire once and never again you need to add a guard boolean to
prevent code being executed again after the timer has fired
#include <elapsedMillis.h>
// see warning above about FioV3
int led = 13;
// Pin 13 has an LED connected on most Arduino boards.
// if using Arduino IDE 1.5 or above you can use pre-defined
// LED_BUILTIN instead of 'led'
//
elapsedMillis timer0;
#define interval 5000
// the interval in mS
boolean timer0Fired;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
digitalWrite(led, HIGH);
timer0Fired = false;
timer0 = 0; // clear the timer at the end of startup
}
void loop() {
if ((!timer0Fired) && (timer0 > interval)) {
timer0Fired = true; // don't execute this again
digitalWrite(led, LOW); // turn led off after 5 sec
}
4. }
Also see http://playground.arduino.cc//Code/ElapsedMillis
Code Alternatives to using ElapsedMillis
Here are two code examples that do not used ElapsedMillis.
RepeatingTimer
The following sketch shows a simple repeating timer. You can download the sketch
from RepeatingTimer.ino
int led = 13;
unsigned long timer; // the timer
unsigned long INTERVAL = 1000; // the repeat interval
void setup() {
pinMode(led, OUTPUT); // initialize LED output
timer = millis(); // start timer
}
void loop() {
if ((millis()-timer) > INTERVAL) {
// timed out
timer += INTERVAL;// reset timer by moving it along to the
next interval
// toggle led
if (digitalRead(led)) {
digitalWrite(led, LOW); // turn the LED off by making the
voltage LOW
} else {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the
voltage level)
}
}
}
SingleShotTimer
This sketch shows a simple single shot timer. You can download the sketch
from SingleShotTimer.ino
int led = 13;
unsigned long timer; // the timer
boolean timedOut = false; // set to true when timer fired
unsigned long INTERVAL = 5000; // the timeout interval
void setup() {
5. pinMode(led, OUTPUT); // initialize LED output
timedOut = false; // allow timer to fire
timer = millis(); // start timer
}
void loop() {
// this will toggle the led ONCE only after 5sec (timeOut)
if ((!timedOut) && ((millis() - timer) > INTERVAL)) {
// timed out
timedOut = true; // don't do this again
// you can reset the single shot timer by setting
// timedOut = false;
// timer = millis();
// toggle led
if (digitalRead(led)) {
digitalWrite(led, LOW); // turn the LED off by making the
voltage LOW
} else {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the
voltage level)
}
}
}
Code Examples to be Avoided
SimpleBlink ExampleusingDelay
Many of the sample Arduino programs are seductively simple. Take the Blink example
// Initial code attempt
int led = 13; // don't use on FioV3 when battery connected
// Pin 13 has an LED connected on most Arduino boards.
// if using Arduino IDE 1.5 or above you can use pre-defined
// LED_BUILTIN instead of 'led'
//
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the
voltage level)
delay(1000); // wait for a second
6. digitalWrite(led, LOW); // turn the LED off by making the
voltage LOW
delay(1000); // wait for a second
}
The problem with this example is that the CPU is stuck waiting in the delay
function.
delay(1000);
If you try and add more code to the loop() you will find it is very slow to execute.
So the first point is:-
Don't use delay( )
Second Attemptto Blink,without Delay
But if you don't use delay what are the alternatives. Well Arduino provides a
millis() method that returns the number of milli Seconds since the last uC reset.
Using this method we can code this second attempt at a delay.
// Second attempt
int led = 13; // don't use on FioV3 when battery connected
// Pin 13 has an LED connected on most Arduino boards.
// if using Arduino IDE 1.5 or above you can use pre-defined
// LED_BUILTIN instead of 'led'
//
unsigned long timeout;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
timeout = millis();
}
// the loop routine runs over and over again forever:
void loop() {
if (millis() > timeout) { // WARNING – this has problems as discussed
below
// time to toggle the Led
timeout += 1000;
if (digitalRead(led)) {
digitalWrite(led, LOW); // turn the LED off by making the
voltage LOW
} else {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the
voltage level)
}
}
}
7. Now there are no delays in the main loop() and your other code will be run
promptly.
However all it not good with this solution.
The second attempt above has a failing. About 50 days after the Arduino board is
reset, millis() goes back to counting from 0. This is because the 32bits used to store
the value overflow and start counting from zero again. See theArduino reference
description for millis(). The timeout variable is also 32bits and so eventually
timeout + 1000 will overflow and become a small number. What this means is that
for about 1 second every 50 days
if (millis() > timeout) {
will be true every loop and the led will flash at a very high rate for that second until
millis() over flows back to a small number as well.
For a blinking led this may not be a problem but in a real application it could cause
damage every 50 days when the timers stop working as expected.
If you are just interested in a repeating timer then
see http://arduino.cc/en/Tutorial/BlinkWithoutDelay for a simple reliable repeating
timer which does not count down. The code below works because even
if currentMillisoverflows back to a small number, currentMillis –
previousMillis still gives the correct result.
void loop() {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis> interval) {
// save the last time
previousMillis = currentMillis;
// do stuff here each interval (interval -- an unsigned
long)
...
}
AlmostFinal solution to Blink withoutDelay
The almost final solution involves a very small but significant change to the code.
Replace
if (millis() > timeout) { // WARNING – this has problems as discussed below
with
if (millis() == timeout) { // this works if loop() takes <1mS to execute
So the code becomes
// Final solution code
8. int led = 13; // don't use on FioV3 when battery connected
// Pin 13 has an LED connected on most Arduino boards.
// if using Arduino IDE 1.5 or above you can use pre-defined
// LED_BUILTIN instead of 'led'
//
unsigned long timeout;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
timeout = millis();
}
// the loop routine runs over and over again forever:
void loop() {
if (millis() == timeout) { // NOTE: the == only toggle led when millis()
equals timeout
// time to toggle the Led
timeout += 1000;
if (digitalRead(led)) {
digitalWrite(led, LOW); // turn the LED off by making the
voltage LOW
} else {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the
voltage level)
}
}
}
This code works because when timeout + 1000 overflows, millis() will not equal it
until millis() also overflows.
Word of Warning – Add a loop monitor
The almost final solution presented above does have one dependency. That is the
main loop() must execute at lease once every 1mS, otherwise you may miss the
exact milliSecond when millis() == timeout.
This means you must not have any other delay()'s in you program what would
prevent the loop() from running at least once every 1mS. Unfortunately many of
the standard Arduino libraries use delay() or introduce pauses, such as AnalogRead
and SoftwareSerial. Usually the delay these introduce are small but they can add
up so I suggest you add a monitor at the top of your loop() to check how quickly it
runs.
The loop monitor is very similar to the blink example. A small piece of code at the
top of the loop() method just toggles the Led each time loop() is executed. You can
then use a digital multimeter with at Hz scale to measure the frequency of the
output on the LED pin (pin 13 in this case)
9. The code is:-
// Loop Monitor – this checks that the loop() is executed at
least once every 1mS
// (c)2013 Forward Computing and Control Pty. Ltd.
// www.forward.com.au
//
// This example code is in the public domain.
int led = 13; // don't use on FioV3 when battery connected
// Pin 13 has an LED connected on most Arduino boards.
// if using Arduino IDE 1.5 or above you can use pre-defined
// LED_BUILTIN instead of 'led'
//
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
// add your other setup code here
}
// the loop routine runs over and over again forever:
void loop() {
// toggle the led output each loop The led frequency must
measure >500Hz (i.e. <1mS off and <1mS on)
if (digitalRead(led)) {
digitalWrite(led, LOW); // turn the LED off by making the
voltage LOW
} else {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the
voltage level)
}
// add the rest of your loop code here
}
You can download the monitor code here. When I run this code on my Uno board
the multiMeter on the Hz range connected between pin 13 and GND reads
57.6Khz. i.e. about 100 times >500hz. As you add your code to loop() the Hz
reading will reduce. Just check it stays well above 500Hz in all situations.
Final Solution for Reliable CountDown Timers
(Note: this code has been supersededby the elapsedMilliscode at
the top of this page)
This last example shows how to code count down timers, both repeating and one
off, that will reliably execute even if loop() takes more the 1mS to execute.
10. The idea is to capture the number of millis() that have gone by since the last loop()
and use that number to decrement your timers. This code can be downloaded from
here. As noted above seehttp://arduino.cc/en/Tutorial/BlinkWithoutDelay for an
alternative simple reliable repeating timer which does not count down.
/*
Robust Timer
(c)Forward Computing and Control Pty. Ltd.
Works even if sometimes the loop() takes longer the 1mS to
execute.
This example code is in the public domain.
*/
static unsigned long lastMillis = 0; // holds the last read
millis()
static int timer_1 = 0; // a repeating timer max time 32768 mS
= 32sec use a long if you need a longer timer
// NOTE timer MUST be a signed number int or long as the code
relies on timer_1 being able to be negative
// NOTE timer_1 is a signed int
#define TIMER_INTERVAL_1 2000
// 2S interval
static int timer_2 = 0; // a one off timer max time 32768 mS =
32sec use a long if you need a longer timer
// NOTE timer MUST be a signed number int or long as the code
relies on timer_2 being able to be negative
// NOTE timer_2 is a signed int
#define TIMER_INTERVAL_2 5000
// 5 sec interval
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
timer_1 = TIMER_INTERVAL_1; // timeout in first loop
timer_2 = TIMER_INTERVAL_2; // set up one off timer times out
in 10 sec
Serial.begin(9600);
while (Serial.available()) {
}
Serial.println("Timer Begin");
lastMillis = millis(); // do this last in setup
}
// the loop routine runs over and over again forever:
void loop() {
// set millisTick at the top of each loop if and only if
millis() has changed
unsigned long deltaMillis = 0; // clear last result
unsigned long thisMillis = millis();
11. // do this just once to prevent getting different answers from multiple
calls to millis()
if (thisMillis != lastMillis) {
// we have ticked over
// calculate how many millis have gone past
deltaMillis = thisMillis-lastMillis; // note this works even
if millis() has rolled over back to 0
lastMillis = thisMillis;
}
// handle one off timer
// repeat this code for each timer you need to handle
if (timer_2 > 0) { // still counting down
timer_2 -= deltaMillis;
if (timer_2 <= 0) {
// timer timed out
// do timeout stuff here
// in this set the led HIGH
Serial.println("Timer 2 timed out");
}
}
// handle repeating timer
// repeat this code for each timer you need to handle
timer_1 -= deltaMillis;
if (timer_1 <= 0) {
// reset timer since this is a repeating timer
timer_1 += TIMER_INTERVAL_1; // note this prevents the
delay accumulating if we miss a mS or two
// if we want exactly 1000 delay to next time even if this
one was late then just use timeOut = 1000;
// do time out stuff here
Serial.println("Repeating Timer 1 timed out");
}
}
Note that for the one off timer, timer_2, we first check if the timer is >0 before
subtracting the deltaMillis so that we only process the timeout once.
For the repeating timer, timer_1, we just subtract the deltaMillis every time, but
most of the time deltaMillis will be 0.
So for both types of timers, you can also add a check for deltaMillis > 0 and skip
all the timer code except for those times when the mS ticks over. i.e.
if (deltaMillis> 0) {
// handle one off timer
// repeat this code for each timer you need to handle
.. etc
12. // handle repeating timer
// repeat this code for each timer you need to handle
.. etc
}
For use of the Arduino name see http://arduino.cc/en/Main/F