0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何在Arduino中编码计时器和延迟

454398 来源:网络整理 作者:网络整理 2019-11-18 17:15 次阅读

步骤1:

这是否以便在草图中编写延迟。

int led = 13;

unsigned long delayStart = 0; // the time the delay started

bool delayRunning = false; // true if still waiting for delay to finish

void setup() {

pinMode(led, OUTPUT); // initialize the digital pin as an output.

digitalWrite(led, HIGH); // turn led on

delayStart = millis(); // start delay

delayRunning = true; // not finished yet

}

void loop() {

// check if delay has timed out after 10sec == 10000mS

if (delayRunning && ((millis() - delayStart) 》= 10000)) {

delayRunning = false; // // prevent this code being run more then once

digitalWrite(led, LOW); // turn led off

Serial.println(“Turned LED Off”);

}

// Other loop code here 。 . 。

Serial.println(“Run Other Code”);

}

Arduino启动后调用的 setup()方法中,LED会被打开上。一旦完成 setup(),Arduino就会一次又一次调用 loop()方法。这就是您大多数代码的去向,读取传感器发送的输出等。在上面的草图中,第一次调用loop()时, delay(10000)会在关闭LED之前停止所有动作10秒钟。并继续。如果运行此代码,则会在启动后的10秒钟内未打印出 Run Other Code (运行其他代码),但是在led关闭(ledOn等于false)后,它会很快地循环打印出来

这里要注意的一点是,您真的不应该在loop()代码中完全使用delay()函数。 有时在 setup()代码中使用 delay()有时很方便,并且您通常可以使用很小的延迟(只有很少的延迟)来摆脱很小的麻烦 loop()代码中的毫秒数,但您实际上应该避免在 loop()方法

中完全使用:如何在Arduino中编写非阻塞延迟

上一幅草图使用了阻塞延迟,即在延迟等待到期时,它完全停止了代码执行任何其他操作。下一个草图向您展示了如何编写非阻塞延迟,该延迟使代码在等待延迟到期之前继续运行。

int led = 13;

unsigned long delayStart = 0; // the time the delay started

bool delayRunning = false; // true if still waiting for delay to finish

void setup() {

pinMode(led, OUTPUT); // initialize the digital pin as an output.

digitalWrite(led, HIGH); // turn led on

delayStart = millis(); // start delay

delayRunning = true; // not finished yet

}

void loop() {

// check if delay has timed out after 10sec == 10000mS

if (delayRunning && ((millis() - delayStart) 》= 10000)) {

delayRunning = false; // // prevent this code being run more then once

digitalWrite(led, LOW); // turn led off

Serial.println(“Turned LED Off”);

}

// Other loop code here 。 . 。

Serial.println(“Run Other Code”);

}

在上面的草图中, setup()方法,将 delayStart 变量设置为 millis()的当前值。

millis()是一种内置方法,该方法返回自电路板加电以来的毫秒数。每次复位板卡时,它都从0开始,并由CPU硬件计数器每毫秒增加一次。稍后有关 millis()的更多信息。一旦完成 setup(),Arduino就会一遍又一遍地调用loop()方法。

每次 loop()都称为代码检查。

a)延迟仍在运行,以及 b)如果 millis()与 delayStart 中存储的值相差10000 mS(10秒) 》。

当时间经过10000mS或更多时,会将 delayRunning 设置为false,以防止再次执行if语句中的代码并关闭led。

如果运行此草图,您将很快看到运行其他代码的打印,并且10秒钟后,LED将关闭,如果很快,您可能会看到Turned LED Off

请参见下面的第4步,了解millisDelay库如何简化此代码

第3步:无符号长整数,溢出和无符号减法

如果您熟悉无符号的long,溢出,无符号的算术以及使用无符号的long变量的重要性,那么您可以直接跳至使用millisDelay库的第4步。

上一个草图的重要部分是测试

(millis() - delayStart) 》= 10000

此测试必须以非常特定的方式进行编码才能正常工作。

无符号长溢出

delayStart 变量a从 millis()内置函数返回的数字是 unsigned long 。这是一个从0到4,294,967,295的数字。

如果将1加到保持最大值4,294,967,295的 unsigned long ,答案将为0(零)。那就是溢出的数字,然后回绕到0。您可以想象溢出位会被丢弃。例如3位无符号111是最大值(7)加1得出1000(8),但是前导1溢出3位存储空间并被丢弃,因此回绕到000。

