首页 > 微机单片机 >单片机制作 > 如何使用Arduino millis函数执行多任务处理

如何使用Arduino millis函数执行多任务处理

来源:互联网发布者:fish001 关键词: 函数 Arduino 多任务处理 更新时间: 2024/05/17

多任务处理将计算机带入了一场革命,其中一个或多个程序可以同时运行,从而提高了效率、灵活性、适应性和生产力。在嵌入式系统中,微控制器还可以处理多任务并同时执行两个或多个任务,而不会停止当前指令。

在本教程中,我们将学习Arduino 如何使用 Arduino millis 函数执行多任务处理。通常在 Arduino 中使用delay()函数来执行LED 闪烁等周期性任务,但此 delay() 函数会暂停程序一段确定的时间,并且不允许执行其他操作。所以这篇文章解释了我们如何避免使用 delay() 函数并将其替换为 millis()以同时执行多个任务并使 Arduino 成为一个多任务控制器。

什么是多任务处理?

多任务处理只是意味着同时执行多个任务或程序。几乎所有操作系统都具有多任务处理功能。这种操作系统被称为MOS(多任务操作系统)。MOS 可以是移动或桌面 PC 操作系统。计算机中多任务处理的一个很好的例子是,当用户同时运行电子邮件应用程序、互联网浏览器、媒体播放器、游戏时,如果用户不想使用该应用程序,如果不关闭,它就会在后台运行。最终用户同时使用所有这些应用程序,但操作系统采用这个概念有点不同。让我们讨论一下操作系统如何管理多任务。

pYYBAGMW60iAYtxhAABWB9UQiL8404.png

如图所示,CPU 将时间分成三个相等的部分,并将每个部分分配给每个任务/应用程序。这就是大多数系统中多任务处理的方式。Arduino Multitasking的概念几乎相同,只是时间分布会有所不同。由于 Arduino 与笔记本电脑/手机/PC 相比以低频运行且 RAM 运行,因此分配给每个任务的时间也会有所不同。Arduino 还有一个广泛使用的delay()函数。但在开始之前,让我们讨论一下为什么我们不应该在任何项目中使用delay()函数。

为什么要使用 millis() ?

为了克服使用延迟带来的问题,开发人员应该使用millis()函数,一旦你习惯了它就很容易使用,它会使用100%的CPU性能而不会在执行指令时产生任何延迟。millis()是一个函数,它只返回自 Arduino 板开始运行当前程序而不冻结程序以来经过的毫秒数。大约 50 天后,该时间数将溢出(即回到零)。

就像Arduino有delayMicroseconds()一样,它也有micro版本的millis()作为micros()。micros 和 millis 之间的区别在于,micros() 将在大约 70 分钟后溢出,而 millis() 则为 50 天。因此,根据应用程序,您可以使用millis() 或micros()。

使用毫秒()而不是延迟():

要使用millis()进行计时和延迟,您需要记录并存储动作发生的时间以开始时间,然后每隔一段时间检查定义的时间是否已经过去。如前所述,将当前时间存储在一个变量中。

无符号长 currentMillis = millis();

我们需要另外两个变量来确定是否已经过了所需的时间。我们已将当前时间存储在currentMillis变量中,但我们还需要知道计时周期何时开始以及该周期有多长。因此声明了 Interval 和previousMillis。间隔将告诉我们时间延迟,previosMillis 将存储事件最后发生的时间。

unsigned long previousMillis; 
无符号长周期 = 1000;

为了理解这一点,让我们以一个简单的闪烁 LED 为例。period = 1000 将告诉我们 LED 将闪烁 1 秒或 1000 毫秒。

常量 int led

在这里,语句《if (currentMillis - previousMillis 》= period)》检查 1000 毫秒是否已过。如果 1000 毫秒过去了,则 LED 闪烁并再次进入相同状态。这种情况还在继续。就是这样,我们已经学会了使用毫秒而不是延迟。这样它就不会在特定的时间间隔内停止程序。

Arduino 中的中断与其他微控制器中的工作方式相同。Arduino UNO 板有两个独立的引脚,用于在 GPIO 引脚 2 和 3 上附加中断。我们在Arduino 中断教程中详细介绍了它,您可以在其中了解有关中断及其使用方法的更多信息。

在这里,我们将通过同时处理两个任务来展示 Arduino 多任务处理。这些任务将包括两个 LED 以不同的时间延迟闪烁以及一个按钮,该按钮将用于控制 LED 的开/关状态。所以三个任务将同时执行。

poYBAGMW60KALgZpAATs0CDzeeE572.png

所需组件

Arduino UNO

三个 LED(任何颜色)

电阻(470、10k)

跳线

面包板

电路原理图

演示使用Arduino Millis() 函数的电路图 非常简单,无需附加太多组件,如下所示。

poYBAGMW6zuABeMrAACZlx-F4jI138.png

为多任务处理编程 Arduino UNO

