New Library: muTimer / Delay (non-blocking)

I have not found an easy to use non-blocking timer / delay library so I created one.
This library does not use any hardware timers, it uses the Arduino millis() function.

You actually need just two lines of code to use it.
Create the object and call the funktion. I hope it is easy to use for beginners.

muTimer myTimer1 = muTimer();
output1 = myTimer1.timerOnOff(input1, 2000, 1000); // on delay 2000 ms, off delay 1000 ms

There are also calls available to use either the on or off timer

output1 = myTimer1.timerOn(input1, 2000); // on delay 2000 ms
output1 = myTimer1.timerOff(input1, 1000); // off delay 1000 ms

I started about one month ago with the programming of an Arduino Mega unit and this is actually my first C++ library (I just programmed C before), any comments regarding the style or functionality are welcome.

What is actually the proper way to get a libray into the Arduino IDE Library Manager?

Edit:
timerOnOff() got in the meanwhile renamed to delayOnOff().

Thanks for your contribution to the Arduino community @michael_uray!

michael_uray:
any comments regarding the style or functionality are welcome.

I ran my Bash script that checks for common problems in the metadata and structure (but not the code) of Arduino libraries and sketches on your library and its example sketches and it came up clean, which is very rare. Impressive!

michael_uray:
What is actually the proper way to get a libray into the Arduino IDE Library Manager?

The instructions are here:

Please let me know if you have any questions.

michael_uray:
I have not found an easy to use non-blocking timer / delay library so I created one.

This may be very useful but without proper documentation I can't see it getting much use.

For example this line of code (from your Github page)

output = myTimer1.timerOnOff(input, 2000, 1000);

does not tell me anything.

...R

pert:
The instructions are here:
Library Manager FAQ · arduino/Arduino Wiki · GitHub
Please let me know if you have any questions.

Thanks for the link, I will have a look on it in detail.

Robin2:
This may be very useful but without proper documentation I can't see it getting much use.

For example this line of code (from your Github page)

output = myTimer1.timerOnOff(input, 2000, 1000);

does not tell me anything.

I did improve the documentation on the Github repository.
Is this now something what you would expect as meaningfull documentation? If not, could you provide a link to any other library which provides a good documentation?

I am wondering if I should rename it from muTimer to muDelay to prevent any confusions with hardware timers.

michael_uray:
I did improve the documentation on the Github repository.
Is this now something what you would expect as meaningfull documentation?

It is improved but it's not going nearly as far as what I have in mind. Documentation is a very different thing from examples, although it will probably include examples to illustrate the documentation.

I like to see a suitable introductory essay that explains what a program is for (and, ideally, what it is not intended for) and the situations in which it would be useful.

The essay could discuss the problems with using delay() and explain, with some before-and-after examples how your library makes it easy to produce non-blocking timing.

Maybe have a look at the style of this first chapter of the OpenScad tutorial. I realize that OpenScad is a great deal more complex than your library, so it is just the style I am suggesting.

Another way to think about this is to write the essay that preempts all the new users' questions.

...R

PS ... What would my demo Several Things at a Time be like using your library?

Further improved the documentation.
Implemented trigger functions.

Robin2:
PS ... What would my demo Several Things at a Time be like using your library?

It could get used there to do the LED flashing and to debounce buttons.
Added examples for debouncing inputs and flashing LED.

michael_uray:
Further improved the documentation.

That's a big improvement.

May I make one more suggestion ... that you create an example using your library that is exactly equivalent to your delay() example.

