for those using millis/micros for non blocking code....

Hi,

I created a small library(attached) for using millis/micros in non blocking code (e.g blink without delay)

comments/ constructive criticism welcomed! :slight_smile:

millis_micros.zip (1.13 KB)

is it an Arduino library? Arduino uses camel-case not underscores. The Arduino code style is Java-like because of origin in Processing.

I recommend publishing libraries to a popular code hosting service like GitHub. This will make your project more visible and easier for people to collaborate on. The Arduino Forum gets so much activity that things are buried here within a couple days

Example sketches should be placed under the examples subfolder of the library:
millis_micros
|_examples
|_millis_micros
|_millis_micros.ino

Reference: Arduino IDE 1.5: Library specification ยท arduino/Arduino Wiki ยท GitHub

It's a good idea to document the license for all code you publish so there's no ambiguity about how it may be used. A guide to some popular open source licenses is here:

Of course you are welcome to license your work however you like.

pert:
I recommend publishing libraries to a popular code hosting service like GitHub.

ah.. yes... wouldn't i be nice is the forum has a repository or use a common sign-in with it... could not be asked to create another account just for one upload

Juraj:
is it an Arduino library? Arduino uses camel-case not underscores. The Arduino code style is Java-like because of origin in Processing.

Yes I have used it with a UNO... whether it's using what would be a "standard" arduino library guideline... no idea... just based myself on other libraries that I have found on the web and used

sherzaad:
ah.. yes... wouldn't i be nice is the forum has a repository or use a common sign-in with it... could not be asked to create another account just for one upload

If you do post to Github, you can add a markdown file to illustrate how to use it, and a json file which will help anyone using Arduino IDE to pull it directly into their sketch using the library manager.

sherzaad:
comments/ constructive criticism welcomed! :slight_smile:

If you want comments why not post the code here so we don't have to download a ZIP file.

...R

Nice.

I have the personal opinion that writing a library to replace a simple if-else structure is overkill. "Timer libraries" is just a crutch for those unable(unwilling?) to understand keeping them from progressing.

But, it is a nice short library. Actually, I mean that. Totally devoid of helpfull comments why it does what it does, in particular there is no comment that the elapsedtime() has a optional argument which resets that timer to a new interval. Learned something new today there, didn't know that syntax was allowed.

And I concur on it was short and sweet enough to include inline in your post. Makes it searchable, too.

Robin2:
If you want comments why not post the code here so we don't have to download a ZIP file.

...R

to show how I used the library I created... but for the sake of visibility I now post the code:

ms_us_Timer.h file:

#ifndef	MS_US_TIMER_H
#define	MS_US_TIMER_H

//millisecond timer class using millis()
class mstimer {
  private:
    unsigned long _oldtime;
    unsigned long _period;

  public:
    //returns if time has elapsed or not
    inline uint8_t checkTime()
    {
      if (_period > 0 && millis() - _oldtime >= _period) {
        _oldtime = millis();
        return 1;
      }
      else return 0;
    }

    //update period
    inline void setTime(unsigned long period) {
      //using setTime to set period=0 essentially disables the timer
      _period = period;
      _oldtime = millis();
    }

    //constructor
    mstimer(unsigned long period = 0)
    {
      _oldtime = millis();
      _period = period;
    }

    //deconstructor
    //~mstimer() {}
};

//microsecond timer class using micros()
class ustimer {
  private:
    unsigned long _oldtime;
    unsigned long _period;

  public:
    //returns if time has elapsed or not
    inline uint8_t checkTime()
    {
      if (_period > 0 && micros() - _oldtime >= _period) {
        _oldtime = micros();
        return 1;
      }
      else return 0;
    }

    //update period
    inline void setTime(unsigned long period) {
      //using setTime to set period=0 essentially disables the timer
      if (period > 0) {
        _period = period;
        _oldtime = micros();
      }
    }

    //constructor
    ustimer(unsigned long period = 0)
    {
      _oldtime = micros();
      _period = period;
    }

    //deconstructor
    //~ustimer() {}
};

#endif

example sketch:

#include "ms_us_Timer.h"

mstimer ms_t1(500); //create a 500ms timer
mstimer ms_t2(1000); //create a 1000ms timer
uint8_t i = 0;

void setup() {

  // put your setup code here, to run once:
  Serial.begin(115200);
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);

}

