
今天,我们将讨论与Arduino上的计时器和多任务相关的话题。 撰写本文的原因是
Oleg Artamonov @olartamonov 在三星物联网学院的框架
中为
MIREA学生提供的讲座,或者更确切地说,是Oleg的声明,引用(第2讲,1:13:08):
“例如,有些arduino驾驶员(尤其是初学者)可能会被打破,要求他们使用具有不同频率和周期的五个不同的LED闪烁,以便每个LED可以单独更改另一个周期...”
从奥列格(Oleg)的陈述来看,他对Arduino尤其是对“ arduino”有一个非常误解。 以Arduino指示的模式以五个LED闪烁是绝对微不足道的任务,对于
Arduino Mega Server来说这根本不是一项任务,而是一个真正的误解-多任务是通过其常规方式组织的,它可以轻松控制数百个不同的实体(LED,伺服器,步进电机等)。 d。)实时。
让我们弄清楚如何在Arduino上一起组织多任务,同时帮助
MIREA学生摆脱对他们与当今时代称为
Arduino的社会文化和技术现象有关的刻板印象。
Oleg Artamonov的演讲
我们必须致敬,Oleg的
演讲本身很好-它们提供了许多有关微控制器的有用且结构良好的信息,我建议对这个问题感兴趣的每个人都熟悉它们。 在我看来,这些讲座的唯一缺点似乎是关于Arduino的公开技术吹嘘,它在Arduino中充当“鞭打男孩”的角色。
特别是,在所有讲座中,Oleg都强行声明了Arduino不适合构建复杂的多任务系统,这与事实和实际做法相矛盾。
在Arduino上,您可以创建令人惊叹的多任务系统,其中数十个实体(LED,传感器,执行器,伺服器,步进电机,无线和有线接口等)在(伪自然)多任务模式下同时工作。
我们不会走很多例子。 这是
冬季花园 (“智能温室”)的项目,其中以下实体以多任务模式实时工作:
具有大量连接的实时设备的分布式nRF24控制器的拓扑。 用户只处理“基础”,nRF24合作伙伴的工作对他是完全透明的。 而且,是的,这是Arduino。在“基地”:
-7个伺服器
-9个步进电机
-6个继电器
-3个土壤湿度传感器
-2个光传感器
-水位传感器
-湿度和空气温度传感器
在远程部分的nRF24上:
-12个土壤湿度传感器
-12个继电器
-3个步进电机
-2个光传感器
-水位传感器
此外,nRF24本身可以实时在系统的两个分布式部分之间运行,并在服务器和服务器引擎的以太网接口之间运行,从而提供系统的Web用户界面。
总体上,在多任务处理模式下,实时至少有60个实体在8位Mega上运行(这还不包括AMS操作系统本身的许多服务,实体的数量将接近100)。 这显然与“在Arduino上无法实现真正的多任务处理,即使上面有五个LED指示灯闪烁也存在问题”的说法不符。
捍卫Arduino的几句话
(尽管很明显,Arduino是一种社会文化和技术现象,拥有数百万粉丝和数以千计的惊人项目,但并不需要保护。)
我已经说过很多遍了,并且会再次重申,事实上,Arduino在其软件组件中只是具有自身优缺点的可能抽象级别之一(就像其他任何抽象级别一样)。 而且,对于用户来说,在他的小片硅片中“旋转”什么是绝对没有区别的-纯粹的Arduino,RTOS,RIOT OS,AMS或控制器铁资源的表示和管理的其他一些数学抽象。
对于用户来说,解决他的问题很重要-对于控制器给植物浇水,开灯,控制窗帘等。主要问题不在于开发中使用的工具,而在于使用它们的能力以及开发人员本人的想象力和工程视野。
如何运作?
就其本身而言,微控制器上的多任务可以以不同的方式组织,在这种情况下,我们将讨论最简单的一种-进程轮流进行控制,并在使用其时间片后自愿放弃。 当然,这种方法并非没有明显的缺点,但是,正如他们所说,实践是一种真理的标准,并且已经在真实条件下证明了自己:在标准
Arduino Mega Server发行版和
AMS Pro的许多项目中都使用了这种方法。 这些系统可以24/7全天候工作,并且已经在许多个月的无故障运行中确认了正常运行时间。
这表明分布式nRF24系统的大约一百个实体是实时独立管理的。 请注意最后两个CPU指示器-即使在8位Mega上,处理器负载也为零(即系统完全空闲)。关于计时器的一些知识
为了组织复杂系统的控制,仅在过程之间依次转移控制是不够的,并且随着自动控制转移到AMS,使用了各种类型的计时器:循环,具有给定重复次数(批处理)的循环,单个,随机,混合等。所有这些都是有组织的Arduino的本机方式,不使用中断或直接对微控制器计时器进行编程(但是,中断是系统“出于其预期目的”使用的)。
这又直接与以下说法背道而驰:“将有足够的熨斗计时器来容纳3个LED,从那时起,建筑学家将遇到问题。” 不要开始。 我们可以使用任何数量的任何类型的计时器。 而且,如果需要的话,我们可以使自己变得更加新颖和随意。
主要情况
这种多任务组织的主要情况是创建所谓的“非阻塞”代码,即不使用delay()函数的代码,该函数只是将程序暂停给定时间。
实时性
可以将所描述的用于实现多任务的方法描述为“软实时”,系统中的典型延迟时间为10毫秒(但峰值延迟可能更长,并且没有标准化)。 这对该解决方案的应用范围施加了众所周知的限制,但是对于大多数“家庭”任务(不仅是),它非常适合,请参见上面的示例。
如果您需要更严格的实时控制,则需要对特定任务的代码进行特殊优化,重新架构,或者在极端情况下为特定功能分配单独的控制器。 例如,突出显示用于智能LED灯条的
单独的效果
控制器 。
这是对Arduino尤其是AMS中多任务工作的一般理论描述,现在我们转向考虑实际示例。
循环计时器

考虑最简单的循环计时器的实现。 这些是计时器(在AMS“周期”的术语中),它们以某些预定义的时间间隔激活,并用于激活循环过程。
通常,最好以编程方式将计时器设计为对象,但是在Arduino Mega Server的标准交付中,这些计时器被实现为功能,因此,对于初学者而言,我们将在这种假设中考虑它们。
使用循环计时器非常简单:只需将需要定期执行的代码放在if语句的括号之间。 如果需要使用其他触发间隔,则只需使用所需的变量而不是cycle1s。 您可以根据需要设置任意多个周期-即使在8位Mega上,系统也可以轻松地处理数百个此类计时器(当然,只有您需要记住被调用的代码没有阻塞)。
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,
. , , .