Timers and multitasking on Arduino

image

Today we will talk about such an important topic as timers and multitasking on Arduino. The reason for writing this article was the lectures of Oleg Artamonov @olartamonov for MIREA students as part of the IoT Academy of Samsung , or rather, the statement of Oleg, quote (2nd lecture, 1:13:08):
“There are, for example, tasks for which most arduinschik can be broken, especially beginners, ask them to flash with five different LEDs with different frequency and period and so that another period can be changed individually for each LED ...”

Judging by the statements of Oleg, he has a very wrong idea about the Arduino in general and about the “Arduinschiki” in particular. The flashing of five LEDs in the modes designated by it is an absolutely trivial task for Arduino, and for the Arduino Mega Server it is not a task at all, but a real misunderstanding - its multi-tasking is organized by its regular means, which easily controls hundreds of different entities (LEDs, servo drives, step motors, etc.). e.) in real time.

Let's work out how to organize multitasking on Arduino, and at the same time help MIREA students get rid of stereotypes of perception imposed on them in relation to the socio-cultural and technological phenomenon of our time called Arduino .

Lectures of Oleg Artamonov


We must pay tribute, Oleg's lectures themselves are good - they give a lot of useful and well-structured information about microcontrollers and I would recommend to all interested in this issue to get acquainted with them. The only drawback of these lectures seemed to me overt techno-snobbery in relation to the Arduino, which acts in them in the role of "whipping boy".

In particular, throughout all the lectures, Oleg makes categorical statements about the unsuitability of the Arduino to build complex multi-tasking systems, which simply contradicts the truth and real practice.

Arduino can make stunning multi-tasking systems in which dozens and hundreds of entities (LEDs, sensors, actuators, servo drives, stepping motors, wireless and wired interfaces, etc.) work simultaneously in a (pseudo, naturally) multitasking mode.

We will not go far for examples. Here is the project of the Winter Garden (“Smart Greenhouse”) in which the following entities work in real-time in multitasking mode:

image

Topology distributed nRF24 controller with a huge number of connected and working in real time equipment. The user deals only with the “base”, the work of the nRF24 partner is completely transparent to him. And, yes, this is the Arduino.

On the base":

- 7 servos
- 9 stepping motors
- 6 relays
- 3 soil moisture sensors
- 2 light sensors
- Water level sensor
- Sensor of humidity and air temperature

On the nRF24 remote part:

- 12 soil moisture sensors
- 12 relays
- 3 stepper motors
- 2 light sensors
- Water level sensor

In addition, the nRF24 itself functions in real time between two distributed parts of the system and the Ethernet interface of the server and the server engine providing the web-based user interface of the system.

Total, in real time, in multitasking mode, on an 8-bit Mega, at least 60 entities operate (and this is not counting the many services of the AMS operating system itself, with them the number of entities will approach one hundred). What obviously doesn’t agree with the statement that "real multi-tasking is impossible on the Arduino and it is problematic to flash even five LEDs on it".

A couple of words in defense of the Arduino


(Although it is obvious that Arduino, as a socio-cultural and technological phenomenon with a multimillion army of fans and many thousands of amazing projects, does not need protection.)

I have said many times and will repeat once again that in its software component, Arduino is, in fact, just one of the possible levels of abstraction (like any other) with its own advantages and disadvantages. And the user has absolutely no difference what is “spinning” inside his small piece of silicon - the “pure” Arduino, RTOS, RIOT OS, AMS or some other mathematical abstraction of the representation and control of the iron resources of the controller.

It is important for the user to solve his problems - the controller would water the plants, turn on the light, control the curtains, etc. And the main problem is not in the tools used in the design, but in the ability to use them and, tritely, in the imagination and engineering vision of the developer himself.

How it works?


By itself, multitasking on microcontrollers can be organized in different ways, in this case we will talk about the simplest - the processes in turn get control and voluntarily give it away after using their time slice. This method, of course, is not without obvious flaws, but, as they say, practice is a criterion of truth and it has proven itself in real conditions: it is used both in standard Arduino Mega Server distributions and in many AMS Pro projects. And these systems work 24/7 and have confirmed uptimes for many months of trouble-free operation.

