contrem / arduino-timer Goto Github PK
View Code? Open in Web Editor NEWNon-blocking library for delaying function calls
License: BSD 3-Clause "New" or "Revised" License
Non-blocking library for delaying function calls
License: BSD 3-Clause "New" or "Revised" License
As the title says, there is a bug / inconsistency when canceling a timer.
Let's say we have a timer: Timer<10> MainTimer; // Timer with 10 task slots
.
If we assign a Task ID to a certain task, e.g. Timer<>::Task DummyTask;
and set a task for it, e.g. DummyTask = MainTimer.every(1000, DummyFunction);
, the library behaves differently when canceling the timer from the inside (by returning false
into the DummyFunction
), compared to canceling it from the outside (by calling the MainTimer.cancel(DummyTask)
method ).
When canceling the timer using the .cancel()
method, DummyTask
gets back ID (value) = 0, as it should.
But when canceling the timer from the inside (by returning false
in DummyFunction
), DummyTask
retains its original ID, without reverting back to 0
as it should.
I created two demo examples here:
This one demonstrates the good behavior (using the cancel()
method): https://wokwi.com/projects/355520237400512513
And the other one, demonstrates the wrong behavior (by retaining its task ID whenever using return false
): https://wokwi.com/projects/355520290434348033 .
I'm not an experienced C++ developer, but I suppose the code misses a task reference when removing it, here.
(I'm wondering if this could also explain the fact that I found situations when the timer cancels itself, as per my other opened issue, #76 ).
Thanks,
A.
does not accept muötiple arguments
https://wokwi.com/projects/334634662909444692
An "enhancement" request.
Sometimes when I make changes in code I accidentally break some other part of the system I didn't understand.
It can be difficult to recognize that kind of issue until after the code is released and breaks other user's builds.
It would be nice to have some regression tests which can confirm your code changes will not break other required behaviors. Regression test results should be trivial to interpret (for example return PASS or FAIL). There should be no question if your change broke something important. Even if you don't understand what the problem is, you should be able to learn there is a problem.
On my ESP32 I configure with configTime(3600, 3600, "time.google.com"); European Time for Germany(MESZ) with automatic time changeover. I have the issue, that the automatic time changeover from winter time to summer time takes place approx. 2 weeks too early. It seems that he uses the American dates for the summer/winter time changeover and not the European ones? How can I fix this?
Current implementation doesn’t account for the possibility of timer overflow, which should be a concern specially when using microsecond resolution (will happen every ~1h 12min).
How can I reuse the same timer after it's over? The timer may remain in memory and the space cannot be freed.
#include <arduino-timer.h>
Timer<1, millis, void*> timer;
Timer<>::Task task;
uint32_t n = 0;
void setup() {
SerialUSB.begin(115200);
while (!SerialUSB){}
task = timer.in(1000, test);
}
void loop() {
timer.tick();
}
bool test(void *)
{
SerialUSB.print("n: ");
SerialUSB.println(n);
n++;
timer.cancel(task);
task = timer.in(1000, test);
return true;
}
Return the number of ticks until next event for advanced use cases, such as dynamic sleeping.
Hi,
A brief description of what I am trying to achieve, anytime an IF condition is true a timer should activate and set a GPIO pin HIGH/LOW at end of timer. The hardware I am using is an ESP8266 with WIFI enabled. I am aware that the workflow of ESP MCU is different compared to Arduino MCU.
I read through the documentation and issues of arduino-timer, but I am not able to figure out the problem. I tried using both timer.in(delay, func) and timer.at(millis()+delay, func).
I have setup two timers, timerON - 60s delay and timerOFF - 30s delay. After a reboot, once WIFI is connected, timerON will execute properly and set GPIO pin LOW. However, when WIFI disconnects timerOFF does not execute, GPIO pin is instantaneously set HIGH. Subsequently if WIFI is connected again, nothing happens GPIO pin is kept HIGH.
I would be grateful if you could point out my mistake and looking forward for suggestions to workaround delay().
Please find below my code.
#include <ESP8266WiFi.h>
#include <arduino-timer.h>
const char* ssid = "*********";
const char* password = "*********";
byte bssid[] = {***, ***, ***, ***, ***, ***};
WiFiEventHandler gotIpEventHandler, disconnectedEventHandler;
const int DCON = 12; // Red LED
const int CON = 14; // Green LED
const int SSR = 4; // Solid State Relay
auto timerON = timer_create_default();
auto timerOFF = timer_create_default();
bool ON(void *)
{
Serial.println("Switch ON");
digitalWrite(SSR, LOW);
return false;
}
bool OFF(void *)
{
Serial.println("Switch OFF");
digitalWrite(SSR, HIGH);
return false;
}
void setup()
{
pinMode(SSR, OUTPUT);
pinMode(CON, OUTPUT);
pinMode(DCON, OUTPUT);
digitalWrite(SSR, HIGH);
Serial.begin(115200);
Serial.println();
WiFi.mode(WIFI_STA);
gotIpEventHandler = WiFi.onStationModeGotIP([](const WiFiEventStationModeGotIP& event)
{
Serial.print("Station connected, IP: ");
Serial.println(WiFi.localIP());
digitalWrite(CON, HIGH);
digitalWrite(DCON, LOW);
});
disconnectedEventHandler = WiFi.onStationModeDisconnected([](const WiFiEventStationModeDisconnected& event)
{
Serial.println("Station disconnected");
WiFi.begin(ssid, password, 0, bssid);
digitalWrite(DCON, HIGH);
digitalWrite(CON, LOW);
});
Serial.printf("Connecting to %s ...\n", ssid);
WiFi.begin(ssid, password, 0, bssid);
Serial.println();
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
timerON.in(60000, ON);
timerOFF.in(30000, OFF);
}
void loop()
{
if (WiFi.status() == WL_CONNECTED)
{
timerON.tick();
}
else
{
timerOFF.tick();
}
}
Is it possible to designate a given timer to return false or return true outside of their respective interrupt routines?
For example, create two timers:
auto timer1 = timer_create_default();
timer1.every(500, Do_Something1);
auto timer2 = timer_create_default();
timer2.every(25, Do_Something2);
void loop()
{
blah, blah,blah
if (x<10)
timer1.return false;
if (y>0.1)
timer2.return true;
blah,blah,blah
}
i made a timer with:
auto delay_timer = timer_create_default();
and cannot terminate it using:
delay_timer.cancel();
timer is started with:
delay_timer.every(1000, bomb_armed);
seems he need the "task", but cannot find a way to define this task ...
Hi. This is probably mode of a programming issue than an issue with the library but I'm struggling to find the appropriate syntax.
I create some timers in the main setup function and update them in the loop as expected, but I need to access and control the timer object from a function within another file.
I've tried.. both without success.
extern Timer<> timer0 ;
extern auto timer0;
What would be the correct format to use for this as I'm not familiar using externs with templates.
Hello. What are the changes between the release tags?
I think that having the possibility of canceling a task before it gets executed could be very useful.
Here is how I've implemented it https://github.com/bogomips/arduino-timer
How can I change the timeout of a timer running 'every' either before it's timed out or at the function call?.
If I want to create several global timers but not have all of them running, how would one do that? E.g,
static bool heartbeatTimerCallback (void *argument __attribute__ ((unused)));
static bool sixHourTimerCallback (void *argument __attribute__ ((unused)));
static bool motionTimerCallback (void *argument __attribute__ ((unused)));
static auto timer = timer_create_default ();
static auto heartbeatTimer = timer.every (HEARTBEAT_TIMEBASE, heartbeatTimerCallback);
static auto sixHourTimer = timer.in (0, sixHourTimerCallback);
static auto motionTimer = timer.in (0, motionTimerCallback);
You can't actually create a timer with an expiration of 0 milliseconds, so what I've done is set it for a ridiculous amount of time, then cancel it in the setup()
function. The heartbeatTimer
is one I do want running when I create it.
Disclaimer: Not a C++ guy, but been writing C for 40 years.
Hello,
I have a strange bug with this code.
Minuterie.ino.txt
When line 126 ( Serial.println("RING 2"); ) is commented, "Ring 1" is sent to serial monitor at each call.
When line 126 is uncommented, "Ring 1" is displayed only at the first call, and then nothing.
No problem with the call to display_data() in both case.
I don't kown how to debug this case.
I tried creating an automated regression test to verify good behavior for timer.cancel() and timer ID collisions.
... and I think I found a regression for the returned value from timer.cancel()
.
bool
cancel(Task &task)
{
struct task * const t = static_cast<struct task * const>(task);
if (t) {
remove(t);
task = static_cast<Task>(NULL);
return true;
}
return false;
}
Here's the regression: Now that a timer ID is just a pointer to the timer's slot in the array, it will never be 0... and so timer.cancel(anId)
always returns true
.
See #79 for the regression test and a fix.
Hey I tried looking for the lib on platform io but couldn't find, if you could add it there, it will great.
Hi,
how to clear / reset a Timer?
Hi Michael,
This is one of the better timer libraries for Arduino I've seen so far. 👍 It does without dynamic allocation and makes use of const
. I hope you've tested the timer overflow. 😉
Only a personal nitpicking: I would change the meaning of the function_to_call()
return value. false
is negative, intuitively meaning "I don't want no more." I would have expected it to not be called again when returning a false
.
Just my 2¢,
Flössie
Is there any circumstance or technical possibility that could lead to a timer canceling itself?
I have few .every()
timers and sometimes (very rarely indeed), with no possible explanation a random timer simply stops.
I just can't figure out why.
Their function always return true;
, there's plenty of RAM available, I had set plenty of timers (Timer<48> MainTimer;
), I run the loop with MainTimer.tick<void>(); // to avoid ticks() calculation
, I count them and I have a total of 15
... but one of them, very rarely, just suddenly stops.
Can't figure out why.
Board is ATMega4808 if it helps.
Hi,
first let me thank you for this library it makes scheduling easier.
I am using Version 2.3.1
I use the timer library to schedule sensor requests on a 328P board. (Software like it behaves as an arduino UNO).
There a stange error happens: If I set the number of timers higher than 8 - the concaternation of two strings stops working:
lcd.print("Temperature: "+String(SHT2X_data.Temperature));
produces no output on the display. It does not help to call:
lcd.print("Temperature: "+String(24));
I thinned out the whole program it might not be compilable
If you need the complete program I can send it to you.
Regards
Alexander
-------------------------- cut here --------------------------------------
#include "Arduino.h"
#include "Wire.h"
#include "TCA9548A.h"
#include "LiquidCrystal_I2C.h"
#include "SHT2x.h"
#include <arduino-timer.h>
uint8_t NewSensorData=1; // True if new Sensor data to display
auto timer = timer_create_default(); // create a timer with default settings
Timer<> default_timer; // save as above
// create a timer that holds 16 tasks, with millisecond resolution,
// and a custom handler type of 'const char *
Timer<8, millis, const char *> My_timer; // ####################### If you set here more than 8 timers ############
//########## Timed Tasks ########
bool toggle_led(void *) {
digitalWrite(Debug_LED, !digitalRead(Debug_LED)); // toggle the LED
return true; // repeat? true
}
void DisplayPage (uint8_t PageToDisplay) {
digitalWrite(Debug_LED2, !digitalRead(Debug_LED2)); // Humidity Sensor
I2CMux.openChannel(AddrDisplay);
lcd.clear();
// Line 0
lcd.print("SHT21");
// Line 1
lcd.setCursor(0,1);
lcd.print("Temperature: "+String(SHT2X_data.Temperature)); // ####################### This String command fails ############
}
void setup() {
// initialize digital pin as an output.
pinMode(Debug_LED, OUTPUT);
pinMode(Debug_LED2, OUTPUT);
lcd.init();
// turn on the backlight
lcd.backlight();
lcd.clear();
My_timer.every(500, toggle_led);
My_timer.every(3000, HumidSensorUpdate);
}
void loop() {
My_timer.tick();
if (NewSensorData==1) {
DisplayPage(PageToDisplay);
NewSensorData=0;
}
--------------------------- cute here ------------------------
I am using this (brilliant) library to run several tasks repeatedly using an Arduino Uno.
I have got 3 or 4 tasks running at different intervals using:
scheduler_timer.every(500, update_sensors)
and similar calls, as per the example provided in the docs.
This works. My code runs as expected and things are fine, except that there is a warning during compilation.
`Test_Rig.ino: In function 'bool send_config_data(void*)':'
'Test_Rig.ino:299:70: warning: invalid conversion from 'void ()()' to 'Timer<4, millis>::handler_t {aka bool ()(void*)}' [-fpermissive]
scheduler_timer.in(250, scheduler_timer.every(500, update_sensors));'
^
In file included from Test_Rig.ino:15:0:
\Arduino\libraries\arduino-timer\src/arduino-timer.h:85:5: note: initializing argument 2 of 'Timer<max_tasks, time_func, T>::Task Timer<max_tasks, time_func, T>::every(long unsigned int, Timer<max_tasks, time_func, T>::handler_t, T) [with unsigned int max_tasks = 4; long unsigned int (* time_func)() = millis; T = void*; Timer<max_tasks, time_func, T>::Task = unsigned int; Timer<max_tasks, time_func, T>::handler_t = bool ()(void)]'
every(unsigned long interval, handler_t h, T opaque = T())
^~~~~
Test_Rig.ino:299:50: warning: invalid conversion from 'Timer<4, millis>::Task {aka unsigned int}' to 'Timer<4, millis>::handler_t {aka bool ()(void)}' [-fpermissive]
scheduler_timer.in(250, scheduler_timer.every(500, update_sensors));
~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
In file included from Test_Rig.ino:15:0:
\Arduino\libraries\arduino-timer\src/arduino-timer.h:70:5: note: initializing argument 2 of 'Timer<max_tasks, time_func, T>::Task Timer<max_tasks, time_func, T>::in(long unsigned int, Timer<max_tasks, time_func, T>::handler_t, T) [with unsigned int max_tasks = 4; long unsigned int (* time_func)() = millis; T = void*; Timer<max_tasks, time_func, T>::Task = unsigned int; Timer<max_tasks, time_func, T>::handler_t = bool ()(void)]'
in(unsigned long delay, handler_t h, T opaque = T())
^~
Sketch uses 14514 bytes (44%) of program storage space. Maximum is 32256 bytes.
Global variables use 1067 bytes (52%) of dynamic memory, leaving 981 bytes for local variables. Maximum is 2048 bytes.
`
I dont know what to do (if anything) to fix this issue. I cannot copy too much of my code here (confidentiality and all), but I can maybe make a minimal demonstration of the problem if necessary.
Thanks
Greg
This is a very nice compact library! Just what I needed.
I ended up splitting my code into 2 timers, because I observed that if I register an task to run every 10ms, and one a slow one to run every 1s, but the slow one might take 200ms, the high frequency task would not get triggered.
At least not when respecting the return value of the tick()
function. If I ran the tick()
twice after each other, it would go fine. Since the slow one wouldn't trigger, but the fast one would, and it would now return a much smaller delay time.
rough code:
void setup() {
Serial.begin();
timer.every(1000, [](void*) -> bool{ delay(200); return true);
timer.every(10, [](void*) -> bool { blinkLed(); return true});
}
void loop() {
unsigned long sleepTime = timer.tick();
if (sleepTime > 10) {
Serial.print("Sleeping longer than high frequency max: ");
Serial.println(sleepTime);
}
delay(sleepTime);
}
Version: 2.1.0
Arduino IDE version 1.8.9, for Windows 10
arduino-timer library version 2.0.1.
Boards Manager support for "Arduino nRF528x Boards (Mbed OS)", version 1.1.4.
Select "examples/arduino-timer/blink" sketch.
Select "Arduino Leonardo" board and build.
Build works as expected. This is a really nice, simple and useful library.
Select "Arduino Nano 33 BLE" board and build.
NOTE: Build fails with:
blink:10:14: error: 'timer_create_default' was not declared in this scope
auto timer = timer_create_default(); // create a timer with default settings
However if I rename the arduino-timer library file "timer.h" to "renamedAduinoTimer.h"
#include <timer.h>
#include <renamedAduinoTimer.h>
the code compiles and the timer works correctly.
I think the conflict is with the file named https://github.com/arduino/ArduinoCore-nRF528x-mbedos/blob/master/cores/arduino/mbed/drivers/Timer.h.
While Windows ignores case in filenames, with these two file names so similar there WILL be confusion for developers anyway.
Could we rename <timer.h> to <Arduino_timer.h> perhaps?
Pros:
Cons:
Another alternative would be to just mark this library as incompatible with Nano 33 BLE boards. Which would be a shame because this is really a nice timer library.
Thanks for creating this library!
Hey guys,
my timer stops executing after some executions. Short breakdown of my code:
Timer<2, micros> timer;
void setup()
{
timer.every(20000, updateLight1);
timer.every(20500, updateLight2);
}
void loop()
{
auto ticks = timer.tick();
Serial.println(ticks);
}
// updateLight1 and updateLight2 reads and writes GPIOs
If I add Serial.println()
to the updateLight1
/updateLight2
function after the gpio doing it works as expected and executes forever. If not it stops after some executions and the serial ticks output shows 0.
At this time ticks() returns 0 when the task queue is empty. (Bug?)
This makes it difficult to know how long to sleep before checking the queue again. Is it time to run tick() again right now? Is it safe to go to sleep?
I think ticks() should return (unsigned long) (-1L)
to hint that the queue is idle (no tasks to run). Then the caller can decide how how much sleep is appropriate when there are no tasks.
To see this behavior there is a unit test which confirms this in extras/tests/timerTest/timerTest.ino, test(timer_every).
Hi,
I appreciate your work and I would know if is possible to show the time remaining until the end.
For example, I have a countdown with a specific time using the function in(), but I want to show the time remaining in a display.
I tried use the function every() but in the looping the time is desynchronized because I have some delays.
An exemple of code to illustrate that.
`#include <arduino-timer.h>
auto t = timer_create_default();
int timerToShow = 60000;
int timerToShowArduino = 60000;
long previousMillis = 0;
const int maxTime = 1000;
bool counting = false;
bool updateTimer(void *)
{
timerToShow -= 1000;
return true;
}
void updateTimerByArduino() {
timerToShowArduino -= 1000;
}
bool finishTimer(void *) {
Serial.println("finish");
counting = false;
t.cancel();
return true;
}
void setup()
{
Serial.begin(9600);
Serial.println("start");
counting = true;
t.in(timerToShow, finishTimer);
t.every(1000, updateTimer);
}
void loop()
{
if(millis() - previousMillis >= maxTime) {
previousMillis = millis();
t.tick();
updateTimerByArduino();
if(counting) {
Serial.println(String(t.ticks()) + "|" + String(timerToShow) + "|" + String(timerToShowArduino));
}
delay(1500);
}
}`
In this case when the call finishTimer() in the correct time, the counters are on 20000 yet.
Can you help me?
Regards
Hi,
How long can a timer run without needing to reset the timer/device ?
Thnx in advance
It would be useful to have a signature that specified whether a timer should start already expired so that it fires on the first timer tick via loop() rather than only after the specified interval. In this way an initial action can be performed without the need to explicitly trigger the callbacks.
Hi, i have to handle events that will occour in minutes (not milliseconds), but i noticed that using this code:
// in the global
auto play_time_timer = timer_create_default();
// in the setup
play_time_timer.in(play_time*1000, CT_win);
// in the loop
play_time_timer.tick();
// and the called procedure
bool CT_win(void *argument){
Serial.print("timer complete!");
return false;
}
works only if play_time if less than 33 seconds (so global delay less than 33000 milliseconds).
I suppose have to deal with the INT limit, but how i can make a minute counting timer?
In the past I have run into problems where my code was not compatible with a new (unknown to me) platform.
Code changes were necessary to get it to work in new environments which I did not have access to.
It would be nice to be able to check that code changes are compatible with many Arduino variants without having to confirm by manually reconfiguring my local system for each check.
Timer<>::Task timerTask
instead of int timerId
like in JS? Id more understandable and you don't need pick in mind or looking for docs about Timer<>::Task
instead of auto
if variable is not defined.void function_to_call()
without error or warnings? It is common way to return void and use no arguments in the callback. Boolean returning and arguments should be optional.The Timer template is treated by the gcc compiler as belonging to the anonymous namespace. This causes a linker error.. I have made a simple test program available at (https://github.com/rogerjames99/heapstat.git).
This program has two versions of the Timer template class member one produces a compiler warning the other does not. Neither define the symbol.
I cannot understand why the template is in the anonymous namespace.
All help gratefully received! Apologies in advance if I have made a stupid error.
Roger
In my code, alarm()
is called once, which activates the previously defined Task blinkAlarm
, calling the function alarmSub()
every blinkDelay
. I want this alarmSub()
function to run for a limited time, duration
, and then end. currently, I set up another function, alarmEnd()
, which is called using timer.in(duration, alarmEnd)
, but this seems unnecessarily complicated to me. My setup might be more of an edge-case though..
Here's my full code
Timer<>::Task blinkAlarm;
bool alarmSub(void *)
{
alarmState *= -1;
if(alarmState == 1) {
on();
} else {
off();
}
return true;
}
bool alarmEnd(void *) {
timer.cancel(blinkAlarm);
return true;
}
void alarm()
{
blinkAlarm = timer.every(blinkDelay, alarmSub);
timer.in(duration, alarmEnd);
}
In the example below, the timers do not repeat unless the default for add_task is changed to
add_task(unsigned long start, unsigned long expires,
handler_t h, T opaque, bool repeat = 1)
#include <arduino-timer.h>
// create a timer that holds 16 tasks, with millisecond resolution,
Timer<16, millis, const char *> t_timer1;
Timer<16, millis, int> t_timer2;
bool print_message(const char *m) {
Serial.print("print_message: ");
Serial.println(m);
return true; // repeat? true
}
bool pmsg(int m) {
Serial.print("pmsg: ");
Serial.println(m);
return true; // repeat? true
}
void setup() {
Serial.begin(9600);
t_timer1.in(3000, print_message, "3");
t_timer2.in(3000, pmsg, 3);
t_timer2.in(1000, pmsg, 1);
}
void loop() {
t_timer1.tick();
t_timer2.tick();
//Serial.print(".");
}
Hi! Thank you for a great library!
When I try to use a delay grater than 32768 with the timer.in method i get weird results.
For example: timer.in(32768, function_to_call);
Is this some known limit of the library or some of the dependent libraries?
(Sorry if this is obvious from the code, but I´m still a beginner in c++ and don´t fully understand how this library work)
If so, is there a simple way to get around this limit?
(I´m using this on a uno where I have changed the prescalers on the internal timers to get a higher frequency PWM-output, and therefore have to multiply all time values accordingly to compensate for the timer moving faster while using functions such as millis etc. Thats why I easily get values that are quite large.
With a compensation factor of 64, the maximum time I can have is 512ms.)
Thanks! /Nbasse
Hello,
I am using the timer library to generate 100 Hz PWM on four pins, which can have different duty cycles. In my current implementation, the timer misses one cycle every 500ms or so, where it just skips the timer.in delay and proceeds with the delay function immediately i.e. switching the pin high and then low immediately. Could you please share your thoughts on the probable cause for this ?
`#include <arduino-timer.h>
Timer<10> timer;
float frequency; // Frequency in Herz
double period;
double onFor[]={0,0,0,0};
long previous;
// Output pins for solenoid valves
#define Valve1 2 // Valve 1
#define Valve2 3 // Valve 2
#define Valve3 4 // Valve 3
#define Valve4 5 // Valve 4
bool switch_high(void *) {
//Serial.println(*onFor);
previous = millis();
// PWM1
if (onFor[0] > 0) {
digitalWrite(Valve1, 1); // Switch to high
}
if (onFor[0] < period) {
timer.in(onFor[0], switch_low1);
}
// PWM2
if (onFor[1] > 0) {
digitalWrite(Valve2, 1); // Switch to high
}
if (onFor[1] < period) {
timer.in(onFor[1], switch_low2);
}
// PWM3
if (onFor[2] > 0) {
digitalWrite(Valve3, 1); // Switch to high
}
if (onFor[2] < period) {
timer.in(onFor[2], switch_low3);
}
// PWM4
if (onFor[3] > 0) {
digitalWrite(Valve4, 1); // Switch to high
}
if (onFor[3] < period) {
timer.in(onFor[3], switch_low4);
}
// Serial.print(onFor[0]); Serial.print(";");
// Serial.print(onFor[1]); Serial.print(";");
// Serial.print(onFor[2]); Serial.print(";");
// Serial.print(onFor[3]); Serial.println();;
//Serial.print(period); Serial.println();;
return true;
}
bool switch_low1(void *) {
// Serial.print(millis()-previous);Serial.print(";");
digitalWrite(Valve1, 0); // Switch to low
return false;
}
bool switch_low2(void *) {
// Serial.print(millis()-previous);Serial.print(";");
digitalWrite(Valve2, 0); // Switch to low
return false;
}
bool switch_low3(void *) {
// Serial.print(millis()-previous);Serial.print(";");
digitalWrite(Valve3, 0); // Switch to low
return false;
}
bool switch_low4(void *) {
Serial.print(onFor[3]);Serial.print(";");
Serial.print(millis()-previous);Serial.println();
digitalWrite(Valve4, 0); // Switch to low
return false;
}
void setup() {
pinMode(Valve1, OUTPUT); // set Valve1 pin to OUTPUT
pinMode(Valve2, OUTPUT); // set Valve2 pin to OUTPUT
pinMode(Valve3, OUTPUT); // set Valve3 pin to OUTPUT
pinMode(Valve4, OUTPUT); // set Valve4 pin to OUTPUT
digitalWrite(Valve1, 0); // Switch to low
digitalWrite(Valve2, 0); // Switch to low
digitalWrite(Valve3, 0); // Switch to low
digitalWrite(Valve4, 0); // Switch to low
frequency = 100;
period = 1000 / frequency;
Serial.begin(9600);
onFor[0] = 0;
onFor[1] = 0;
onFor[2] = 0;
onFor[3] = 0;
timer.every(period, switch_high);
}
void loop()
{
//int sensorValue = analogRead(A5); // Range is 0 to 1023
//float dutyCycle = sensorValue*100.0 / 1023.0;
float dutyCycle[] = { 98, 0, 0, 98 };
onFor[0] = period * (dutyCycle[0] / 100.0);
onFor[1] = period * (dutyCycle[1] / 100.0);
onFor[2] = period * (dutyCycle[2] / 100.0);
onFor[3] = period * (dutyCycle[3] / 100.0);
timer.tick(); // tick the timer
}`
OMG! I had a couple of hours troubles with this code until understand that every
works one time if return nothing. Really wired logic.
arduinoTimer.every(500, readSerial);
bool readSerial(void *argument) {
// Do something
}
Hello,
With the current definition of the func handler:
typedef bool (*handler_t)(T opaque); /* task handler func signature */
It's impossible to use std::bind
when you want the timer to run a callback that is a member of the class.
by changing the definition to use std::function
like
typedef std::function<bool(T opaque)> handler_t;
It should let the user use any type of supported callback and shouldn't break the current working of the library.
I tried to modify a inteval of a timer in loop() to dynamically change the timer's inteval, but it doesn't work.
nacelle_timer.every(nacelleFrequencySetpoint ++, move_motor_count);
What should I do ?
I was trying to handover multiple arguments to the callback function, but it did not work. However as descibed in the readme, one argument is working fine.
Therefore is it maybe possible to cast
timer.every(10, callbackFunc_timer, color, screenBufferOld, screenBufferNew);
to
bool callbackFunc_timer(void *, uint16_t screenBufferOld[], uint16_t screenBufferNew[], uint8_t color) {
// do something
}
I would like to use timer tasks for my finite state machines, but I have been having trouble with them.
Basically I want to ensure that at most ONE state machine task is in the timer at any stage. This helps ensure that the number of tasks does not increase uncontrollably if I queue up a new task (for example for an emergency stop).
So, what I was planning on doing is cancel the pending task, then add the new task. This works ok EXCEPT when the two timer.cancel()...timer.in()
calls are made from within the running task.
Here is my example (built for Arduino Nano -- processor should not matter):
#include <arduino-timer.h>
auto timer = timer_create_default();
static const int WAIT_POLO = 2022;
static const int WAIT_MARCO = 4000;
Timer<>::Task activeMarcoPoloTask = 0; // NULL
///////////////////////////////////////////////////////////////////////////////
// reschedule a new task in place of the old one
// at most ONE task is scheduled, regardless of where it happens
//
void rescheduleTask(int nextWait, Timer<>::handler_t nextAction) {
#define SHOW_CANCEL_BUG
#ifdef SHOW_CANCEL_BUG
timer.cancel(activeMarcoPoloTask);
#endif
activeMarcoPoloTask = timer.in(nextWait, nextAction);
}
///////////////////////////////////////////////////////////////////////////////
bool doMarco(void *) {
Serial.print("Marco ");
rescheduleTask(WAIT_POLO, doPolo);
return false;
}
///////////////////////////////////////////////////////////////////////////////
bool doPolo(void *) {
Serial.println("Polo");
rescheduleTask(WAIT_MARCO, doMarco);
return false;
}
///////////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println(F("Running " __FILE__ ",\nBuilt " __DATE__));
activeMarcoPoloTask = timer.in(1000, doMarco);
}
///////////////////////////////////////////////////////////////////////////////
void loop() {
timer.tick();
}
The phrase "Marco Polo" does not repeat when SHOW_CANCEL_BUG
is defined -- output freezes as there are no tasks in the timer.
I THINK the problem is that canceling the active task (while it is running) frees up its slot in the timer but the timer does not realize the free slot can now refer to a new task. When a new task uses that slot, the timer cleanup code from the previous task deletes it,
Here's the code for tick():
template <typename R> void
tick()
{
timer_foreach_task(task) {
if (task->handler) {
const unsigned long t = time_func();
const unsigned long duration = t - task->start;
if (duration >= task->expires) {
task->repeat = task->handler(task->opaque) && task->repeat; // ! THIS MAY BE REPLACED WITH A NEW TASK!
if (task->repeat) task->start = t;
else remove(task);
}
}
}
}
So... is this a bug?
Should I submit a pull request with a bugfix and new regression test to confirm it works?
First I would like to thank you for this really easy to use and very versatile timer.
I have got a question to the amount of timers I can program. Have I got it right and the functions are limited to 16 timers? If so, is there any chance to extend this in any way, let's say 24 or 32?
As the project is growing, so is the need to control different things with the timer functions and slowly I've used all 16 ;-)
Thanks
It would be great if we could get a reset funtion
Dear Michael,
Is it better to have multiple timers with one task apiece, or one timer with multiple tasks? I ask because I can't reliably set multiple tasks and cancel them individually. The code below fires phasers and photon torpedoes on a model starship. I want to "randomly" alternate firing phasers and torpedoes with each press of a button, for a total of four weapons fire: one phaser, three torpedoes (port and starboard); one torpedo, one phaser, two torpedoes; etc.
I'm using the LedFlasher library from Nick Gammon to fire the phasers, but I use your timer to tell it when to stop. (I've also tried disabling LedFlasher.) I also use your timer to repetitively increase the intensity of the torpedo effect, and again to ramp down the effect. I've tried it with one timer and assigning a task without obtaining an identifier, and just doing a blanket cancel when I want to end the task. And I've also created multiple tasks and using systemTimer.cancel(phasTask) and systemTimer.cancel(torpTask).
Whatever method I try, it only seems to work for two calls to the randomFire function. After that, the fireTorpedo function or firePhaser functions act unreliably. The randomFire function, for instance, just keeps firing torpedoes endlessly.
I've also tried instantiating the timer with Timer<2> systemTimer, but that causes a different problem — the phaser fires endlessly.
I'd appreciate any suggestions. Tomorrow I'll try creating multiple timers with one task apiece. Ultimately I have four tasks for this sketch, to control spotlights, thrusters, phasers and torpedoes. But for now, I'd just be happy to handle two tasks.
Thanks,
Jennifer Petkus
`#include <arduino-timer.h>
#include <LedFlasher.h>
const int CS_PIN = 10;
// Audio out = pin 9, declared in setup
const int WEAP_BTN = 8;
const int TORP1_PIN = 6;
const int TORP2_PIN = 5;
const int PHAS_PIN = 4;
auto systemTimer = timer_create_default();
/* Next value is a very loose approximation of the time
for a torpedo launch burst. Torpedo brightness increases
until it reaches threshold value, goes to 255, and then fades */
const int TORP_DUR = 1500/255;
const int TORP_THRESH = 64; // when torp launcher switches to full bright
int torpInt = 0; // current brightness of torp launcher
int torpCnt = 0; // port or starboard launcher
int fireCnt = 0; // how many times weapons fired
int fireLmt = 4; // max number weapons fire
bool weapFlag = 0; // prevents overlapping fire
bool warpFlag = 0; // prevents overlapping impulse/warp triggers
bool phasFlag = 0;
const int PHAS_LOW = 250;
const int PHAS_HIGH = 1500;
LedFlasher phasers(PHAS_PIN, 50, 100); // phaser flicker effect
void setup() {
pinMode(TORP1_PIN, OUTPUT);
pinMode(TORP2_PIN, OUTPUT);
pinMode(WEAP_BTN, INPUT);
phasers.begin();
}
void loop() {
systemTimer.tick();
if (digitalRead(WEAP_BTN) == HIGH && !weapFlag) { // prevents overlapping fire and firing in spacedock
weapFlag = 1;
randomFire();
}
if (phasFlag) {
digitalWrite(PHAS_PIN, HIGH);
phasers.update();
}
}
void randomFire() {
if (fireCnt < fireLmt) {
if (random(0,2) == 1) {
phasFlag = 1;
firePhaser("fire");
} else {
systemTimer.every(TORP_DUR, fireTorpedo, "ramp");
}
fireCnt++;
} else {
fireCnt = 0;
weapFlag = 0;
}
}
void fireTorpedo(const char *which) {
if (which == "ramp") { // slowly lights LED until …
if (torpInt > TORP_THRESH) { // … flash after threshold
systemTimer.cancel();
torpInt = 255;
systemTimer.every(TORP_DUR/2, fireTorpedo, "fade");
} else {
torpInt++;
}
} else if (which == "fade") {
if (torpInt <= 0) {
if (torpCnt == 0) {
systemTimer.cancel();
systemTimer.every(TORP_DUR, fireTorpedo, "ramp");
torpCnt++;
torpInt = 0;
} else if (torpCnt == 1) {
torpCnt = 0;
randomFire();
}
} else {
torpInt--;
}
}
int cur_pin = 0;
if (torpCnt == 0) { // switches between port / stbd launcher
cur_pin = TORP1_PIN;
} else if (torpCnt == 1) {
cur_pin = TORP2_PIN;
}
analogWrite(cur_pin, torpInt);
}
void firePhaser(const char *which) {
if (which == "fire") {
systemTimer.in(500, firePhaser, "stop");
} else if (which == "stop") {
systemTimer.cancel();
digitalWrite(PHAS_PIN, LOW);
phasFlag = 0;
randomFire();
}
}`
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.