最终,当cpu再加上一个变量时,它的变量包含 millis()结果将环绕到0。即 millis()将再次从0开始计数。如果您让Arduino开发板运行4,294,967,295mS(即大约49天17小时,即50天),就会发生这种情况。

现在让我们考虑另一种编码测试的方式(millis()-delayStart)》 = 10000

算术上,此测试等于 millis()》 =(delayStart + 10000)

但是,如果您在将近50点后开始延迟天,例如 millis()返回4,294,966,300 mS,则 delayStart + 10000 将溢出到995,而测试millis()》 =(delayStart + 10000)将立即真实,不会有任何延迟。因此,这种形式的测试并不总是有效。

不幸的是,您不太可能在测试过程中遇到这种情况,但是由于它可能会意外地出现在长时间运行的设备中,例如车库门控制器运行连续数月。如果尝试使用

delayEnd = millis()+ 10000

,然后使用测试(millis()》 = delayEnd),您也会遇到类似的问题。

最后, delayStart 变量必须为 unsigned long 。如果改用 long (即 long int )或 int 或 unsigned int ,则它们可以hold小于从 millis()返回的 unsigned long 。最终,从 millis()重新调整的值将使存储在其中的较小变量溢出,并且您会发现时间突然倒退了。例如,如果对 startDelay 使用 unsigned int ,则将在Uno板上65秒后发生。

Unsigned Subtraction

另一个兴趣点是 millis()-delayStart 的结果,当 delayStart 表示为4,294,966,300,而我们希望有10000mS的延迟时,会发生什么。

millis()会在发生这种情况之前回绕为0。请记住,将无符号长整数可以存储的最大值加1会回绕到0。因此,一种计算millis()的方法-delayStart,其中《strong》 millis()已经环绕并且小于 delayStart ,是说“ W 我必须将多少数字加到delayStart等于millis()(溢出后)?”,即方程式delayStart + X == millis()

例如,再次使用一个3位无符号变量,要计算2-4(无符号),请考虑一个从0开始的时钟面,并将其一直加到111( 7),然后回到0。现在要从4变到2,您需要加上6(5,6,7,0,1,2),所以2-4 = 6,这实际上是计算的工作方式,尽管

因此,两个无符号长整数之差将始终为正数,范围为0到4,294,967,295。例如,如果 startDelay 为1,并且 millis()换为0(50天后),则 millis()-startDelay 将等于4,294,967,295 。这意味着您可以在0到4,294,967,295毫秒之间的任意位置指定 DELAY_TIME ,并且(millis()-delayStart)》 = DELAY_TIME 将始终按预期工作,无论何时

步骤4:使用MillisDelay库

要安装millisDelay库。下载了millisDelay.zip文件。

将此文件解压缩到Arduino/libraries目录(打开IDE File-》 preferences窗口以查看本地Arduino目录的位置)。有时,有关如何安装库的说明-自动安装工作,但并非总是如此。手动解压缩文件是最安全的。安装millisDelay库后,将有三个可用的交互式示例,您可以将它们加载到Arduino板上,然后在9600baud处打开Serial Monitor(在5秒内)以使用它们。这是使用millisDelay库重写的先前的非阻塞延迟草图。

#include “millisDelay.h”

int led = 13;

millisDelay ledDelay;

void setup() {

pinMode(led, OUTPUT); // initialize the digital pin as an output.

digitalWrite(led, HIGH); // turn led on

ledDelay.start(10000); // start a 10sec delay

}

void loop() {

// check if delay has timed out

if (ledDelay.justFinished()) {

digitalWrite(led, LOW); // turn led off

Serial.println(“Turned LED Off”);

}

// Other loop code here 。 . 。

Serial.println(“Run Other Code”);

}

如果查看millisDelay库代码,您将看到先前草图的代码已被移至库中的 start()和 just Finished()方法。

这是ledDelay还是ledTimer?您可以使用自己喜欢的任何一个术语。我倾向于将。.. delay用于执行一次的单次延迟,并使用…timer重复一次。

步骤5:延迟和计时器示例

《这是两个基本的延迟和计时器草图以及它们的millisDelay库等效项。这些示例用于一次关闭(单发)延迟和重复延迟/定时器

单发延迟

单发延迟是仅运行一次然后出现一次的延迟。停止。它是Arduino delay()方法的最直接替代。您开始延迟,然后在延迟完成后执行一些操作。 BasicSingleShotDelay是普通代码,而SingleShotMillisDelay使用millisDelay库。

BasicSingleShotDelay