image

This is an indication of about a hundred entities of a distributed nRF24 system, managed independently of each other in real time. Pay attention to the last two indicators "CPU" - even on an 8-bit Mega, the processor load is equal to zero (that is, the system is completely free).

A little bit about timers


To organize the management of complex systems, it is not enough just to transfer control between processes in turn and, along with automatic transfer of control, AMS uses various types of timers: cyclic, cyclic with a given number of repetitions (packet), single, random, mixed, etc. Everything is organized Arduino native tools and does not use interrupts or direct programming of microcontroller timers (but interrupts are, of course, used by the system “for their intended purpose”).

Which again comes into direct contradiction with the statement “There will be enough iron iron timers for 3 LEDs, problems will start further with the arduinschikov”. Will not start. Any types of timers are available to us in any quantity. And, if desired, we can make ourselves some more new and arbitrarily exotic.

Main case


The main case for this type of multitasking organization is to create a so-called “non-blocking” code, that is, a code that does not use the delay () function, which simply pauses the execution of a program for a specified time.

Real time


The described method of multitasking can be described as “soft-realtime”, the typical delay time in the system is 10 ms (but peak delays can be much longer and are not normalized). This imposes known restrictions on the range of application of this solution, but for most “everyday” tasks (and not only) it is perfect, see the example above.

If control is required in a more rigid real time, then this requires special optimization of the code for a specific task, reorganization of the architecture or, in very extreme cases, the allocation of a separate controller for specific functions. As an example, the selection of a separate controller effects smart LED strip.

This is a general theoretical description of the work of multitasking in Arduino in general and in AMS in particular, we now turn to the consideration of practical examples.

Cyclic timers



image

Consider the implementation of the most simple cyclic timers. These are timers (in the terminology of AMS "cycles"), which are turned on at certain predetermined time intervals and are used to activate cyclic processes.

Generally, it is better to program out timers in the form of objects, but in the standard Arduino Mega Server delivery these timers are implemented as functions, therefore, for a start, we will consider them in this aspect.

Using cyclic timers is very simple: just put the code that you need to periodically execute between the brackets of the if statement. If you need to use a different trigger interval, then simply use the desired variable instead of cycle1s. You can do as many different cycles as you want - even on an 8-bit Mega, the system can easily be serviced by literally hundreds of such timers (but, of course, you need to remember that the code you are calling is not blocking).

  if (cycle1s) {
    // ,   , ,  
  }

. :

// Cycles
bool cycle1s  = false;
bool cycle5s  = false;
bool cycle20s = false;
bool cycle30s = false;
bool cycle1m  = false;
bool cycle3m  = false;
bool cycle5m  = false;

.

«Timers»:

/*
  Module Timers
  part of Arduino Mega Server project
*/

// Cycles
unsigned long timeSec;
unsigned long timer1s;
unsigned long timer5s;
unsigned long timer20s;
unsigned long timer30s;
unsigned long timer1m;
unsigned long timer3m;
unsigned long timer5m;

void timersInit() {
  unsigned long uptimeSec = millis() / 1000;
  timeSec  = uptimeSec;
  timer1s  = uptimeSec;  
  timer5s  = uptimeSec; 
  timer20s = uptimeSec;
  timer30s = uptimeSec;
  timer1m  = uptimeSec;
  timer3m  = uptimeSec;
  timer5m  = uptimeSec;
}

