
Heute werden wir über ein so relevantes Thema wie Timer und Multitasking auf Arduino sprechen. Der Grund für das Schreiben dieses Artikels waren die Vorlesungen von
Oleg Artamonov @olartamonov für
MIREA- Studenten innerhalb
der Samsung IoT Academy , oder besser gesagt, Olegs Aussage, Zitat (2. Vorlesung, 1:13:08):
"Es gibt zum Beispiel Aufgaben, für die die meisten Arduino-Treiber, insbesondere Anfänger, unterbrochen werden können. Bitten Sie sie, mit fünf verschiedenen LEDs mit unterschiedlichen Frequenzen und Perioden zu blinken, damit für jede LED eine andere Periode individuell geändert werden kann ..."
Nach Olegs Aussagen zu urteilen, hat er ein sehr falsches Verständnis von Arduino im Allgemeinen und von „Arduino“ im Besonderen. Das Blinken mit fünf LEDs in den von ihm angegebenen Modi ist für Arduino eine absolut triviale Aufgabe, und für
Arduino Mega Server ist es überhaupt keine Aufgabe, sondern ein echtes Missverständnis - Multitasking wird durch seine regulären Mittel organisiert, die leicht Hunderte verschiedener Einheiten (LEDs, Servos, Schrittmotoren usw.) steuern. d.) in Echtzeit.
Lassen Sie uns gemeinsam herausfinden, wie Multitasking auf Arduino organisiert werden kann, und gleichzeitig den
MIREA- Schülern helfen, die Stereotypen der Wahrnehmung zu beseitigen, die ihnen in Bezug auf das soziokulturelle und technologische Phänomen unserer Zeit namens
Arduino auferlegt wurden.
Vorträge von Oleg Artamonov
Wir müssen Tribut zollen, Olegs
Vorträge selbst sind gut - sie bieten viele nützliche und gut strukturierte Informationen über Mikrocontroller, und ich würde jedem, der sich für dieses Thema interessiert, empfehlen, sich mit ihnen vertraut zu machen. Der einzige Nachteil dieser Vorträge schien mir offener Techno-Snobismus in Bezug auf Arduino zu sein, der in ihnen als „Prügelknabe“ auftritt.
Insbesondere machte Oleg in allen Vorträgen zwingende Aussagen über die Ungeeignetheit von Arduino für den Aufbau komplexer Multitasking-Systeme, was einfach der Wahrheit und der tatsächlichen Praxis widerspricht.
Auf Arduino können Sie erstaunliche Multitasking-Systeme erstellen, in denen Dutzende und Hunderte von Einheiten (LEDs, Sensoren, Aktoren, Servos, Schrittmotoren, drahtlose und drahtgebundene Schnittstellen usw.) gleichzeitig im (Pseudo-, natürlich) Multitasking-Modus arbeiten.
Wir werden für Beispiele nicht weit gehen. Hier ist das Projekt des
Wintergartens („Smart Greenhouse“), in dem die folgenden Einheiten in Echtzeit im Multitasking-Modus arbeiten:
Die Topologie eines verteilten nRF24-Controllers mit einer Vielzahl verbundener Geräte in Echtzeit. Der Benutzer befasst sich nur mit der „Basis“, die Arbeit des nRF24-Partners ist für ihn völlig transparent. Und ja, das ist Arduino.An der "Basis":
- 7 Servos
- 9 Schrittmotoren
- 6 Relais
- 3 Bodenfeuchtesensoren
- 2 Lichtsensoren
- Wasserstandsensor
- Feuchtigkeits- und Lufttemperatursensor
Auf nRF24 des Remote-Teils:
- 12 Bodenfeuchtesensoren
- 12 Relais
- 3 Schrittmotoren
- 2 Lichtsensoren
- Wasserstandsensor
Darüber hinaus arbeitet der nRF24 selbst in Echtzeit zwischen den beiden verteilten Teilen des Systems und der Ethernet-Schnittstelle des Servers und der Server-Engine, die eine Webbenutzeroberfläche des Systems bereitstellt.
Insgesamt funktionieren in Echtzeit im Multitasking-Modus mindestens 60 Entitäten auf dem 8-Bit-Mega (und dies berücksichtigt nicht die vielen Dienste des AMS-Betriebssystems selbst, mit denen sich die Anzahl der Entitäten 100 nähert). Was offensichtlich nicht mit der Aussage übereinstimmt, dass "echtes Multitasking auf dem Arduino unmöglich ist und es problematisch ist, selbst mit fünf LEDs darauf zu blinken".
Ein paar Worte zur Verteidigung von Arduino
(Obwohl es offensichtlich ist, dass Arduino als soziokulturelles und technologisches Phänomen mit einer millionenschweren Armee von Fans und vielen tausend erstaunlichen Projekten keinen Schutz benötigt.)
Ich habe viele Male gesagt und werde noch einmal wiederholen, dass Arduino in seiner Softwarekomponente tatsächlich nur eine der möglichen Abstraktionsebenen (wie jede andere) mit ihren eigenen Vor- und Nachteilen ist. Und es gibt absolut keinen Unterschied für den Benutzer, was sich in seinem kleinen Stück Silizium „dreht“ - das „reine“ Arduino, RTOS, RIOT OS, AMS oder eine andere mathematische Abstraktion der Darstellung und Verwaltung der Eisenressourcen des Controllers.
Es ist wichtig, dass der Benutzer seine Probleme löst - damit der Controller die Pflanzen bewässert, das Licht einschaltet, die Vorhänge steuert usw. Das Hauptproblem liegt nicht in den in der Entwicklung verwendeten Werkzeugen, sondern in der Fähigkeit, sie zu verwenden, und, kitschig, in der Vorstellungskraft und der technischen Vision des Entwicklers selbst.
Wie funktioniert es
Multitasking auf Mikrocontrollern kann für sich genommen auf unterschiedliche Weise organisiert werden. In diesem Fall werden wir über das einfachste sprechen - Prozesse wechseln sich ab und geben es freiwillig weiter, nachdem sie ihr Zeitquantum verwendet haben. Diese Methode ist natürlich nicht ohne offensichtliche Mängel, aber wie sie sagen, ist die Praxis ein Kriterium der Wahrheit und hat sich unter realen Bedingungen bewährt: Sie wird sowohl in Standard-
Arduino Mega Server- Distributionen als auch in vielen Projekten auf
AMS Pro verwendet . Und diese Systeme arbeiten rund um die Uhr und haben die Betriebszeit in vielen Monaten störungsfreien Betriebs bestätigt.
Dies ist ein Hinweis auf ungefähr hundert Entitäten eines verteilten nRF24-Systems, die unabhängig in Echtzeit verwaltet werden. Achten Sie auf die letzten beiden CPU-Anzeigen - selbst beim 8-Bit-Mega ist die Prozessorlast Null (dh das System ist vollständig frei).Ein bisschen über Timer
Um die Steuerung komplexer Systeme zu organisieren, reicht es nicht aus, nur die Steuerung zwischen Prozessen zu übertragen, und neben der automatischen Steuerungsübertragung an AMS werden verschiedene Arten von Zeitgebern verwendet: zyklisch, zyklisch mit einer bestimmten Anzahl von Wiederholungen (Stapel), einzeln, zufällig, gemischt usw. All dies ist organisiert native Mittel von Arduino und verwendet keine Interrupts oder direkte Programmierung von Mikrocontroller-Timern (aber Interrupts werden natürlich vom System "für ihren beabsichtigten Zweck" verwendet).
Was wiederum direkt der Aussage widerspricht: "Es wird genug Eisen-Timer für 3 LEDs geben, von da an werden Arduinisten Probleme haben." Nicht starten. Alle Arten von Timern stehen uns in beliebiger Menge zur Verfügung. Und wenn gewünscht, können wir uns noch neuer und willkürlich exotischer machen.
Hauptfall
Der Hauptfall für diese Art von Multitasking-Organisation besteht darin, den sogenannten "nicht blockierenden" Code zu erstellen, dh Code, der die delay () - Funktion nicht verwendet, wodurch das Programm einfach für eine bestimmte Zeit angehalten wird.
Echtzeit
Das beschriebene Verfahren zur Implementierung von Multitasking kann als "Soft-Realtime" bezeichnet werden. Die typische Verzögerungszeit im System beträgt 10 ms (die Spitzenverzögerungen können jedoch viel länger und nicht standardisiert sein). Dies führt zu bekannten Einschränkungen des Anwendungsspektrums dieser Lösung, ist jedoch für die meisten "Haushalts" -Aufgaben (und nicht nur) perfekt geeignet (siehe Beispiel oben).
Wenn Sie eine strengere Echtzeitsteuerung benötigen, erfordert dies eine spezielle Optimierung des Codes für eine bestimmte Aufgabe, eine Umstrukturierung der Architektur oder in extremen Fällen die Zuweisung eines separaten Controllers für bestimmte Funktionen. Hervorheben eines
separaten Effekt-
Controllers für einen intelligenten LED-Streifen.
Dies ist eine allgemeine theoretische Beschreibung der Arbeit des Multitasking in Arduino im Allgemeinen und in AMS im Besonderen. Nun wenden wir uns der Betrachtung praktischer Beispiele zu.
Zyklus-Timer

Betrachten Sie die Implementierung der einfachsten zyklischen Timer. Dies sind Timer (in der Terminologie von AMS-Zyklen), die in bestimmten, vordefinierten Zeitintervallen aktiviert werden und zur Aktivierung zyklischer Prozesse verwendet werden.
Im Allgemeinen ist es besser, Timer programmgesteuert als Objekte zu entwerfen, aber in der Standardauslieferung von Arduino Mega Server werden diese Timer als Funktionen implementiert. Daher werden wir sie zunächst in dieser Hypostase berücksichtigen.
Die Verwendung von zyklischen Timern ist sehr einfach: Setzen Sie einfach den Code, der regelmäßig ausgeführt werden muss, in die Klammern der if-Anweisung. Wenn Sie ein anderes Triggerintervall verwenden müssen, verwenden Sie einfach die gewünschte Variable anstelle von cycle1s. Sie können so viele verschiedene Zyklen ausführen, wie Sie möchten - selbst auf einem 8-Bit-Mega-System können Hunderte solcher Timer problemlos verarbeitet werden (natürlich müssen Sie sich daran erinnern, dass der aufgerufene Code nicht blockiert).
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,
. , , .