此草图可在BasicSingleShotDelay.ino

int led = 13; // Pin 13 has an LED connected on most Arduino boards.

unsigned long DELAY_TIME = 10000; // 10 sec

unsigned long delayStart = 0; // the time the delay started

bool delayRunning = false; // true if still waiting for delay to finish

void setup() {

pinMode(led, OUTPUT); // initialize the digital pin as an output.

digitalWrite(led, HIGH); // turn led on

// start delay

delayStart = millis();

delayRunning = true;

}

void loop() {

// check if delay has timed out

if (delayRunning && ((millis() - delayStart) 》= DELAY_TIME)) {

delayRunning = false; // finished delay -- single shot, once only

digitalWrite(led, LOW); // turn led off

}

}

中找到。 loop()上方的行继续运行,而不会停留在等待延迟到期之前。

在 loop()的每次通过期间,当前《将strong》 millis()和 delayStart 时间与 DELAY_TIME 进行比较。当计时器超过间隔值时,将采取所需的措施。在此示例中,延迟计时器停止并且LED熄灭。

SingleShotMillisDelay

这里是使用millisDelay库重写的BasicSingleShotDelay草图。此草图可在SingleShotMillisDelay.ino中找到。

这里是millisDelay版本,其中上面的代码已包装在millisDelay类的类方法中。

#include

int led = 13;

// Pin 13 has an LED connected on most Arduino boards.

millisDelay ledDelay;

void setup() {

// initialize the digital pin as an output.

pinMode(led, OUTPUT);

digitalWrite(led, HIGH); // turn led on

// start delay

ledDelay.start(10000);

}

void loop() {

// check if delay has timed out

if (ledDelay.justFinished()) {

digitalWrite(led, LOW); // turn led off

}

}

重复计时器

这些是重复延迟/计时器的简单示例。

BasicRepeatingDelay

BasicRepeatingDelay是简单的代码,RepeatingMillisDelay使用millisDelay库。

BasicRepeatingDelay.h

int led = 13; // Pin 13 has an LED connected on most Arduino boards.

unsigned long DELAY_TIME = 1500; // 1.5 sec

unsigned long delayStart = 0; // the time the delay started

bool delayRunning = false; // true if still waiting for delay to finish

bool ledOn = false; // keep track of the led state

void setup() {

pinMode(led, OUTPUT); // initialize the digital pin as an output.

digitalWrite(led, LOW); // turn led off

ledOn = false;

// start delay

delayStart = millis();

delayRunning = true;

}

void loop() {

// check if delay has timed out

if (delayRunning && ((millis() - delayStart) 》= DELAY_TIME)) {

delayStart += DELAY_TIME; // this prevents drift in the delays

// toggle the led

ledOn = !ledOn;

if (ledOn) {

digitalWrite(led, HIGH); // turn led on

} else {

digitalWrite(led, LOW); // turn led off

}

}

}

使用

delayStart + = DELAY_TIME;

重设延迟以再次运行,是否允许 millis()-delayStart 可能是》 DELAY_TIME ,因为 millis()刚刚增加,或者是由于 loop()中的某些其他代码降低了它的速度。例如长打印语句。 (请参阅第7步中的添加循环Montor)

另一点是在 startup()的末尾开始延迟。即使 startup()需要花费一些时间来执行,这也可以确保计时器在 loop()开始时是准确的。

RepeatingMillisDelay

这是使用millisDelay库重写的BasicRepeatingDelay草图。该草图可在RepeatingMillisDelay.ino

#include

int led = 13;

// Pin 13 has an LED connected on most Arduino boards.

bool ledOn = false; // keep track of the led state

millisDelay ledDelay;

void setup() {

// initialize the digital pin as an output.

pinMode(led, OUTPUT); // initialize the digital pin as an output.

digitalWrite(led, LOW); // turn led off

ledOn = false;

// start delay

ledDelay.start(1500);

}

void loop() {

// check if delay has timed out

if (ledDelay.justFinished()) {

ledDelay.repeat(); // start delay again without drift

// toggle the led

ledOn = !ledOn;

if (ledOn) {

digitalWrite(led, HIGH); // turn led on

} else {

digitalWrite(led, LOW); // turn led off

}

}

}

步骤6:其他MillisDelay库函数

中使用,除了 start(延迟),公正 Finished()和 repeat()功能,millisDelay库也具有

stop()以停止延迟超时,

isRunning()以检查其是否尚未超时且尚未停止,

restart()从现在开始重新延迟,使用相同的延迟间隔