为多任务编程 Arduino UNO 只需要上面解释的 millis() 工作原理背后的逻辑。建议在开始对 Arduino UNO 进行多任务编程之前,一次又一次地练习使用millis闪烁 LED ,以使逻辑清晰并让自己对 millis() 感到满意。在本教程中,中断还与 millis() 同时用于多任务处理。该按钮将是一个中断。因此,只要产生中断,即按下按钮,LED 就会切换到 ON 或 OFF 状态。

编程从声明连接 LED 和按钮的引脚号开始。

诠释 led1 = 6; 
诠释 led2 = 7; 
int toggleLed = 5; 
int 按钮 = 2;

接下来我们编写一个变量来存储 LED 的状态以备将来使用。

诠释 ledState1 = 低;
诠释 ledState2 = 低;

正如上面闪烁示例中所解释的,period 和 previousmillis 的变量被声明为比较并为 LED 生成延迟。第一个 LED 每 1 秒闪烁一次,另一个 LED 在 200ms 后闪烁。

unsigned long previousMillis1 = 0; 
常量长周期1 = 1000;
unsigned long previousMillis2 = 0; 
常量长周期2 = 200;

另一个毫秒函数将用于生成去抖动延迟,以避免多次按下按钮。将有与上述类似的方法。

int debouncePeriod = 20;  
int debounceMillis = 0;

这三个变量将用于存储按钮的状态为中断、切换 LED 和按钮状态。

bool buttonPushed = false; 
int ledChange = 低;  
诠释最后状态=高;

定义引脚的动作,哪个引脚将作为 INPUT 或 OUTPUT 工作。

  pinMode(led1,输出);             
  pinMode(led2,输出);
  pinMode(toggleLed,输出);
  pinMode(按钮,输入);

现在通过附加中断与 ISR 和中断模式的定义来定义中断引脚。请注意,建议在声明attachInterrupt()函数时使用digitalPinToInterrupt(pin_number)将实际的数字引脚转换为特定的中断号。

attachInterrupt(digitalPinToInterrupt(pushButton), pushButton_ISR, CHANGE);

中断子程序被编写,它只会改变buttonPushed标志。需要注意的是,中断子程序要尽可能的短,所以尽量写,尽量减少多余的指令。

无效 pushButton_ISR() 
{ 
  buttonPushed = true; 
}

循环首先将毫秒值存储在 currentMillis 变量中,该变量将存储每次循环迭代时经过的时间值。

无符号长 currentMillis = millis();

多任务处理共有三个功能,1 秒闪烁一个 LED,200 毫秒闪烁第二个 LED,如果按下按钮,则关闭/打开 LED。所以我们将写三个部分来完成这个任务。

第一个是通过比较经过的毫秒数每 1 秒切换一次 LED 状态。

if (currentMillis - previousMillis1 >= period1) { 
    previousMillis1 = currentMillis;  
    如果(ledState1 == 低){ 
      ledState1 = 高;
    } 其他 { 
      ledState1 = 低;
    } 
    digitalWrite(led1, ledState1);   
  }

类似地,第二次它通过比较经过的毫秒数每 200 毫秒后切换一次 LED。解释已经在本文前面进行了解释。

  if (currentMillis - previousMillis2 >= period2) { 
    previousMillis2 = currentMillis;  
    如果(ledState2 == 低){ 
      ledState2 = 高;
    } 其他 { 
      ledState2 = 低;
    } 
    digitalWrite(led2, ledState2); 
  }

