Introduction
The following article is about my simplest library that I wrote for the arduino: SoftTimers. The SoftTimers arduino library allows one to properly time multiple events and know when each “timer” expires meaning that an action is required.
Skip to the download section for quick download.
When I first learned programming the arduino, I learned the “hello world” of the arduino: turning a LED on and off. As expected, I used delay()
to define how long the LED should be on and off.
However, this approach is bad since it break the “realtime” property of the software to react to other event. If I want to make the LED instantly turn off when pressing a button, I had to wait for the delay to complete before processing the button. (I know you could use interrupts and update with LED pin within the interrupt but that is out of scope for now.)
Another issue is extensibility. Making 3 LEDs blink at different time interval is much harder with delays. How about 40 LEDs? Impossible?
This is where SoftTimers arduino library becomes helpful.
Purpose
The SoftTimers allows one to properly time multiple events and know when each “timer” expires meaning that an action is required. In this example above, a SoftTimer expires when it is time to toggle an LED.
SoftTimers also provide the elapsed time since an event occurred. In case of an interruption, the elapsed time can be used as debugging information. It can also be used as a countdown information displayed to the user.
The library regroups basic timer functionalities into a single class. The usual way to get the same functionality is to create multiple variables for each single timer. This way is hard to maintain when you need multiple timers are required to run at the same time.
SoftTimer classes are designed to be keep “simple & stupid”. No software interrupts. Non-blocking. Each timer must be polled within the loop() to know their status.
Library features
Here is a list of all library features:
- Provides the non-blocking equivalent to blocking
delay()
function. - Each timers encapsulate its own expiration (timeout) time.
- Provides elapsed time, remaining time and progress (in percentage) APIs.
- Supports milliseconds, microseconds or any other arbitrary time with external time counting function.
- Provides expiration loop count API (as if timer never expire and automatically
reset()
) to easily implement toggling, and time based state machines. - Automatically handles
micros()
anmillis()
overflows / wrap around special cases.
Usage
Basic Usage
Call setTimeOutTime()
to setup the non-blocking SoftTimer then call reset()
to restart the internal counter.
Within the loop()
, use hasTimedOut()
to know if the timer has expired.
At any moment, call getElapsedTime()
to get the absolute elapsed time since the last reset()
.
Fade a LED
Fading a LED like arduino’s Built-in Fade Example is trivial using SoftTimers. The library helps in defining the constant speed at which the LED will fade by defining the total length of the process and by easily mapping the timer “progress” to the amount of fade (PWM) used with the output pin. All of this in a non-blocking manner.
The following example increases the intensity of a LED from OFF to ON in 1 second and then decreases the intensity of the LED back to OFF in 1 second.
Demo
Click the following to download the example below:
(download
Fade a LED example.ino)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include <SoftTimers.h> #define LED_PIN 9 /************************************************** *Fade a LED as the Fade basic example: *Increse the intensity of a LED from OFF to ON in 1 seconds *then ON to OFF in 1 seconds **************************************************/ SoftTimer fadeTimer; //millisecond timer void setup() { pinMode(LED_PIN, OUTPUT); Serial.begin(115200); //update timers fadeTimer.setTimeOutTime(1000); // every 1 second. //start counting fadeTimer.reset(); } void loop() { //determine the direction of brightness int direction = fadeTimer.getLoopCount() % 2; //returns 0 or 1 bool increasing = (direction == 0); //assign increasing brightness with direction 0 //get progress double progress = fadeTimer.getLoopProgress(); //correct progress based on direction if (!increasing) { progress = 1.0 - progress; } //map progress to a 0-255 brightness intensity. uint16_t brightness = progress*255; //update the LED analogWrite(LED_PIN, brightness); } |
Countdown or Elapsed time
Any program that need to display a countdown or compute the elapsed time between two events can also benefit from SoftTimers.
The following example runs a countdown of 5 seconds and then turns a LED on.
Demo
Click the following to download the example below:
(download
Countdown example.ino)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#include <SoftTimers.h> #define LED_PIN 13 /************************************************** * Run a countdown from 5 second to 0 and turn LED on **************************************************/ SoftTimer countdown; //millisecond timer void setup() { pinMode(LED_PIN, OUTPUT); Serial.begin(115200); //update timers countdown.setTimeOutTime(5000); // 5 seconds //start counting now countdown.reset(); } void loop() { if (!countdown.hasTimedOut()) { //show user how much time left in milliseconds uint32_t remaining = countdown.getRemainingTime(); Serial.print(remaining); Serial.println(" ms..."); } else { //turn ON the LED digitalWrite(LED_PIN, HIGH); } } |
Timed repetitive cycles
SoftTimer library also help reducing repetitive timed cycles to their simplest non-blocking form. SoftTimer library automatically computes current cycle index. Any toggling or cycle scenarios can be implemented with very few lines of code.
The following example implements a system where a single HIGH pin must be cycled every second within multiple pins as defined by the following loop:
- set pin 8, 9 and 13 to LOW, LOW and HIGH respectively and then wait 1 second.
- set pin 8, 9 and 13 to HIGH, LOW and LOW respectively and then wait 1 second.
- set pin 8, 9 and 13 to LOW, HIGH and LOW respectively and then wait 1 second.
- repeat the cycle forever…
Demo
Click the following to download the example below:
(download
Cycle a High pin example.ino)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#include <SoftTimers.h> #define LED_PIN_0 13 #define LED_PIN_1 8 #define LED_PIN_2 9 /************************************************** *Every second, cycle the HIGH pin within pins 13,8,9 **************************************************/ SoftTimer cyclePinTimer; //millisecond timer void setup() { pinMode(LED_PIN_0, OUTPUT); pinMode(LED_PIN_1, OUTPUT); pinMode(LED_PIN_2, OUTPUT); Serial.begin(115200); //update timers cyclePinTimer.setTimeOutTime(1000); // every 1 second. //start counting cyclePinTimer.reset(); } void loop() { uint32_t loopCount = cyclePinTimer.getLoopCount(); uint32_t pinHighNumber = (loopCount % 3); //from 0 to 2 if (pinHighNumber == 0) { //turn ON the LED 0, turn OFF all other digitalWrite(LED_PIN_0, HIGH); digitalWrite(LED_PIN_1, LOW); digitalWrite(LED_PIN_2, LOW); } else if (pinHighNumber == 1) { //turn ON the LED 1, turn OFF all other digitalWrite(LED_PIN_0, LOW); digitalWrite(LED_PIN_1, HIGH); digitalWrite(LED_PIN_2, LOW); } else //if (pinHighNumber == 2) { //turn ON the LED 2, turn OFF all other digitalWrite(LED_PIN_0, LOW); digitalWrite(LED_PIN_1, LOW); digitalWrite(LED_PIN_2, HIGH); } } |
Timed restricted state machines
SoftTimer library allows one to make an easy abstraction of time when dealing with timed restricted state machines.
The following example implement an hypothetical state machine where each state has a maximum duration:
- State #1 – IDLE (1000 ms)
- State #2 – LISTENING (200 ms)
- State #3 – SYNCHRONIZING (500 ms)
- State #4 – UPDATING (300 ms)
- State #1 ….
Demo
Click the following to download the example below:
(download
State Machine example.ino)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
#include <SoftTimers.h> /************************************************** * An hypothetical state machine needs to step from * state to state. Each state has its own maximum * duration: * State #1 - IDLE (1000 ms) * State #2 - LISTENING (200 ms) * State #3 - SYNCHRONIZING (500 ms) * State #4 - UPDATING (300 ms) * State #1 ... **************************************************/ SoftTimer nextStateTimer; //millisecond timer const int STATE_IDLE = 0; const int STATE_LISTENING = 1; const int STATE_SYNCHRONIZING = 2; const int STATE_UPDATING = 3; int state = STATE_IDLE; void setup() { Serial.begin(115200); //update timers nextStateTimer.setTimeOutTime(1000); // IDLE, 1 second. //start counting now nextStateTimer.reset(); } void loop() { //show current state switch(state) { case STATE_IDLE: Serial.println("IDLE"); break; case STATE_LISTENING: Serial.println("LISTENING"); break; case STATE_SYNCHRONIZING: Serial.println("SYNCHRONIZING"); break; case STATE_UPDATING: Serial.println("UPDATING"); break; default: Serial.println("UNKNOWN STATE!"); break; }; //look for next state... if (nextStateTimer.hasTimedOut()) { state++; //limit state to known states state = state%(STATE_UPDATING+1); //reconfugure time based on new state switch(state) { case STATE_IDLE: nextStateTimer.setTimeOutTime(1000); break; case STATE_LISTENING: nextStateTimer.setTimeOutTime(200); break; case STATE_SYNCHRONIZING: nextStateTimer.setTimeOutTime(500); break; case STATE_UPDATING: nextStateTimer.setTimeOutTime(300); break; default: Serial.println("UNKNOWN STATE!"); break; }; //start counting now nextStateTimer.reset(); } //hypothetical work... //processState() } |
License
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License (LGPL-3.0) for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
DISCLAIMER:
This software is furnished “as is”, without technical support, and with no warranty, express or implied, as to its usefulness for any purpose.
Download
You can download the SoftTimers arduino library by clicking on the following link: