Simple Delays, non Blocking & timer free

Ok, this has been done in different ways before so why again? Hopefully to add some insight as to why one would want to use different delay functions.

You all should be familiar with delay() - it is a simple way of creating a program delay.
pro - simple
con - it is blocking and it uses timer0

Sometimes you come on a library (example RadioHead) which intensively uses internal timers. In some cases this means that not only is the delay() function disrupted, so is millis(). Of course, delay also is blocking which can stop the RadioHead reception in its tracks. What alternatives?

Two Ways

One a non blocking function which allows other operations to continue and does not require the use of interupts. (great as long as timer0 functions are not being modified by something else). This is the use of millis(), a system timer showing elapsed time from processor startup.

millis() based delay;:

nt period = 1000;
unsigned long time_now = 0;
 
void setup() {
    Serial.begin(115200);
}
 
void loop() {
    time_now = millis();
   
    Serial.println("Hello");
   
    while(millis() < time_now + period){
        // add the code you want to keep running here
        //wait approx. [period] ms
    }
       // handle whatever you want to handle after the pause here, than start allover again
}

** OR BETTER YET :**
** try this tutorial**

Blink without Delay - Arduino Tutorial

TWO - a blocking delay, but one that does NOT use timers (timer0, timer1, or timer2) and is able to work with libraries which have a lot of timing issues or which corrupt millis() or timer0 counts.

delayMicroseconds

here is a code snippet for a function to give a delay specified in seconds. There is no particular limitation on this although if you have really long delays and do NOT have to worry about using timers, I would recommend interupt timers and using ISRs.

void ntDelay(byte t){    // non timer delay in seconds
  for (byte i = 0; i < t*1000; i++) {
      delayMicroseconds(1000);
      }
}

So, add these two delays to your programing tool kit and between them, delay() you should almost never have to use interupt timers.

enjoy

Your second example achieves slightly less than nothing. Sorry.

1 Like

lastchancename:
Your second example achieves slightly less than nothing. Sorry.

And your first example is aptly named as "millis() based delay", since although it uses millis() it's still a delay, albeit not a delay() delay, since it sits in the while() with its thumb up its arse.

At least in the link, when they start to use their scheduler they put the millis() stuff in an if() which is cool since it loop()s, but putting it in a while() just makes it a delay.

Hi Lastchance. Sorry it doesn't work for you. That function was pulled from working code. Does a nice delay for a sensor logger/transmitter I built. [using an Arduino nano and ArduinoISP 1.8.10. ]

Of course since like a distance there can't be a time less than nothing so perhaps I'm being obtuse here and not noticing the joke. ha ha. :slight_smile:

delayMicroseconds() is well documented and uses machine processes to waste time, one micro second at a time. 1000 microseconds is one milliseconds and 1000 milliseconds is one second (the t variable). You could without modification get a {blocking} delay of up to 32,767 seconds.


Hi Fishbone,

absolutely correct. I posted a bit from another (referenced) source to make the explanation simple. As shown it is now a blocking delay. This was just for short illustration and thanks for pointing out that it does in this case block. A non blocking example could be found here. ( I should have used this reference to start with now that I think of it, thanks Fishbone)


Non Blocking delay with millis()


So you see, you can't have it all. One can have a non blocking delay using millis(), but that assumes that no other functions/libraries in the sketch are manipulating the built in timers. Or you can have a delay without the use of timers, but end up with a blocking function. Of course, for advanced programmers one can use interrupt timers, just as long as one doesn't use a timer that is being used by another function in your sketch.

BTW - Fishbone, I'm changing the initial URL to this second one for newbies.

fishboneDiagram:
And your first example is aptly named as "millis() based delay", since although it uses millis() it's still a delay, albeit not a delay() delay, since it sits in the while() with its thumb up its arse.

At least in the link, when they start to use their scheduler they put the millis() stuff in an if() which is cool since it loop()s, but putting it in a while() just makes it a delay.

That function was pulled from working code. Does a nice delay for a sensor logger/transmitter I built. [using an Arduino nano and ArduinoISP 1.8.10. ]

I still don’t get it... you’re using microseconds instead of millis() to create a new type of blocking delay that sucks up more cpu cycles...?!

It certainly works, but achieves nothing.

lastchancename:
I still don’t get it... you’re using microseconds instead of millis() to create a new type of blocking delay that sucks up more cpu cycles...?!

It certainly works, but achieves nothing.

Well, it depends on what you mean by nothing. it works, as you said. What it achieves over millis() state machines or delay() which both use timer0 for their operations is that it does the job WITHOUT needing a functioning timer0 and without disturbing timers that other interrupts may be using.

Some libraries (like RadioiHead ASK) with a lot of internal timing work, basically take over timer0. Using millis() or delay() while the other library is loaded will cause unpredictable results. So I guess you could say I achieve nothing. In my case, by using delayMicroseconds I am doing nothing that disturbs the RadioHead object in my program. So perhaps achieving nothing while getting my 'delay' is worth something. no?

I read your comments, but I’m at a loss why using Timer0 is a big deal for 99.9% of program(mer)s.

You simply hook into the timer interrupt (if necessary), and fork out to the function-specific code that needs to be serviced, but in my experience very few Arduino style solutions require microsecond responsiveness... at that point, you’re probably better served with a different, faster core*.

  • in fact, your suggestion could work in those cases if there wasn’t already threading, and ‘multi’ tasking available. (ref ESP ticker class)