finish()强制延迟过期

remaining()可以返回直到延迟结束为止的毫秒数,并且

delay()可以返回传递给 start()

库的微秒版本

millisDelay的延迟值以毫秒为单位进行计数。您还可以按微秒计时。留给读者练习写该类的练习。 (提示:将类重命名为microDelay,并用micros()代替出现的millis())

冻结/暂停延迟

您可以冻结或通过保存剩余的()毫秒并停止延迟来暂停延迟,然后稍后以剩余的mS作为延迟重新启动它以解除冻结。例如参见FreezeDelay.ino示例

mainRemainingTime = mainDelay.remaining(); // remember how long left to run in the main delay

mainDelay.stop(); // stop mainDelay NOTE: mainDelay.justFinished() is NEVER true after stop()

mainDelay.start(mainRemainingTime); // restart after freeze

步骤7:警告之言–添加循环监视器

不幸的是,许多标准Arduino库使用 delay()或引入暂停,例如AnalogRead和SoftwareSerial。通常,这些引入的延迟很小,但是它们会加起来,所以我建议您在 loop()的顶部添加一个监视器,以检查其运行速度。

循环监视器与眨眼示例非常相似。 loop()方法顶部的一小段代码仅在每次执行 loop()时切换Led。然后,您可以使用具有Hz刻度的数字万用表来测量LED引脚(在这种情况下为引脚13)上的输出频率

代码为:-

// Loop Monitor – this checks that the loop() is executed at least once every 1mS

// (c)2013 Forward Computing and Control Pty. Ltd.

// www.forward.com.au》

//

// This example code is in the public domain.

int led = 13; // don‘t use on FioV3 when battery connected

// Pin 13 has an LED connected on most Arduino boards.

// if using Arduino IDE 1.5 or above you can use pre-defined

// LED_BUILTIN instead of ’led‘

// the setup routine runs once when you press reset:

void setup() {

// initialize the digital pin as an output.

pinMode(led, OUTPUT);

// add your other setup code here

}

// the loop routine runs over and over again forever:

void loop() {

// toggle the led output each loop The led frequency must measure 》500Hz (i.e. 《1mS off and 《1mS on)

if (digitalRead(led)) {

digitalWrite(led, LOW); // turn the LED off by making the voltage LOW

} else {

digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)

}

// add the rest of your loop code here

}

您可以在此处下载监视器代码。当我在Uno板上运行此代码时,连接在引脚13和GND之间的Hz范围内的万用表读数为57.6Khz。即》 500hz的大约100倍。

将代码添加到 loop()时,Hz读数将减小。只要检查它在所有情况下都保持在500Hz以上(每个loop()执行1mS)以上即可。
责任编辑:wv

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编码
    +关注

    关注

    6

    文章

    935

    浏览量

    54765
  • 计时器
    +关注

    关注

    1

    文章

    419

    浏览量

    32638
  • Arduino
    +关注

    关注

    187

    文章

    6464

    浏览量

    186669
