
Aujourd'hui, nous allons parler d'un sujet aussi pertinent que les minuteries et le multitâche sur Arduino. La raison de la rédaction de cet article était les conférences d'
Oleg Artamonov @olartamonov pour les étudiants
MIREA au sein de
la Samsung IoT Academy , ou plutôt, la déclaration d'Oleg, citation (2e conférence, 1:13:08):
"Il y a, par exemple, des tâches pour lesquelles la plupart des pilotes Arduino, en particulier les débutants, peuvent être interrompus, leur demander de clignoter avec cinq LED différentes avec des fréquences et des périodes différentes, et de sorte qu'une autre période puisse être modifiée individuellement pour chaque LED ..."
À en juger par les déclarations d'Oleg, il a une idée très fausse sur Arduino en général et sur «arduino» en particulier. Clignoter avec cinq LED dans les modes indiqués par lui est une tâche absolument triviale pour Arduino, et pour
Arduino Mega Server ce n'est pas du tout une tâche, mais un vrai malentendu - le multitâche est organisé par ses moyens réguliers, qui contrôlent facilement des centaines d'entités différentes (LED, servos, moteurs pas à pas, etc.). d.) en temps réel.
Voyons comment organiser le multitâche sur Arduino ensemble, et en même temps aider les étudiants de
MIREA à se débarrasser des stéréotypes de perception qui leur sont imposés en relation avec le phénomène socioculturel et technologique de notre temps appelé
Arduino .
Conférences d'Oleg Artamonov
Nous devons rendre hommage, les
conférences d'Oleg en elles-mêmes sont bonnes - elles fournissent beaucoup d'informations utiles et bien structurées sur les microcontrôleurs et je recommanderais à tous ceux qui s'intéressent à ce problème de se familiariser avec eux. Le seul inconvénient de ces conférences m'a semblé un snobisme technique manifeste concernant Arduino, qui agit en eux comme un «garçon fouetté».
En particulier, tout au long de toutes les conférences, Oleg a fait des déclarations péremptoires sur l'inaptitude d'Arduino à construire des systèmes multitâches complexes, ce qui contredit simplement la vérité et les pratiques réelles.
Sur Arduino, vous pouvez créer des systèmes multitâches incroyables dans lesquels des dizaines et des centaines d'entités (LED, capteurs, actionneurs, servomoteurs, moteurs pas à pas, interfaces sans fil et câblées, etc.) fonctionnent simultanément en mode (pseudo, naturellement) multitâche.
Nous n'irons pas loin pour des exemples. Voici le projet du
Jardin d'hiver («Smart Greenhouse») dans lequel les entités suivantes travaillent en temps réel en mode multitâche:
La topologie d'un contrôleur nRF24 distribué avec un grand nombre d'équipements connectés et en temps réel. L'utilisateur ne s'occupe que de la «base», le travail du partenaire nRF24 lui est totalement transparent. Et oui, c'est Arduino.A la "base":
- 7 servos
- 9 moteurs pas Ă pas
- 6 relais
- 3 capteurs d'humidité du sol
- 2 capteurs de lumière
- capteur de niveau d'eau
- Capteur d'humidité et de température de l'air
Sur nRF24 de la partie distante:
- 12 capteurs d'humidité du sol
- 12 relais
- 3 moteurs pas Ă pas
- 2 capteurs de lumière
- capteur de niveau d'eau
De plus, en temps réel, le nRF24 lui-même fonctionne entre les deux parties distribuées du système et l'interface Ethernet du serveur et le moteur du serveur, qui fournit une interface utilisateur Web du système.
Au total, en temps réel, en mode multitâche, au moins 60 entités fonctionnent sur le Mega 8 bits (et cela ne compte pas les nombreux services du système d'exploitation AMS lui-même, avec eux le nombre d'entités approchera la centaine). Ce qui n'est évidemment pas d'accord avec l'affirmation selon laquelle «le véritable multitâche est impossible sur l'Arduino et il est problématique de clignoter même avec cinq LED dessus».
Quelques mots pour défendre Arduino
(Bien qu'il soit évident qu'Arduino en tant que phénomène socio-culturel et technologique avec une armée de plusieurs millions de fans et des milliers de projets incroyables n'a pas besoin de protection.)
J'ai dit à plusieurs reprises et je répète encore une fois que l'Arduino dans son composant logiciel n'est, en fait, qu'un des niveaux d'abstraction possibles (comme les autres) avec ses propres avantages et inconvénients. Et il n'y a absolument aucune différence pour l'utilisateur ce qui "tourne" à l'intérieur de son petit morceau de silicium - Arduino "pur", RTOS, RIOT OS, AMS ou une autre abstraction mathématique de la représentation et de la gestion des ressources en fer du contrôleur.
Il est important pour l'utilisateur de résoudre ses problèmes - pour que le contrôleur arrose les plantes, allume la lumière, contrôle les rideaux, etc. Et le problème principal ne réside pas dans les outils utilisés dans le développement, mais dans la capacité à les utiliser et, ringard, dans l'imagination et la vision d'ingénierie du développeur lui-même.
Comment ça marche?
En soi, le multitâche sur les microcontrôleurs peut être organisé de différentes manières, dans ce cas, nous parlerons du plus simple - les processus prennent le contrôle à tour de rôle et le donnent volontairement après avoir utilisé leur tranche de temps. Cette méthode, bien sûr, n'est pas sans défauts évidents, mais, comme on dit, la pratique est un critère de vérité et elle a fait ses preuves en conditions réelles: elle est utilisée à la fois dans les distributions
Arduino Mega Server standard et dans de nombreux projets sur
AMS Pro . Et ces systèmes fonctionnent 24h / 24 et 7j / 7 et ont confirmé leur disponibilité pendant plusieurs mois de fonctionnement sans problème.
Il s'agit d'une indication d'une centaine d'entités d'un système nRF24 distribué, géré indépendamment en temps réel. Faites attention aux deux derniers indicateurs CPU - même sur le Mega 8 bits, la charge du processeur est nulle (c'est-à -dire que le système est complètement gratuit).Un peu sur les minuteries
Pour organiser le contrôle de systèmes complexes, il ne suffit pas de transférer le contrôle entre les processus tour à tour et, avec le transfert de contrôle automatique vers AMS, différents types de temporisations sont utilisés: cyclique, cyclique avec un nombre donné de répétitions (batch), unique, aléatoire, mixte, etc. Tout cela est organisé natif d'Arduino et n'utilise pas d'interruptions ou de programmation directe de minuteries de microcontrôleur (mais les interruptions, bien sûr, sont utilisées par le système «pour leur destination»).
Ce qui contredit encore une fois la déclaration: "Il y aura suffisamment de minuteries de fer pour 3 LED, à partir de là , les arduinistes auront des problèmes." Ne commence pas. Tous les types de minuteries sont à notre disposition en toute quantité. Et, si vous le souhaitez, nous pouvons nous rendre plus nouveaux et arbitrairement exotiques.
Cas principal
Le cas principal de ce type d'organisation multitâche est de créer le code dit "non bloquant", c'est-à -dire le code qui n'utilise pas la fonction delay (), qui met simplement le programme en pause pendant un temps donné.
Temps réel
La méthode décrite pour implémenter le multitâche peut être décrite comme «temps réel doux», le temps de retard typique dans le système est de 10 ms (mais les retards de pointe peuvent être beaucoup plus longs et non standardisés). Cela impose des limitations bien connues sur le spectre d'application de cette solution, mais pour la plupart des tâches "domestiques" (et pas seulement) elle est parfaitement adaptée, voir l'exemple ci-dessus.
Si vous avez besoin d'un contrôle en temps réel plus strict, cela nécessite une optimisation spéciale du code pour une tâche spécifique, une restructuration de l'architecture ou, dans des cas très extrêmes, l'allocation d'un contrôleur séparé pour des fonctions spécifiques. Par exemple, mettre en évidence un
contrĂ´leur d' effets
séparé pour une bande LED intelligente.
Il s'agit d'une description théorique générale du travail du multitâche en Arduino en général et en AMS en particulier, maintenant nous passons à la considération d'exemples pratiques.
Minuteurs de cycle

Considérez la mise en œuvre des minuteries cycliques les plus simples. Ce sont des temporisateurs (dans la terminologie des «cycles» AMS), qui sont activés à certains intervalles de temps prédéfinis et sont utilisés pour activer des processus cycliques.
En général, il est préférable de concevoir par programmation des temporisateurs en tant qu'objets, mais dans la livraison standard d'Arduino Mega Server, ces temporisateurs sont implémentés en tant que fonctions.Par conséquent, pour les débutants, nous les considérerons dans cette hypostase.
L'utilisation de minuteries cycliques est très simple: il suffit de mettre le code qui doit être exécuté périodiquement entre les crochets de l'instruction if. Si vous devez utiliser un intervalle de déclenchement différent, utilisez simplement la variable souhaitée au lieu de cycle1s. Vous pouvez effectuer autant de cycles différents que vous le souhaitez - un système, même sur un Mega 8 bits, peut facilement gérer littéralement des centaines de ces temporisateurs (seulement, bien sûr, vous devez vous rappeler que le code appelé n'est pas bloquant).
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

, — . , . , 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,
. , , .