如果 NodeMCU 定时器内的代码在我设置的定时器间隔内执行会发生啥?

Posted

技术标签:

【中文标题】如果 NodeMCU 定时器内的代码在我设置的定时器间隔内执行会发生啥?【英文标题】:What will happen if codes inside a NodeMCU timer execute over the timer interval I set?如果 NodeMCU 定时器内的代码在我设置的定时器间隔内执行会发生什么? 【发布时间】:2017-10-31 22:10:23 【问题描述】:

使用NodeMCU,我们可以很容易地在esp8266芯片中创建定时器功能。 但是,我想知道如果计时器内的代码在我设置的计时器间隔内执行会发生什么?

请看下面的代码。 如果我设置了一个间隔为 2 秒的计时器,并且此计时器中的“要做的事情”执行超过 2 秒,那么会发生什么?

tmr.alarm(0, 2000, 1, function ()
    --Something to do
end)

a) “Something to do”是否会在间隔达到 2 秒后终止?

b) 或者“Something to do”会一直执行到完成,下一个“Something to do”会延迟?

c) 或者这个计时器的每一轮都将等待“某事做”完成,而不管 2 秒的间隔是多少? (区间自动扩大)

d) 还是?

【问题讨论】:

【参考方案1】:

该函数的行为不像您想象的那样。通常当你需要提供回调函数时,回调在事件发生时执行;这就是这里发生的事情。回调函数在计时器到期后执行。

tmr.alarm() 的文档说该函数是tmr.register()tmr.start() 的组合。 tmr.register() 文档说

配置一个计时器并注册回调函数以在到期时调用。

所以,你的回答是“Something to do”将运行,直到它完成,2 秒后tmr.alarm() 函数被调用。

tmr.alarm()(以及它所基于的tmr.register())可以采用mode 参数。我将描述它们的行为以及它们如何受到回调函数执行时间的影响。

tmr.ALARM_SINGLE:在对tmr.alarm() 的调用完成后,只运行一次回调函数 n 秒。完全独立于回调函数的执行时间。 tmr.ALARM_AUTO:在对tmr.alarm() 的调用完成后,每隔 n 秒重复运行一次回调函数。重要的是要注意下一个间隔在前一个完成后立即开始,无论回调的执行时间如何。所以如果回调执行完毕需要0.5s,定时器为2s,那么下一次调用将在回调函数完成后1.5s发生。 tmr.ALARM_SEMI:在调用 tmr.alarm() 完成 n 秒后运行回调函数。与tmr.ALARM_AUTO不同,下一个间隔不会自动开始,而是在你调用tmr.start()之后才会开始;您可能应该在回调函数中执行此操作。这意味着您可以将计时器设置为依赖于回调函数的执行时间。如果计时器是 2 秒,并且您在回调函数结束时重新启动计时器,那么下次运行回调的时间将是 2 秒。

您可能会说,您不希望回调函数的执行时间大于计时器周期,回调将不断堆叠,永远不会完成。回调应该简单快速地执行,可能会将额外的工作安排为另一个任务。

【讨论】:

你的意思是“Something to do”将在每个计时器回合结束时执行一次,而不是开始? 是的,完全正确。计时器运行 n 秒,然后执行代码。您可以根据mode参数将警报设置为一次性,或每隔n秒重复一次。 那么“Something to do”实际上会独立执行,而不是在定时器内部,而且无论执行时间长短,基本上都不会影响定时器?当下一个间隔结束时,计时器将触发另一个“有事做”线程。我的理解对吗? 我不明白您所说的“在计时器内”是什么意思。我认为您正在将您对计时器的理解应用于这个可能名称不佳的库。这个函数的作用是“n 秒后,运行这个函数”,“this”是“Something to do”。回调函数的执行时间不会影响定时器触发的时间,它总是在调用tmr.alarm()之后的n秒。 if 您设置了计时器以使其重复,该函数将根据您设置的模式再次调用。有关模式的更多信息,请参阅我的编辑。【参考方案2】:

我认为对 NodeMCU 是什么类型的固件或它需要什么样的编程模型存在误解。

NodeMCU 编程模型与 Node.js 类似,只是在 Lua 中。它是异步的和事件驱动的。因此,许多函数都有回调函数的参数。

来源:NodeMCU README, "Programming Model"

Lua 库提供了一组函数,用于将应用程序函数(用 Lua 编写)声明为回调(存储在 Lua 注册表中),以将应用程序任务与特定硬件和计时器事件相关联。这些在应用程序级别是非抢占式的* Lua 库与 SDK 协同工作,将挂起的事件排队并调用任何已注册的 Lua 回调例程,然后不间断地运行到完成。

来源:NodeMCU Lua 开发者常见问题解答

完整的解释见https://nodemcu.readthedocs.io/en/latest/en/lua-developer-faq/#so-how-does-the-sdk-event-tasking-system-work-in-lua的“事件任务系统”一章

你说的是

并且此计时器内的“要做的事情”执行超过 2 秒

但事实是它永远不会运行 2 秒。事实上,任何连续运行超过几毫秒的任务都可能导致 Wifi 和 TCP 堆栈失败。如果您编写的代码违反了这一原则,那么看门狗可能会随时重置您的设备。您的代码触发的事件被简单地添加到队列中并按顺序执行。

因此,在大多数情况下,正确答案是 b)。

【讨论】:

感谢您的详细回复。如果“要做的事情”不需要使用 Wifi 和 TCP 堆栈怎么办?让我假设“要做的事情”是打开 LED 3 秒,它真的会亮 3 秒吗? 我相信更多的误解...您不需要任何 处理 电源来保持 LED 亮起 3 秒。该设备需要几纳秒来将 GPIO 引脚从高电平变为低电平(反之亦然),然后它再次处于空闲状态,直到您告诉它反转操作。一个简单的眨眼示例是例如这里:roboindia.com/tutorials/esp8266-led-blinking-lua

以上是关于如果 NodeMCU 定时器内的代码在我设置的定时器间隔内执行会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

Jmeter -- 定时器

Jenkins定时构建时间设置

求教怎么在C语言中使用定时器

spring中定时器每周执行两次

定时器

jmeter的定时器