在任何形式的Arudino上工作时,需要记住一件事:
您的foo()函数将花费一些时间。那是什么时候,我们不能说。
处理时间的最可靠方法是仅依赖于触发时间,而不是依赖于确定下一次触发的时间。
例如,采取以下措施:
if (millis() - last > interval) {
doSomething();
last = millis();
}
该变量last
将是例程触发的时间*加上doSomething
运行所花费的时间。假设interval
是100,并且doSomething
需要10毫秒才能运行,您将在101毫秒,212毫秒,323毫秒等时间内获得触发。而不是您期望的100毫秒。
因此,您可以做的一件事就是始终使用相同的时间,而不必每次都记住特定点(如Juraj所建议的):
uint32_t time = millis();
if (time - last > interval) {
doSomething();
last = time;
}
现在,doSomething()
花费的时间将对任何事物都没有影响。因此,您将在101ms,202ms,303ms等处获得触发。仍然不是您想要的100ms-因为您正在寻找超过 100ms的时间-这意味着101ms或更多。相反,您应该使用>=
:
uint32_t time = millis();
if (time - last >= interval) {
doSomething();
last = time;
}
现在,假设循环中没有其他事件发生,您将在100ms,200ms,300ms等处获得触发。但是请注意一点:“只要循环中没有其他事件发生” ...
如果花费5毫秒的操作恰好发生在99毫秒...处会发生什么?您的下一次触发将延迟到104ms。那是一个漂移。但这很容易战斗。而不是说“现在是录制的时间”,而是说“录制的时间比现在晚100ms”。这意味着无论您在代码中遇到什么延迟,触发都将始终以100ms的间隔进行,或者在100ms的刻度内漂移。
if (millis() - last >= interval) {
doSomething();
last += interval;
}
现在,您将在100ms,200ms,300ms等处获得触发。或者,如果其他代码位存在延迟,您可能会得到100ms,204ms,300ms,408ms,503ms,600ms等。它总是尝试将其运行到接近不考虑延迟的时间间隔。而且,如果延迟时间大于间隔时间,它将自动运行您的例程足够的时间以赶上当前时间。
在你漂泊之前。现在,您有抖动。