📜 ⬆️ ⬇️

Replacing delay () for non-blocking delays in the Arduino IDE

The first thing a newcomer mastering the Arduino faces is the unpleasant feature of the delay () function — blocking program execution. Many examples on the Internet use this function, but practical application somehow hints that it is better to do without it.

As it should be for a beginner, I invented a bicycle made my implementation of non-blocking delay. The task was as follows:


Looking at the fact that most of the Arduin libraries are made using OOP, I also decided not to stand out and wrote the SmartDelay class, which can be obtained from the github as a zip to add to the Arduino IDE or to make git clone in ~ / Arduino / libraries /
')
The result was this.

#include <SmartDelay.h> SmartDelay foo(1000000UL); //   void loop () { if (foo.Now()) { //       ,    . } //  } 

The Now () method returns true if the interval has passed. In this case, the countdown begins again at the same interval. That is, Now () is automatically “recharged” every time.

Classic LED blinking can immediately complicate up to two blink. For example, light bulbs are connected to legs 12 and 11, they should flash at intervals of 1s and 777ms, respectively.

 #include <SmartDelay.h> SmartDelay led12(1000000UL); SmartDelay led11(777000UL); setup () { pinMode(12,OUTPUT); pinMode(11,OUTPUT); } byte led12state=0; byte led11state=0; void loop () { if (led12.Now()) { digitalWrite(12,led12state); led12state=!led12state; } if (led11.Now()) { digitalWrite(11,led11state); led11state=!led11state; } } 

In the cycle, you can do something else, flashing LEDs will not block the execution of this code.

It is clear that this is not a complete replacement of delay (), which stops the flow for a specified time; you must always write a program as an MCA (a finite state machine mechanism). That is, to store the state and, depending on it, to go to the desired place of the code.

Old version:

 ... action1(); delay(1000); action2(); delay(500); action3(); ... 

New option:

 byte state=0; SmartDelay d(); ... switch (state) { case 0: action1(); d.Set(1000000UL); state=1; break; case 1: if (d.Now()) { action2(); d.Set(500000UL); state=2; } break; case 2: if (d.Now()) { action3(); d.Stop(); state=0; } break; } ... 

The Set method (interval) sets a new interval and returns the old one. Just look at the interval can be Get ();

Stop () stops processing and Now () always returns false.

Start () resumes and Now () starts working as usual.

If you need to slow down the counting time, but do not stop at all, that is, the method Wait (). For example, if the LED 12 blinks and does not blink when the button is pressed, it’s enough to add this code to the loop () in the example with two diodes above:

 ... if (digitalRead(9)) led12.Wait(); ... 

So, with a high signal level on the 9th leg, the diode on 12 will not flash and will continue when 0 appears there.

When the screen is drawn using such a “timer”, for example, and the buttons are processed in parallel, it may be necessary to redraw the screen or part immediately after pressing the button, rather than waiting for the interval to end. To do this, use the Reset () method, after which the next call to Now () returns true. For example:

 SmartDelay display(1000000UL); void loop() { if (btClick()) display.Reset(); //   ,   . if (display.Now()) screenRedraw(); //  . } 

From the bugs I see only that the microsecond counter overflow is not taken into account, but otherwise, yes, it is necessary to clean the code. I don't like how Reset () is made while I think.

I liked the object approach, it allows you to hide all the code in the library, which you can then never look into. Now this little library lives in all my projects :)

Project on GitHub

Source: https://habr.com/ru/post/319184/


All Articles