我试图让我的Arduino 草图在每次执行该loop函数时休眠1秒钟.
循环中涉及的方法可能会改变它们的执行时间,这就是我实现millis的原因.
我正在做以下事情:
unsigned long ejecucionExcedida = 0;
int calcularExceso(int tiempo) {
if (tiempo>1000) {
ejecucionExcedida = ejecucionExcedida + (tiempo-1000);
// TO DO agregar alarma si el exceso se incrementa mucho
if(ejecucionExcedida > 20000) {
alertas(9);
}
// Listo las alertas :D
return 1000;
}
else {
if(ejecucionExcedida == 0) {
return tiempo;
}
else {
if (ejecucionExcedida + tiempo < 1000) {
ejecucionExcedida = 0;
return ejecucionExcedida + tiempo;
}
else {
int exceso = ejecucionExcedida + tiempo - 1000;
ejecucionExcedida = exceso;
return 1000;
}
}
}
}
void loop() {
unsigned long comienzo = millis();
// A couple of methods
unsigned long final = millis();
delay(calcularExceso(final-comienzo));
}
Run Code Online (Sandbox Code Playgroud)
预计每次执行时草图将延迟一秒钟,但我已经用时钟计时,每次执行时间超过一秒.
循环函数与您的代码结合导致问题.
void loop() {
// B
unsigned long comienzo = millis();
// a couple of methods
unsigned long final = millis();
// C
delay(calcularExceso(final-comienzo));
// A
}
Run Code Online (Sandbox Code Playgroud)
您没有考虑从A到B使用的时间.您也没有考虑测量和延迟(C)之间的时间.
最大的原因是A到B.如果你查看arduino/hardware/arduino/cores/arduino,你会发现main.cpp.一旦你查看这个文件,很明显为什么这需要很长时间.
#include <Arduino.h>
int main(void)
{
init();
#if defined(USBCON)
USB.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它实际上不仅仅是"没有".
我建议切换到以下方法来弥补这一点
void loop() {
static unsigned long start = millis();
// a couple of methods
while (millis() - start < 1000) {
// busy wating
}
// do NOT read again as this would cummulate the drift
// instead add just one second to start
start += 1000;
}
Run Code Online (Sandbox Code Playgroud)
与您的代码不同,它将变量start声明为static.这意味着在loop()的第一次传递期间将从millis()初始化start.在loop()的每次传递之后,它的值将保留用于loop()的下一次传递.在后续通过期间,它将不再被初始化.因此,在第一次通过中,启动可能具有任何巧合值,例如42.紧接着,最后的while将等到millis()达到1042,总计运行时间为1s.然后start将增加1000.所以在第二次传递中它将是1042而最后一次将等到millis()达到2042.在第三次传递开始将是2042并且最后一次将等到millis()到达3042等.正如你所看到的那样,最终的结束时间总是相隔1000毫秒.由此得出,loop()的开始将间隔1000毫秒(平均),除了可能由serialEventRun()处理引入的一些抖动.
如果您在此更改后仍然遇到大量漂移,那么代码中的某些内容会阻止中断很长时间.由于Arduino的时间是中断的,所以你不能长时间阻止它们.不幸的是,有些功能可能会阻止中断作为副作用.您必须删除代码段才能找出导致此问题的部分.通常最好添加一些LED并每次切换一次状态.
尽管如此,根据您的Arduino型号,您最终仍会遇到一些漂移.较旧的型号有晶体时钟漂移约10ppm(每天几秒).较新的型号通常具有晶体谐振器(更便宜),可能漂移几千ppm(每小时几秒).我在一篇关于Arduino晶体偏差的文章中对此进行了分析