最后,buttonPushed标志被监控,在产生 20ms 的去抖动延迟后,它只是切换 LED 的状态,对应于作为中断附加的按钮。

  if (buttonPushed = true) // 检查是否调用了 ISR 
  { 
    if ((currentMillis - debounceMillis) > debouncePeriod && buttonPushed) // 产生 20ms 的去抖延迟以避免多次按下
    { 
      debounceMillis = currentMillis; // 保存最后的去抖动延迟时间
      if (digitalRe

这样就完成了Arduino millis() 教程。请注意,为了习惯使用millis(),只需练习在其他一些应用程序中实现此逻辑即可。

/* 使用 Arduino millis() 函数进行多任务处理

作者:CircuitDigest (circuitdigest.com)

*/


诠释 led1 = 6; // led1 连接在引脚 6

int led2 = 7; // led1 连接在引脚 7

int toggleLed = 5; // 按钮控制的 LED 连接在引脚 5

int pushButton = 2; // 将按钮连接到引脚 2,这也是中断引脚


诠释 ledState1 = 低;// 判断 led1 和 led2 的状态

int ledState2 = LOW;


unsigned long previousMillis1 = 0; //存储上次 LED1 闪烁的时间

const long period1 = 1000; // led1 闪烁的时间,单位为 ms


unsigned long previousMillis2 = 0; //存储上次 LED2 闪烁的时间

const long period2 = 200; // led1 闪烁的时间,单位为 ms


int debouncePeriod = 20; // 20ms 的去抖动延迟

int debounceMillis = 0; // 类似于previousMillis


bool buttonPushed = false; // 中断例程按钮状态

int ledChange = LOW; // 跟踪 LED 状态 last

int lastState = HIGH; // 跟踪最后一个按钮状态



无效设置(){

pinMode(led1,输出);// 将引脚定义为输入或输出

pinMode(led2, OUTPUT);

pinMode(toggleLed,输出);

pinMode(按钮,输入);

attachInterrupt(digitalPinToInterrupt(pushButton), pushButton_ISR, CHANGE); // 使用中断 pin2

}


无效 pushButton_ISR()

{

buttonPushed = true; // ISR 应该尽可能短

}


void loop() {

unsigned long currentMillis = millis(); // 存储当前时间


if (currentMillis - previousMillis1 >= period1) { // 检查是否经过了 1000ms

previousMillis1 = currentMillis; // 保存上次闪烁 LED 的时间

if (ledState1 == LOW) { // 如果 LED 关闭,则将其打开,反之亦然

ledState1 = HIGH; //更改下一次迭代的 LED 状态

} else {

ledState1 = LOW;

}

digitalWrite(led1, ledState1); //用ledState设置LED再次闪烁

}


if (currentMillis - previousMillis2 >= period2) { // 检查是否经过了 1000ms

previousMillis2 = currentMillis; // 保存上次闪烁 LED 的时间

if (ledState2 == LOW) { // 如果 LED 关闭,则将其打开,反之亦然

ledState2 = HIGH;

} 其他 {

ledState2 = 低;

}

digitalWrite(led2, ledState2);//设置带ledState的LED再次闪烁

}


if (buttonPushed = true) // 检查是否调用了 ISR

{

if ((currentMillis - debounceMillis) > debouncePeriod && buttonPushed) // 产生 20ms 的去抖延迟以避免多次按下

{

debounceMillis = currentMillis; // 保存最后的去抖动延迟时间

if (digitalRead(pushButton) == LOW && lastState == HIGH) // 按下按钮后改变LED

{

ledChange = ! 领导改变;

digitalWrite(toggleLed, ledChange);

最后状态 = 低;

}

else if (digitalRead(pushButton) == HIGH && lastState == LOW)

{

lastState = HIGH;

}

buttonPushed = 假;

}

}

}

提问/讨论

这里还没有内容,您有什么问题吗?

我要提问/讨论

推荐帖子 最新更新时间:2024-11-21 18:50

想问一下关于嵌入式专业考研的问题
本人想考研,请问国内那些学校的嵌入式专业不错啊?不胜感激 想问一下关于嵌入式专业考研的问题 推荐你性价比比较高的吧 西安电子科技大学 成都电子科技大学 接分先!
 xuliqun嵌入式系统
CCS的实例工程代码
文件太大,上传失败,有需要的朋友留下地址 总算上传成功,多谢论坛的帮助 CCS的实例工程代码 我想要,邮箱sally-shenyl@163.com 谢谢 Re: CCS的实例工程代码 我想要,你把内容发送到我的邮箱里好吗? gufeiyuhouchun@126.com 回复:C
 1234嵌入式系统
TI - 提升智能音箱的设计思路
智能音箱行业的竞争愈发激烈,各大制造商都在争相开发功能更强大、使用更方便的产品。当今的智能音箱拥有语音交互、人工智能、智能家居控制及多媒体播放等丰富的功能。要在竞争中占据先机,智能音箱的设计必须在总体系统成本、电池续航能力、热效应、回声消除和音质方面具备优势。   总体系
 火辣西米秀模拟与混合信号
手动型和全自动型烧录器
本帖最后由 jameswangsynnex 于 2015-3-3 20:02 编辑 烧录一般是指使用刻录机把数据刻录(也称烧录)到刻录盘。现在有CD、DVD两种刻录盘,后者容量要比前者大的多,烧录就象COPY一样。把你电脑里的东西COPY在别的文件载体上,就象1.4寸的磁盘就
 ctguhl移动便携
内视镜相关的日本企业
2015 SONY 发布了 4K 内视镜 2017 日立预定 发布8K 另外 olympus,做胃镜的朋友都知道的 内视镜有待解决的问题蛮多的, 镜头只能越来越小,不能变大 拍的camera模块,要小---估计这两年不会一下子到5nm工艺 图像太暗,---需要新的技术出现
 5525医疗电子
二极管发烫,该怎么解决
简单的mic口充电输入电源,并联接两个二极管,严重发烫,该怎么解决,有谁用过并联两个二极管的输入电路么 二极管发烫,该怎么解决 自顶 “二极管,严重发烫,该怎么解决” 先确定你的电路设计是否正确。 楼主,我觉得你基础欠缺,电路分析基础和模拟电子的书应该先翻个两三遍。 是不是二
 一株草电源技术

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版 版权声明

EEWORLD 电路图 站点相关: 下载中心 Datasheet 参考设计

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved