Arduino 使用 millis() 函数实现多任务处理

多任务处理可以使一个或多个程序可以同时运行。在嵌入式系统中,微控制器还可以处理多任务处理并同时执行两个或多个任务,而无需停止当前指令。

通常在 Arduino 中使用 delay() 函数来执行 LED 闪烁等周期性任务,但是 delay() 函数会暂停程序一段时间,并且不允许执行其他操作。因此,在 Arduino 中将 delay 替换为 millis() 函数可以同时执行多个任务,并使 Arduino 成为多任务控制器

为什么不用 Arduino 中的 delay()

在 Arduino 的参考文档中有两种类型的延迟函数,第一种是 delay() ,第二种是 delayMicroseconds()。两个函数在产生延迟时间方面是相同的。唯一的区别在于,在 delay() 函数中,传递的参数整数是以毫秒为单位,即如果我们写入 delay(1000) 则延迟将是1000毫秒,即1秒。类似地,在 delayMicroseconds() 函数中,传递的参数是微秒,即如果我们写 delayMicroseconds(1000),则延迟将是1000微秒,即1毫秒。

重点是,两个函数都会暂停程序延迟函数传递的时间。因此,如果我们给出1秒的延迟,则处理器在1秒钟之前不能进入下一条指令。类似地,如果延迟是10秒,则程序将停止10秒,并且处理器将不允许进行下一指令,直到10秒过去。这妨碍了微控制器在速度和执行指令方面的性能。

解释延迟函数缺点的最好例子是使用两个按钮:比如使用两个按钮切换两个LED。如果按下一个按钮,则相应的LED发光2秒;如果按下第二个,则LED应该发光4秒。但是当我们使用 delay() 时,如果用户按下第一个按钮,程序将停止2秒,如果用户在2秒延迟之前按下第二个按钮,则微控制器将不接受输入,因为程序是在停止阶段。

Arduino的官方文档在其delay()函数描述的注释和警告中明确提到了这一点。

为什么要使用 millis()

为了克服使用 delay() 函数引起的问题,我们可以使用 millis() 函数,这个函数在习惯使用后很容易使用,它将使用100%的 CPU 性能而不会在执行指令时产生任何延迟。 millis() 函数只返回自 Arduino 开发板开始运行当前程序以来没有冻结程序所经过的毫秒数。大约50天后,这个时间数将溢出(即回到零)。

就像 Arduino 有 delayMicroseconds() 一样,它也有微型版本的 millis(),那就是 micros()。 micros 和 millis 之间的差异是,micros() 在大约70分钟后会溢出,而millis()则是50天。

使用 millis() 而不是 delay()

要使用 millis() 进行计时和延迟,就是要记录并存储操作开始时间的时间,然后定期检查定义的时间是否已过。 如上所述,将当前时间存储在变量中。

unsigned long currentMillis = millis();

我们还需要两个变量来确定是否已经过了所需的时间。 我们已将当前时间存储在 currentMillis 变量中,但我们还需要知道定时周期何时开始以及周期有多长。 因此声明了 Interval (下方为 Period ,即延迟周期。类似于 delay 函数括号中的时间)和 previousMillis。 Interval 将告诉我们时间延迟周期,单位为毫秒;previosMillis 将存储事件发生的最后时间:

unsigned long previousMillis;
unsigned long period = 1000;

但是如果同时有多个需要延迟的进程,那么需要定义多个 previousMillis,以便进行区分:

unsigned long previousMillisHeater = 0;  //用来存时间
unsigned long previousMillisVentilateur = 0;  //用来存时间
unsigned long previousMillisMoteur = 0;  //用来存时间
const long period = 30000;         // 周期,不中断正在进行的进程,单位为ms

举一个简单的闪烁LED示例。 period = 1000 将告诉我们 LED 将闪烁1秒:

const int ledPin =  4; // the LED pin number connected
int ledState = LOW;             // used to set the LED state
unsigned long previousMillis = 0;  //will store last time LED was blinked
const long period = 1000;         // period at which to blink in ms

void setup() {
  pinMode(ledPin, OUTPUT); // set ledpin as output
}

void loop() {
  unsigned long currentMillis = millis(); // store the current time
  if (currentMillis - previousMillis >= period) { // check if 1000ms passed
    previousMillis = currentMillis;   // save the last time you blinked the LED
    if (ledState == LOW) { // if the LED is off turn it on and vice-versa
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);//set LED with ledState to blink again
  }
}

这里,语句 if (currentMillis - previousMillis >= period) 检查是否已经过去了 1000ms 。如果超过1000ms,则LED闪烁并再次进入相同状态;此效果和 delay 函数相同,但是同时它不会暂停整个 Arduino 代码的运行。

Arduino 的中断与其他微控制器的工作方式相同。 Arduino UNO 板有两个独立的引脚,用于连接 GPIO 引脚 2和 3 上的中断,这可能会在之后的文章中提到。

参考资料

评论

  1. 李苏旺
    iPhone Safari 13.0.5
    2 年前
    2022-9-12 10:22:24

    使用的delay 函数 在阻塞的时候 如果发生中断事件 arduino会怎么处理呢?

    • 博主
      李苏旺
      Windows Chrome 104.0.0.0
      2 年前
      2022-9-22 13:07:52

      您好 不好意思好久没看后台🤣我试了一下当使用delay的时候,使用attachInterrupt(interrupt, ISR, mode)函数没有效果,也就是说使用delay的时候arduino就不做别的事情了(也可能执行了中断,但是中断执行完毕继续执行delay),要么就是复位停止delay。另一种办法是
      用while循环,将delay的值设小一点,当满足结束条件时跳出while,不满足条件就继续。

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