void timersWorks() {
  timeSec = millis() / 1000;
    if (timeSec - timer1s  >=  1)  {
                                    timer1s  = timeSec; cycle1s  = true;
    if (timeSec - timer5s  >=  5)  {timer5s  = timeSec; cycle5s  = true;}
    if (timeSec - timer20s >= 20)  {timer20s = timeSec; cycle20s = true;}
    if (timeSec - timer30s >= 30)  {timer30s = timeSec; cycle30s = true;}
    if (timeSec - timer1m  >= 60)  {timer1m  = timeSec; cycle1m  = true;}
    if (timeSec - timer3m  >= 180) {timer3m  = timeSec; cycle3m  = true;}
    if (timeSec - timer5m  >= 300) {timer5m  = timeSec; cycle5m  = true;}
  }
}

void eraseCycles() {
  cycle1s  = false;
  cycle5s  = false;
  cycle20s = false;
  cycle30s = false;
  cycle1m  = false;
  cycle3m  = false;
  cycle5m  = false;
}

. - , . , , .

void loop() {
  timersWorks();

  //   

  eraseCycles();
}


, , . myCycle.

, :

/*
  myCycle Library
  part of Arduino Mega Server project
*/

#ifndef _MYCYCLE_H
#define _MYCYCLE_H

#define MS_500       500
#define MS_01S      1000
#define MS_02S      2000
#define MS_05S      5000
#define MS_10S     10000
#define MS_13S     13000
#define MS_17S     17000
#define MS_20S     20000
#define MS_30S     30000
#define MS_01M     60000
#define MS_03M    180000
#define MS_05M    300000
#define MS_01H   3600000
#define MS_06H  21600000
#define MS_12H  43200000
#define MS_01D  86400000

class myCycle {
  private:
    bool          _go;
    bool          _active;
    unsigned long _start;
    unsigned long _period;
  
  public:
    myCycle(unsigned long per, bool act);
    void reInit(unsigned long per, bool act);
    void reStart();
    bool check();
    bool go();
    void clear();
    
    // active
    bool active();
    void setActive(bool act);
    // period
    unsigned long period();
    void setPeriod(unsigned long per);
}; // class myCycle

#endif // _MYCYCLE_H

:

/*
  myCycle Library
  part of Arduino Mega Server project
*/

#include "myCycle.h"
#include <Arduino.h>

myCycle::myCycle(unsigned long per, bool act) {
  _go     = false;
  _active = act;
  _period = per;
  _start  = millis();
}

// Methods

void myCycle::reInit(unsigned long per, bool act) {
  _go     = false;
  _active = act;
  _period = per;
  _start  = millis();
}

void myCycle::reStart() {
  _start = millis();
}

bool myCycle::check() {
  if (millis() - _start >= _period) {
    _start = millis();
    if (_active) {
      _go = true;
    }
  }
  return _go;
}

bool myCycle::go() {
  return _go;
}

void myCycle::clear() {
  _go = false;
}

// Active

bool myCycle::active() {
  return _active;
}

void myCycle::setActive(bool act) {
  _active = act;
}

// Period

unsigned long myCycle::period() {
  return _period;
}

void myCycle::setPeriod(unsigned long per) {
  _period = per;
}

«» : « ».

:

:

#include "myCycle.h"

:

// Cycles
myCycle cycle500(MS_500, true);
myCycle cycle2s(MS_02S, true);
myCycle cycle5s(MS_05S, true);

:

void timersWorks() {
  cycle500.check();
  cycle2s.check();
  cycle5s.check();
}

void eraseCycles() {
  cycle500.clear();
  cycle2s.clear();
  cycle5s.clear();
}

:

void loop() {
  timersWorks();

  //   

  if (cycle5s.go()) {
    Serial.println(F("cycle5s!"));
  }

  eraseCycles();
}

, , . , / , , , .

Arduino



image

, — . , . , AMS .

()


, . , 3 nRF24. 3 .

/ . .


«», - - .


- , , .

, , . , , , 20 , «», «» , . , «» .

, . — Arduino Mega Server .


, , / , « » . .

— , 8- .


, , Arduino - — — , .

, Arduino Mega Server .


, , Arduino , , , Arduino () .

, , .

P.S.
, 0.17 Arduino Mega Server Arduino Mega, Due, 101 M0, . , , .

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


All Articles