void loop() {
  
  if (ms_t1.checkTime()) {
    if (i == 50) {
      Serial.println("t1 disabled");
      digitalWrite(13, LOW);
      ms_t1.setTime(0); //disable t1. could have also used this function to change the timer period
    }
    else {
      digitalWrite(13, !digitalRead(13));
      Serial.println(digitalRead(13));
    }
    ++i;
  }
  else if (ms_t2.checkTime()) {
    Serial.println("t2 triggered!");
  }

}

Thanks. Can you also post a program that illustrates how the library is used?

...R

Delta_G:
Just posted this on another thread. Thought I'd share here.

Here is my simple universal millis timer library. It's the single line of code at the top of this example.

#define BWoD(x)  for(static unsigned long pm = millis(); millis() - pm >= x; pm = millis())

const byte ledPin = 13;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);

}

void loop() {

BWoD(500){
    digitalWrite(ledPin, !digitalRead(ledPin));
    Serial.print("Blink @ ");
    Serial.println(millis());
  }
  BWoD(1000){
    Serial.print("One Second Timer @");
    Serial.println(millis());
  }
  BWoD(333){
    Serial.print("3 Hz Timer @");
    Serial.println(millis());
  }

}

correct me if I'm wrong but is this not a blocking code?

#define BWoD(x) for(static unsigned long pm = millis(); millis() - pm >= x; pm = millis())

the way I read it, the 'for' loop need to completed before the code can move on... could you teach how the macro works please?

sherzaad:
correct me if I'm wrong but is this not a blocking code?

#define BWoD(x) for(static unsigned long pm = millis(); millis() - pm >= x; pm = millis())

the way I read it, the 'for' loop need to completed before the code can move on... could you teach how the macro works please?

The for loop checks the condition before doing the loop, so it exits until the condition is true, then runs the loop, and does the afterthought, which insures the loop is run only once. Anywhere BWoD(x) is found in the program is replaced with this same for loop, as if the for loop were typed in it's place.

Delta_G:
Here is my simple universal millis timer library. It's the single line of code at the top of this example.

Without wishing to sound in any way unkind I can't see how that is any more obvious for a newbie than the "raw" use of millis().

And I am still waiting for @sherzaad to post an example showing how his library is used.

IMHO the real problem for a newbie is the conversion (both in code and in mindset) from delay() to non-blocking code. I don't believe that packaging millis() in a fancy box helps with that. There is simply no non-blocking function that can replace delay() using a simple find-and-replace.

...R

Robin2:
Without wishing to sound in any way unkind I can't see how that is any more obvious for a newbie than the "raw" use of millis().

I would agree that the raw use of millis() is much more friendly to new programmers. Intermediate programmers get to a point where they are tired of repeating the same blocks of code, arrays of previousMillis etc. and wonder if there is a simple way to organize everything needed to "Blink Without Delay". I personally wouldn't go with a macro or library, but I will start organizing my timing by using for loops.

Delta_G:
Here is my simple universal millis timer library.

The comma operator may get you to a version that does not drift.

sherzaad:
comments/ constructive criticism welcomed!

Get rid of the empty destructors.

sherzaad:
comments/ constructive criticism welcomed!

inline uint8_t elapsedtime

Don't bother with "inline". The compiler / optimizer both ignore it.

sherzaad:
comments/ constructive criticism welcomed!

//returns 1 if period is reached or allows user to change the period set

Why not bool / false / true?

Robin2:
And I am still waiting for @sherzaad to post an example showing how his library is used.

I updated reply #7 with the example

Delta_G:
I'm just being tricky with how a for loop works. But it is really no different from the standard BWoD code. To be sure this isn't a normal for loop as it would never repeat. I'm just using the form of a for to collect all the stuff that has to happen for BWoD into one line.

Thanks for the explanation (to Perehama as well).

It's just I never seen a for loop used like that before. In any case I think it's a pretty compact code that does the job and useful if you are running many things as the "same" time with millis/micros... which was the reason I made the classes (to save me repeating code and increasing my variables).

This macro is definitely going in my library of codes to keep! :slight_smile:

Delta_G:
Oh wait I see: The static was throwing me off making me forget that the first bit runs every time too.

#define BWoD(x)  for(static unsigned long pm = millis(), unsigned long cm = millis(); cm - pm >= x; pm += x)

Like I said that was originally designed not for BWoD but as part of a demonstration on how for loops work.

#define BWoD(x) for(static unsigned long pm = millis(), unsigned long cm = millis(); cm - pm >= x; pm += x)

will not compile in IDE but if I change it to

#define BWoD(x) for(static unsigned long pm = millis(), long cm = millis(); cm - pm >= x; pm += x)

it compiles.

will that not have the same issue mentioned in reply #18?