An Arduino library to make timing easier

I made an arduino library that makes it very easy to do timed events. Its called Every.

#include <Every.h>

Every everyFiveSeconds(5, "seconds");

void doSomething(){
    // Do something every 5 seconds
}

void setup() {
  everyFiveSeconds.setCallback(doSomething);
  // Initialize any necessary hardware or variables here
}

void loop() {
  everyFiveSeconds.update();
}

As you can see, the Every class makes it super easy to do timed things without having to rely on delay and also without having to do any sort of setup other than making the class instance and configuring it.

Also:

Every everyFiveSeconds(5, "seconds");

void setup() {
}

void loop() {
  everyFiveSeconds.update();
  if (everyFiveSeconds.triggered()) {
    Serial.println("Every 5 seconds");
  }
  if(Serial.available()){
    char command = Serial.read();
    if(command == 'p') everyFiveSeconds.pause();
    if(command == 'r') everyFiveSeconds.resume();
  }
}

Every has full support for pause and resume. It can even return how many microseconds it will be until the next trigger.

Whether you are a n00b or hyper 1337, this tool makes programming a lot easier.

2 Likes

Good attempt but …

some constructive feedback

  • update() does not call the callback when delay is over. Your first example would not work.

  • This is not how you compare c-strings. You would need to Use strcmp() especially if you support non const c-strings

Every::Every(unsigned long interval, char* unit) {
  …
  if (unit == "microseconds") {
    _interval *= 1;
  }

(It’s all over the place)

  • Ideally you would not have to waste memory with strings for unit, use an enum for this.

  • The use of micros will make it not suitable for long delays

  • Your time management does not account for rollover

Example here

unsigned long currentTime = micros();
  if (currentTime < _previousTime) {
    _previousTime = currentTime;
  }

Or here

if (_previousTime > currentTime) {
    return 0;
  }

Or here

else if (_previousTime + _interval > currentTime) {

➜ the library requires some rework.

lmao my bad. I added so many features and very excitedly posted it before testing it.

#include <Every.h>

Every everyFiveSeconds(5, "seconds");

void doSomething(){
  Serial.print("test");
}

void setup() {
  Serial.begin(115200);
  everyFiveSeconds.setCallback(doSomething);
  // Initialize any necessary hardware or variables here
}

void loop() {
  everyFiveSeconds.update();
  everyFiveSeconds.trigger();
};

this is the corrected code for the first example, works great.

working on the other stuff now. thanks for your input.

It has now been updated to make use of strcmp. Also, i removed micros and went to just millis() as those will be fine for most use cases and has better characteristics for long delays.

rollover is still not accounted for but is far less of an issue with millis() but its still important, ill get to it. thanks again for your input!!

#include <Every.h>

Every timer(4, "seconds");

void setup() {
  Serial.begin(115200);
}

void loop() {
  timer.update();
  int counter = timer.mapValue(255);
  Serial.println(counter);
};

I've added a mapValue method that makes it very easy to count up from 0 to a given number over a given time span.

Good progress

I think update() should trigger the callback when it’s due rather than having to test it and make that part of your code.

Get rid of the strings, really our small microcontrollers don’t have much memory. No point wasting it with text when a named byte would do. It will also waste less cycles in testing the strings

@ElectronicsWorkshawp
Before writing libraries, it would be worthwhile to study the issue of millis overflow.
Your code is not "overflow-safe".

if (_previousTime + _interval > currentTime) {

Knowledge of unsigned arithmetic is absolutely essential to work properly with time.

Thank you and yes, im working on making it so that trigger doesnt have to be constantly tested in the loop but I feel like its very important for people to be able to just type seconds, milliseconds, etc, because it makes it more readable vs passing a 0 for ms, a 1 for seconds, etc

Thank you and I am aware of that. Working on it. Other than the overflow issue that has already been stated, is there anything else you see that i can improve?

By the way, in general, I'm not sure at all about the usefulness of such libraries. Every beginner MUST learn to work with millis by himself :))))

1 Like

That’s why I am saying use an enum. (If you know what this is)

Ok, well this library is to make arduino programming easier. Its not to teach programming but i understand where you are coming from.

we can go on all day about that and we can say people should not learn digitalRead and just work with registers, etc.

This is a good learning opportunity for @ElectronicsWorkshawp to explore a few things - there are so many of those timing libraries around anyway that it probably won’t get any traction but it’s always respectable to have the courage to put your work out for public feedback.

1 Like

Overflow protection added.

Please upload changes to the github

haha i did NOT know what enum was, at least not by name. I have used it before. Great idea. I googled it a bit and converted it.

#include <Every.h>

Every timer(3000, Every::milliseconds);


void setup() {
  Serial.begin(115200);
}

void loop() {
  timer.update();
  int counter = timer.mapValue(255);
  Serial.println(counter);
};

I did just now.

Your mapped value can only be positive. May be an alternative version (same function name, different parameters) with two longs to form an interval would be useful?

There is a bug here on 8 bits arduino like UNO

_interval *= 1000*60;}

I let you figure it out

Still rollover issue here

else if(currentTime < _previousTime) {
		_previousTime = currentTime;
	  }