Arduino millis的功能比预期的要长

时间:2013-05-26 02:24:03

标签: arduino timing

每次执行loop函数时,我都试图让我的Arduino sketch睡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));
}

预计草图在每次执行时都会延迟一秒钟,但我已经用时钟计时,每次执行的时间超过一秒。

2 个答案:

答案 0 :(得分:5)

循环功能与您的代码结合导致了问题。

void loop() {
// B 

    unsigned long comienzo = millis();

    // a couple of methods

    unsigned long final = millis();
// C
    delay(calcularExceso(final-comienzo));
// A
}

您没有考虑从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;
}

它实际上不仅仅是“没有”。

我建议切换到以下方法来补偿这个

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;
}

与您的代码不同,它将变量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 crystal deviation

的文章中对此进行了分析

答案 1 :(得分:0)

您的代码需要时间才能执行,但您没有考虑到