2

我试图让我的 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));
}

预计草图将在每次执行时恰好延迟一秒钟,但我已经用时钟对其进行计时,每次执行花费的时间超过一秒。

4

2 回答 2

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 声明为静态。这意味着 start 将在 loop() 的第一次传递期间从 millis() 初始化。在 loop() 的每一次通过之后,它的值将被保留用于 loop() 的下一次通过。在随后的传递过程中,它将不再被初始化。因此,在第一次通过 start 可能有任何巧合的值,例如 42。因此,最后的 while 将等到 millis() 达到 1042,总计 1s 运行时。然后 start 将增加 1000。所以在第二遍中它将是 1042,最后的 while 将等到 millis() 达到 2042。在第三遍中 start 将是 2042,最后的 while 将等到 millis() 达到3042 等等。正如你所看到的,最后的结束时间总是相隔 1000 毫秒。

如果您在此更改后仍然遇到巨大的漂移,那么您的代码中有一些东西会长时间阻止中断。由于 Arduino 的时间被中断,因此您不能长时间阻止它们。不幸的是,有些函数可能会阻止中断作为副作用。您必须删除部分代码才能找出导致此问题的部分。通常,添加一些 LED 并在每次通过时切换其状态一次是个好主意。

话虽如此,最终您仍然会根据您的 Arduino 模型经历一些漂移。旧型号的晶体时钟漂移约 10ppm(每天几秒)。较新的型号通常具有可能漂移数 1000 ppm(每小时几秒)的晶体谐振器(更便宜)。我在一篇关于Arduino 晶体偏差的文章中对此进行了分析

于 2013-05-26T10:16:26.377 回答
0

您的代码需要时间来执行,但您没有考虑到这一点

于 2013-05-26T02:29:58.027 回答