It would probably also help a newbie if you extend your delay() example (and the library version) so they are complete compilable programs. (Sorry, that's 2 suggestions)

PS ... What would my demo Several Things at a Time be like using your library?

It could get used there to do the LED flashing and to debounce buttons.

I was (am) hoping to tempt you into writing my demo using your library so I could compare the two :slight_smile:

...R

Good suggestions, suggestions added.

Much better.

In your delay() example I think the LED is on for 100 and off for 500. I think you have it the other way round in your muTimer example. That could confuse people.

Separately, I often use millis() like this (assume that another part of the program set the value for timeWhenSomethingHappened)

if (millis() - timeWhenSomethingHappened >= interval) {
  doThis()
  doThat()
}

How would I do that sort of thing using muTimer?

...R

Robin2:
In your delay() example I think the LED is on for 100 and off for 500. I think you have it the other way round in your muTimer example. That could confuse people.

I double checked the LED flashing on my Arduino Mega unit and with both examples the LEDs are ON for 100ms and OFF for 500ms.
The only difference was the initial run of the loop(), it started with ON in the delay() example and with OFF in the muTimer example, now both are (hopefully) exactly identical.

Robin2:
Separately, I often use millis() like this (assume that another part of the program set the value for timeWhenSomethingHappened)

if (millis() - timeWhenSomethingHappened >= interval) {

doThis()
  doThat()
}




How would I do that sort of thing using muTimer?

I understand that your code looks like this:

if (somethingHappens)
{
   timeWhenSomethingHappened = millis();
}

if (millis() - timeWhenSomethingHappened >= interval)
{
  doThis();
  doThat();
}

The same thing should work then on this way with muTimer:

if (somethingHappens)
{
   myTimer1.resetTimer();
}

if (myTimer1.timerOn(1, interval)) // or use timerOnTrigger() if you want to execute the code just once when timer elapses
{
  doThis();
  doThat();
}

The SerialTimerOnTriggerReset example shows the usage of resetTimer().
So far as I can see would cause your example a problem if somethingHappens stays true for longer as the uint32_t range in msec (~49 days) minus the interval, your condition would get then false again.
The muTimer library should not have this problem, since it only gets active if (output != input). If the timer is already elapsed it does not care anymore about the time difference.

michael_uray:
now both are (hopefully) exactly identical.

This line of code

LED1 = myTimer1.timerOnOff(!LED1, 500, 100);

suggests to me that it will be ON for 500 and off for 100.

For it to work the other way I would expect the function to be named timeroffOn()

Maybe it would be less confusing to name it timerHighLow() to indicate the return values. Then it is up to the user whether a HIGH or a LOW is used to turn something on.

ANOTHER THING ...
I had not thought about it before now but I don't understand the purpose of the first parameter in this code

LED1 = myTimer1.timerOnOff(!LED1, 500, 100);

Why is the timer linked to the state of the LED?

The same thing should work then on this way with muTimer:

Many thanks for that

The SerialTimerOnTriggerReset example shows the usage of resetTimer().

I don't like it when programmers only use an example to explain something. Examples on their own only demonstrate one particular situation. If the reader has another usage in mind the example can be useless. There should be explanatory text and then an example can used to illustrate the text.

(And your URL is incorrect - but I did find the example)

...R

Robin2:
This line of code

LED1 = myTimer1.timerOnOff(!LED1, 500, 100);

suggests to me that it will be ON for 500 and off for 100.

For it to work the other way I would expect the function to be named timeroffOn()

Maybe it would be less confusing to name it timerHighLow() to indicate the return values. Then it is up to the user whether a HIGH or a LOW is used to turn something on.

The basic idea of this function was to create an onDelay and an offDelay. So it is not the onTime, it is the delay time to switch it on.
I did rename the function variables
delayOnTime -> delayTimeSwitchOn
and
delayOffTime -> delayTimeSwitchOff
to make it more clear what it means.

Robin2:
ANOTHER THING ...
I had not thought about it before now but I don't understand the purpose of the first parameter in this code

LED1 = myTimer1.timerOnOff(!LED1, 500, 100);

Why is the timer linked to the state of the LED?

To send the inverted output back to the input just restarts the timer evertime when the time is elapsed.
On this way it clears the input as soon as the output gets set to start the switch off delay.

This is what the timerOnOff() function does.

// in : _______------------______---______________------------_------
// out: ___________----------_________________________---------------

It sets the output delayed to the input by the given time durations.

If you would not send the inverted output back, then it would look like as followed.

LED1 = myTimer1.timerOnOff(1, 500, 100);
// in : --------------------------------------------------------------
// out: ___________---------------------------------------------------

I did create in the meanwhile a new function timerCycleOnOff() which is better to use for LED flashing or other cyclically intervals.
It uses offTime which equals the time the LED would be off and onTime which eqals the time the LED would be on.

bool timerCycleOnOff(uint32_t offTime, uint32_t onTime)

// example with timerCycleOnOff() which does the same as the other LED flashing samples before
LED1 = myTimer1.timerCycleOnOff(500, 100);

Robin2:
I don't like it when programmers only use an example to explain something. Examples on their own only demonstrate one particular situation. If the reader has another usage in mind the example can be useless. There should be explanatory text and then an example can used to illustrate the text.

I personally look in the most cases at first into the examples to understand how the library functions work in general in a user program. After that I look into the reference to see which parameters these functions have and which I have to change to adapt it to my application. However, I think this is more a personal preference, I think a documentation should have a reference as well as examples.
The timerReset() function itself is described there in the README.md. Do you think it requires a more detailed description?

Robin2:
(And your URL is incorrect - but I did find the example)

Thanks, I did correct it.

michael_uray:
The basic idea of this function was to create an onDelay and an offDelay. So it is not the onTime, it is the delay time to switch it on

I think the HIGH time and LOW time would be much more intuitive and less ambiguous.

To send the inverted output back to the input just restarts the timer evertime when the time is elapsed.
On this way it clears the input as soon as the output gets set to start the switch off delay.

I can understand what you are getting at but it is extremely unintuitive to my mind. I wonder if you are trying to be too concise.

I think it would be useful to have a free-running function that just does HIGH - LOW - HIGH - LOW all the time. I actually can't think why one would need a repeating HIGH - LOW function that needs an external trigger. I would just use a one-shot timer in that case.

By the way, I won't be in the least offended if you ignore my suggestions.

...R

Robin2:
I can understand what you are getting at but it is extremely unintuitive to my mind. I wonder if you are trying to be too concise.

The first intention was to create just an on/off delay which ended up in the timerOnOff() function. This one could get used for example to debounce a button in both positions with just one function, or to add any other on/off delay to any input.
Then I added the timerOn() and timerOff() functions which either provide on or off delays. These functions are similar as the IEC timer functions ton() and tof() which are well known in the PLC programming according to IEC 61131. Later its trigger functions to allow a single trigger when the time elapsed.

The LED example there was just a way how you could do it with this function. The purpose of this function actually was not to create such flashing intervals, but it could get done on this way. I have a similar function on the PLC system on which I program and maybe I am used to this style, but probably not others.

Robin2:
By the way, I won't be in the least offended if you ignore my suggestions.

I absolutely do consider them.

Robin2:
I think it would be useful to have a free-running function that just does HIGH - LOW - HIGH - LOW all the time. I actually can't think why one would need a repeating HIGH - LOW function that needs an external trigger. I would just use a one-shot timer in that case.

I added in the meanwhile the timerCycle() function which is much better to create a flashing LED and it does not have any confusing "OnOff" in its name.

bool timerCycle(uint32_t offTime, uint32_t onTime)

// example: LED off 4000ms, LED on 2000ms
LED1 = myTimer1.timerCycle(4000, 2000);

// out: ____--____--____--____--____

michael_uray:
The first intention was to create just an on/off delay which ended up in the timerOnOff() function. This one could get used for example to debounce a button in both positions with just one function,

So just call it muDebounce() ?

Then I added the timerOn() and timerOff() functions which either provide on or off delays. These functions are similar as the IEC timer functions ton() and tof() which are well known in the PLC programming according to IEC 61131. Later its trigger functions to allow a single trigger when the time elapsed.

99% of Arduino folks will not be starting from a knowledge of PLCs so compatibility is irrelevant and the transfer of understanding even less relevant.

In my mind functions should have simple and obvious names so that the user does not have to scratch his head (or check the manual) to remember what they are for or how to use them. Also "obvious" should mean "obvious in the context of the user's existing knowledge" (not the programmers existing knowledge).

That may mean having more functions in a library, several of which may use near-identical code. Or perhaps one function would call another after adding some parameter so the user would not have to.

...R

Robin2:
So just call it muDebounce() ?
99% of Arduino folks will not be starting from a knowledge of PLCs so compatibility is irrelevant and the transfer of understanding even less relevant.

In my mind functions should have simple and obvious names so that the user does not have to scratch his head (or check the manual) to remember what they are for or how to use them. Also "obvious" should mean "obvious in the context of the user's existing knowledge" (not the programmers existing knowledge).

My intention was to create a simple generic on- and off-delay as for example a classic time delay relay would provide.
Such an on/off delay can get used to debounce a switch or a button, but it is not its main purpose. Its actual main purpose is to provide an on and off delay for any digital signal.
I did rename the timerOnOff() function in the meanwhile to delayOnOff() to make it easier to understand by its name. I also did consider to name it delayHighLow or delayTrueFalse, but I think on- and off delay would be the thing what most of the people understand.

Robin2:
That may mean having more functions in a library, several of which may use near-identical code. Or perhaps one function would call another after adding some parameter so the user would not have to.

I have this done for this reason on a couple functions, for example with the delayOn() and delayOff() functions which internally just call delayOnOff().

Means now the functions
delayOn()
delayOff()
delayOnOff()
provide simple on and off delays for any digital signal.

The function cycleOnOff() provides a simple cyclically on/off output, for example to blink a LED.

cycleTrigger() allows to run periodically any action once after each cycle.

Noted.

Best wishes with the project.

...R

Robin2:
Noted.

Best wishes with the project.

Thank you very much for your support here Robin, I appreciate that.
You definitly helped me to improve the documentation very much as well as to find the right names for the functions.

PS:
It looks as such a library is like an anthill, there is always something to do, to improve or extend it.

michael_uray:
PS:
It looks as such a library is like an anthill, there is always something to do, to improve or extend it.

Probably the reason I have never felt like writing a library. :slight_smile: :slight_smile:

And once you start extending or enhancing a library the issue of backwards compatibility comes to the fore.

...R

pert:
The instructions are here:
Library Manager FAQ · arduino/Arduino Wiki · GitHub
Please let me know if you have any questions.

Thanks for the instructions, I was able to get the library added to the library manager and it is already showing up there.

But for some reason does it not show up on the Arduino website in the section timing, even the section got choosen properly in the library.properties file.

Is there something else required to do, or does it just take some more time to show up there?