Skip to content

Commit ff363ba

Browse files
committed
arduino-timer: library for delaying function calls
Signed-off-by: Michael Contreras <[email protected]>
0 parents  commit ff363ba

File tree

13 files changed

+615
-0
lines changed

13 files changed

+615
-0
lines changed

.gitignore

Whitespace-only changes.

LICENSE

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Copyright (c) 2018, Michael Contreras
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are
6+
met:
7+
8+
1. Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
10+
11+
2. Redistributions in binary form must reproduce the above copyright
12+
notice, this list of conditions and the following disclaimer in the
13+
documentation and/or other materials provided with the distribution.
14+
15+
3. Neither the name of the copyright holder nor the names of its
16+
contributors may be used to endorse or promote products derived from
17+
this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Makefile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
NAME := arduino-timer
2+
VERSION := $(shell grep version library.properties | cut -d= -f2)
3+
4+
$(NAME)-$(VERSION).zip:
5+
git archive HEAD --prefix=$(@:.zip=)/ --format=zip -o $@
6+
7+
tag:
8+
git tag $(VERSION)

README.md

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# arduino-timer - library for delaying function calls
2+
3+
Simple *non-blocking* timer library for calling functions **in / at / every** specified units of time. Supports millis, micros, time rollover, and compile time configurable number of tasks.
4+
5+
### Use It
6+
7+
Include the library and create a *Timer* instance.
8+
```cpp
9+
#include <timer.h>
10+
11+
auto timer = timer_create_default();
12+
```
13+
14+
Or using the *Timer* constructors for different task limits / time resolution
15+
```cpp
16+
Timer<10> timer; // 10 concurrent tasks, using millis as resolution
17+
Timer<10, micros> timer; // 10 concurrent tasks, using micros as resolution
18+
```
19+
20+
Call *timer*.**tick()** in the loop function
21+
```cpp
22+
void loop() {
23+
timer.tick();
24+
}
25+
```
26+
27+
Make a function to call when the *Timer* expires
28+
```cpp
29+
bool function_to_call(void *argument /* optional argument given to in/at/every */) {
30+
return false; // to keep the timer active - true removes it (for timer.every())
31+
}
32+
```
33+
34+
Call *function\_to\_call* **in** *delay* units of time *(unit of time defaults to milliseconds)*.
35+
```cpp
36+
timer.in(delay, function_to_call);
37+
timer.in(delay, function_to_call, argument); // or with an optional argument for function_to_call
38+
```
39+
40+
Call *function\_to\_call* **at** a specific *time*.
41+
```cpp
42+
timer.at(time, function_to_call);
43+
timer.at(time, function_to_call, argument); // with argument
44+
```
45+
46+
Call *function\_to\_call* **every** *interval* units of time.
47+
```cpp
48+
timer.every(interval, function_to_call);
49+
timer.every(interval, function_to_call, argument); // with argument
50+
```
51+
52+
Be fancy with **lambdas**
53+
```cpp
54+
timer.in(1000, [](void*) -> bool { return false; });
55+
timer.in(1000, [](void *argument) -> bool { return argument; }, argument);
56+
```
57+
58+
### API
59+
60+
```cpp
61+
/* Constructors */
62+
/* Create a timer object with default settings - millis resolution, TIMER_MAX_TASKS (=16) task slots */
63+
Timer<> timer_create_default(); // auto timer = timer_create_default();
64+
65+
/* Create a timer with max_tasks slots and time_func resolution */
66+
Timer<size_t max_tasks = TIMER_MAX_TASKS, unsigned long (*time_func)(void) = millis> timer;
67+
Timer<> timer; // Equivalent to: auto timer = timer_create_default()
68+
Timer<10> timer; // Timer with 10 task slots
69+
Timer<10, micros> timer; // timer with 10 task slots and microsecond resolution
70+
71+
/* Signature for handler functions */
72+
bool handler(void *argument);
73+
74+
/* Timer Methods */
75+
/* Ticks the timer forward - call this function in loop() */
76+
void tick();
77+
78+
/* Calls handler with opaque as argument in delay units of time */
79+
bool in(unsigned long delay, handler_t handler, void *opaque = NULL);
80+
81+
/* Calls handler with opaque as argument at time */
82+
bool at(unsigned long time, handler_t handler, void *opaque = NULL);
83+
84+
/* Calls handler with opaque as argument every interval units of time */
85+
bool every(unsigned long interval, handler_t handler, void *opaque = NULL);
86+
```
87+
88+
### Installation
89+
90+
[Check out the instructions](https://www.arduino.cc/en/Guide/Libraries) from Arduino.
91+
92+
**OR** copy **src/timer.h** into your project folder *(you won't get managed updates this way)*.
93+
94+
### Examples
95+
96+
Found in the **examples/** folder.
97+
98+
The simplest example, blinking an LED every second *(from examples/blink)*:
99+
100+
```cpp
101+
#include <timer.h>
102+
103+
auto timer = timer_create_default(); // create a timer with default settings
104+
105+
bool toggle_led(void *) {
106+
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // toggle the LED
107+
return false; // stop repeating? false
108+
}
109+
110+
void setup() {
111+
pinMode(LED_BUILTIN, OUTPUT); // set LED pin to OUTPUT
112+
113+
// call the toggle_led function every 1000 millis (1 second)
114+
timer.every(1000, toggle_led);
115+
}
116+
117+
void loop() {
118+
timer.tick(); // tick the timer
119+
}
120+
```
121+
122+
### LICENSE
123+
124+
Check the LICENSE file - 3-Clause BSD License
125+
126+
### Notes
127+
128+
Currently only a software timer. Any blocking code delaying *timer*.**tick()** will prevent the timer from moving forward and calling any functions.
129+
130+
The library does not do any dynamic memory allocation.
131+
132+
The number of concurrent tasks is a compile time constant, meaning there is a limit to the number of concurrent tasks. The **in / at / every** functions return **false** if the *Timer* is full.
133+
134+
Change the number of concurrent tasks using the *Timer* constructors. Save memory by reducing the number, increase memory use by having more. The default is **TIMER_MAX_TASKS** which is currently 16.

examples/blink/blink.ino

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* timer_blink
3+
*
4+
* Blinks the built-in LED every second using the arduino-timer library.
5+
*
6+
*/
7+
8+
#include <timer.h>
9+
10+
auto timer = timer_create_default(); // create a timer with default settings
11+
12+
bool toggle_led(void *) {
13+
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // toggle the LED
14+
return false; // stop repeating? false
15+
}
16+
17+
void setup() {
18+
pinMode(LED_BUILTIN, OUTPUT); // set LED pin to OUTPUT
19+
20+
// call the toggle_led function every 1000 millis (1 second)
21+
timer.every(1000, toggle_led);
22+
}
23+
24+
void loop() {
25+
timer.tick(); // tick the timer
26+
}
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* timer_blink_micros
3+
*
4+
* Blinks the built-in LED every second using the arduino-timer library.
5+
*
6+
*/
7+
8+
#include <timer.h>
9+
10+
Timer<1, micros> timer; // create a timer with 1 task and microsecond resolution
11+
12+
bool toggle_led(void *) {
13+
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // toggle the LED
14+
return false; // stop repeating? false
15+
}
16+
17+
void setup() {
18+
pinMode(LED_BUILTIN, OUTPUT); // set LED pin to OUTPUT
19+
20+
// call the toggle_led function every 1000000 micros (1 second)
21+
timer.every(1000000, toggle_led);
22+
}
23+
24+
void loop() {
25+
timer.tick(); // tick the timer
26+
}

examples/blink_print/blink_print.ino

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* timer_blink_print
3+
*
4+
* Blinks the built-in LED every half second, and prints a messages every
5+
* second using the arduino-timer library.
6+
*
7+
*/
8+
9+
#include <timer.h>
10+
11+
auto timer = timer_create_default(); // create a timer with default settings
12+
13+
bool toggle_led(void *) {
14+
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // toggle the LED
15+
return false; // stop repeating? false
16+
}
17+
18+
bool print_message(void *) {
19+
Serial.print("print_message: Called at: ");
20+
Serial.println(millis());
21+
return false; // stop repeating? false
22+
}
23+
24+
void setup() {
25+
Serial.begin(9600);
26+
pinMode(LED_BUILTIN, OUTPUT); // set LED pin to OUTPUT
27+
28+
// call the toggle_led function every 500 millis (half second)
29+
timer.every(500, toggle_led);
30+
31+
// call the print_message function every 1000 millis (1 second)
32+
timer.every(1000, print_message);
33+
}
34+
35+
void loop() {
36+
timer.tick(); // tick the timer
37+
}

examples/full/full.ino

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* timer_full
3+
*
4+
* Full example using the arduino-timer library.
5+
* Shows:
6+
* - Setting a different number of tasks with microsecond resolution
7+
* - disabling a repeated function
8+
* - running a function after a delay
9+
*
10+
*/
11+
12+
#include <timer.h>
13+
14+
auto timer = timer_create_default(); // create a timer with default settings
15+
Timer<> default_timer; // save as above
16+
17+
// create a timer that can hold 1 concurrent task, with microsecond resolution
18+
Timer<1, micros> u_timer;
19+
20+
bool toggle_led(void *) {
21+
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // toggle the LED
22+
return false; // stop repeating? false
23+
}
24+
25+
bool print_message(void *msg) {
26+
const char *m = (const char *)msg;
27+
Serial.print("print_message: ");
28+
Serial.println(m);
29+
return false; // stop repeating? false
30+
}
31+
32+
size_t repeat_count = 1;
33+
bool repeat_x_times(void *opaque) {
34+
size_t limit = (size_t)opaque;
35+
36+
Serial.print("repeat_x_times: ");
37+
Serial.print(repeat_count);
38+
Serial.print("/");
39+
Serial.println(limit);
40+
41+
return ++repeat_count > limit; // remove this task after limit reached
42+
}
43+
44+
void setup() {
45+
Serial.begin(9600);
46+
pinMode(LED_BUILTIN, OUTPUT); // set LED pin to OUTPUT
47+
48+
// call the toggle_led function every 500 millis (half second)
49+
timer.every(500, toggle_led);
50+
51+
// call the repeat_x_times function every 1000 millis (1 second)
52+
timer.every(1000, repeat_x_times, 10);
53+
54+
// call the print_message function every 1000 millis (1 second),
55+
// passing it an argument string
56+
timer.every(1000, print_message, "called every second");
57+
58+
// call the print_message function in five seconds
59+
timer.in(5000, print_message, "delayed five seconds");
60+
61+
// call the print_message function at time + 10 seconds
62+
timer.at(millis() + 10000, print_message, "call at millis() + 10 seconds");
63+
64+
// call print_message in 2 seconds, but with microsecond resolution
65+
u_timer.in(2000000, print_message, "delayed two seconds using microseconds");
66+
67+
if (!u_timer.in(5000, print_message, "never printed")) {
68+
/* this fails because we created u_timer with only 1 concurrent task slot */
69+
Serial.println("Failed to add microsecond event - timer full");
70+
}
71+
}
72+
73+
void loop() {
74+
timer.tick(); // tick the timer
75+
u_timer.tick();
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
Test timer rollover handling
3+
*/
4+
5+
#include <timer.h>
6+
7+
unsigned long wrapping_millis();
8+
9+
Timer<1, wrapping_millis> timer; // this timer will wrap
10+
auto _timer = timer_create_default(); // to count milliseconds
11+
12+
unsigned long _millis = 0L;
13+
unsigned long wrapping_millis()
14+
{
15+
// uses _millis controled by _timer
16+
// 6-second time loop starting at rollover - 3 seconds
17+
if (_millis - (-3000) >= 6000)
18+
_millis = -3000;
19+
return _millis;
20+
}
21+
22+
void setup() {
23+
pinMode(LED_BUILTIN, OUTPUT);
24+
_timer.every(1, [](void *) -> bool {
25+
++_millis; // increase _millis every millisecond
26+
return false;
27+
});
28+
29+
// should blink the led every second, regardless of wrapping
30+
timer.every(1000, [](void *) -> bool {
31+
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
32+
return false;
33+
});
34+
}
35+
36+
void loop() {
37+
_timer.tick();
38+
timer.tick();
39+
}

0 commit comments

Comments
 (0)