收藏 人收藏

    评论

    相关推荐

    单个 MSP430™ 计时器模块的多时基应用说明

    电子发烧友网站提供《单个 MSP430™ 计时器模块的多时基应用说明.pdf》资料免费下载
    发表于 09-13 11:09 0次下载
    单个 MSP430™ <b class='flag-5'>计时器</b>模块的多时基应用说明

    TLC555-Q1 LinCMOS™计时器数据表

    电子发烧友网站提供《TLC555-Q1 LinCMOS™计时器数据表.pdf》资料免费下载
    发表于 08-23 11:19 0次下载
    TLC555-Q1 LinCMOS™<b class='flag-5'>计时器</b>数据表

    TLC555 LinCMOS™技术计时器数据表

    电子发烧友网站提供《TLC555 LinCMOS™技术计时器数据表.pdf》资料免费下载
    发表于 08-20 11:15 0次下载
    TLC555 LinCMOS™技术<b class='flag-5'>计时器</b>数据表

    LMC555 CMOS计时器数据表

    电子发烧友网站提供《LMC555 CMOS计时器数据表.pdf》资料免费下载
    发表于 08-20 09:16 0次下载
    LMC555 CMOS<b class='flag-5'>计时器</b>数据表

    使用Arduino 1.6.8在AT STA模式下运行Wi-Fi,“WiFi强制休眠开始”功能后未调用延迟功能是怎么回事?

    (\"WiFi Off, going for forde sleep\"); wifi.forcesleepbegin(); 延迟(10000); 预期是在 WiFi 强制休眠开始后,AP 应等待 WiFi 启动,直到延迟计时器
    发表于 07-22 06:48

    spi_flash期间的计时器中断导致崩溃怎么解决?

    这是我遇到的 SDK 的一个小错误 (esp_iot_sdk_v0.9.5_b1): 我在 Timer1 上使用计时器中断: ets_frc_timer1_intr_attach
    发表于 07-12 11:54

    何在RTOS SDK中将FRC1计时器附加到NMI的信息?

    我一直在寻找有关如何在 RTOS SDK 中将 FRC1 计时器附加到 NMI 的信息。我已经找到了 NON-OS SDK 所需的内容,但我找不到 RTOS SDK 的 NON-OS ETS_FRC_TIMER1_NMI_INTR_ATTACH(pwm_intr_hand
    发表于 07-10 08:32

    双路精密计时器选购指南:准确选择,高效工作

    在快节奏的现代生活,准确的时间管理对于个人和团队的成功至关重要。双路精密计时器作为一种高效的计时工具,受到了越来越多人的青睐。那么,如何选购一款适合自己的双路精密计时器呢?本文将为您
    的头像 发表于 06-26 16:06 328次阅读

    具有可编程复位延迟功能的TPS3430-Q1汽车类窗口看门狗计时器数据表

    电子发烧友网站提供《具有可编程复位延迟功能的TPS3430-Q1汽车类窗口看门狗计时器数据表.pdf》资料免费下载
    发表于 03-28 17:15 0次下载
    具有可编程复位<b class='flag-5'>延迟</b>功能的TPS3430-Q1汽车类窗口看门狗<b class='flag-5'>计时器</b>数据表

    具有内部延迟计时器的2节至5节串联锂离子电池BQ7718过压保护数据表

    电子发烧友网站提供《具有内部延迟计时器的2节至5节串联锂离子电池BQ7718过压保护数据表.pdf》资料免费下载
    发表于 03-28 14:08 0次下载
    具有内部<b class='flag-5'>延迟</b><b class='flag-5'>计时器</b>的2节至5节串联锂离子电池BQ7718过压保护<b class='flag-5'>器</b>数据表

    具有内部延迟计时器、适用于3节至5节串联锂离子电池的过压保护BQ77205数据表

    电子发烧友网站提供《具有内部延迟计时器、适用于3节至5节串联锂离子电池的过压保护BQ77205数据表.pdf》资料免费下载
    发表于 03-25 14:10 0次下载
    具有内部<b class='flag-5'>延迟</b><b class='flag-5'>计时器</b>、适用于3节至5节串联锂离子电池的过压保护<b class='flag-5'>器</b>BQ77205数据表

    具有内部延迟计时器、适用于3节至16节串联锂离子电池的电压和温度保护BQ77216数据表

    电子发烧友网站提供《具有内部延迟计时器、适用于3节至16节串联锂离子电池的电压和温度保护BQ77216数据表.pdf》资料免费下载
    发表于 03-25 10:05 0次下载
    具有内部<b class='flag-5'>延迟</b><b class='flag-5'>计时器</b>、适用于3节至16节串联锂离子电池的电压和温度保护<b class='flag-5'>器</b>BQ77216数据表

    具有可调节延迟和看门狗计时器的TPS386000和TPS386040四路电源电压监视数据表

    电子发烧友网站提供《具有可调节延迟和看门狗计时器的TPS386000和TPS386040四路电源电压监视数据表.pdf》资料免费下载
    发表于 03-14 10:54 0次下载
    具有可调节<b class='flag-5'>延迟</b>和看门狗<b class='flag-5'>计时器</b>的TPS386000和TPS386040四路电源电压监视<b class='flag-5'>器</b>数据表

    具有可编程复位延迟功能的 TPS3430 窗口看门狗计时器数据表

    电子发烧友网站提供《具有可编程复位延迟功能的 TPS3430 窗口看门狗计时器数据表.pdf》资料免费下载
    发表于 03-13 14:42 2次下载
    具有可编程复位<b class='flag-5'>延迟</b>功能的 TPS3430 窗口看门狗<b class='flag-5'>计时器</b>数据表

    ModusToolbox™生成时如何调用systick计时器ISR?

    我无法理解当项目由 ModusToolbox™生成时如何调用 systick 计时器 ISR。 通常,当您设置系统计时器并启用其中断时,系统会直接从中断向量调用 Systick_Handler。 我
    发表于 01-18 09:16