This is a basic OOP timer implementation for easy low-level handling of schedules or repetitive tasks on embedded hardware. Scroll down for a meaningful example.
The code is designed to provide an easy and intuitive interface and therefore help you develop quickly and without pain. To use it, simply create a Timer object and think of it as a stopwatch: You can start, stop, set a desired total duration or check the elapsed time at any time.
Each timer internally uses uint32_t
values as returned by millis()
to store
the duration and starting time. Given this technical limitation, any duration of
up to almost 50 days (4,294,967,295 ms) can be handled, which should be
sufficient for most task running on embedded hardware.
Pro tip: The method
checkAndRestart()
comes in very handy when creating a repetitive task. Used as a one-liner with an if-clause, it checks whether it's time to perform a specific task or not, and if so, it automatically restarts the timer for the next run. Nice. 🎉
The timer module is non-blocking. It has a very simple structure and since
only discrete time events are captured, there's no need for a periodically
called tick()
method or something similar. Plus, timer objects automatically
handle timestamp subtraction/overflow on their own. I thus find it very
handy and often use it in my private projects when it comes down to timing
several tasks on a microcontroller etc.
All Timer objects created a compile time or runtime are independent of each other; you can create as much of them as you need (or your RAM can hold).
Thinking of a simple stopwatch, each timer object provides a fairly intuitive interface.
Timer
(constructor): Creates a Timer object. If a duration is provided as argument, it will be immediately applied. (However, the timer will not be started yet.)set/getDuration
: Sets or gets the desired duration asuint32_t
in ms for this timer.start
: The most important function: Starts the timer. Has no effect on a timer that's already running. If a duration is provided as argument, it will be set accordingly. Returnstrue
if the timer was successfully started, otherwisefalse
.restart
: Acts exactly like thestart
method, but (re)starts the timer even if it was already running.reset
: Stops the timer, keeping the configured duration.check
: Returnstrue
if the timer is running and the elapsed time since start exceeds the specified duration, otherwisefalse
.checkAndRestart
: Acts exactly like thecheck
method. If the result wastrue
, the timer will be immediately restarted. Perfect for cyclic tasks.isRunning
: Returnstrue
if a duration was set and the timer was started, otherwisefalse
.isSet
: Returnstrue
if a duration was set.getStartTime
: Returns the time value asuint32_t
captured when the timer was started in ms.getElapsedTime
: Returns the total elapsed time difference since the timer was started asuint32_t
in ms.getElapsedTimeRel
: Returns the relative elapsed time difference since the timer was started asfloat
in a range from 0 to 1 (0% to 100%).
When compared, two timer objects are considered equal if both their individual durations are equal.
A Timer object that is casted to a bool
will evaluate to true
if a duration
was set, otherwise false
. This can be useful e.g. for a quick check in a
single if-clause.
Add the timer header file to your source code, e.g. by cloning this repository
as a git submodule under
src/lib/
of your main sketch. Use the default git workflow to pull/upgrade
etc.
git clone https://github.com/nbe95/arduino-timer.git ./src/lib/timer/
ℹ️ In the Arduino universe, it is required that the code resides under the main
src
directory of your sketch!
Then, simply include the timer.h
in your sketch and you're ready to go.
Take a quick look at the following code to see how everything works.
#include "./src/lib/timer/timer.h"
// Create a timer with or without a specific duration in ms...
Timer my_timer(1000ul * 60 * 60 * 24 * 3); // =3 days
Timer another_timer;
void setup() {
// ...or provide a duration when starting the timer...
my_timer.start(1000);
// ...or set/change it anytime you want
my_timer.setDuration(2000);
// Check if my_timer is set and running
if (my_timer) { // short for my_timer.isSet()
Serial.println("my_timer is set, i.e. has got a duration.");
}
if (my_timer.isRunning()) {
Serial.println("... and has already been started!");
}
}
void loop() {
// Easy check for repetitive tasks
if (my_timer.checkAndRestart()) {
task_each_2s();
}
// Just check once without resetting another_timer
if (another_timer.check()) {
Serial.print("Congratulations, 7s have elapsed in total! ");
Serial.println("This message should be printed only once.");
}
}
void task_each_2s() {
Serial.println("Yay, 2 seconds have passed again.");
// Check if another_timer is set
if (!another_timer) { // short for another_timer.isSet()
another_timer.setDuration(5000);
Serial.println("Setting another_timer to 5s.");
// Fetch elapsed time
another_timer.start();
delay(10);
Serial.print("Right now, about 10ms should have elapsed: ");
Serial.println(another_timer.getElapsedTime());
}
}