Al pasar por un proyecto antiguo, tenía un código en dos Arduino Due que se veía así
void loop()
{
foo();
delay(time);
}
teniendo en cuenta la mayoría de la literatura sobre el uso delay();
que recodifiqué esto como
void loop()
{
static unsigned long PrevTime;
if(millis()-PrevTime>time)
{
foo();
PrevTime=millis();
}
}
Sin embargo, esto parece haber creado una situación en la que los dos dispositivos derivan durante un período de tiempo en el que no
Mi pregunta es doble:
- ¿Por qué
if(millis()-PrevTime>time)
causaría más deriva quedelay(time)
? - ¿Hay alguna manera de evitar esta deriva sin volver a
delay(time)
?
arduino-due
code-review
timing
ATE-ENGE
fuente
fuente
foo; delay;
) tiene un período superior a 100 ms (es 100 ms + tiempo defoo
). Entonces experimentarás deriva (pero es eldelay
SW implementado el que está derivando). En cualquier caso, tenga en cuenta que incluso las implementaciones perfectamente iguales "derivan", porque los relojes no son iguales; si necesita una sincronización completa, use una señal para, bueno, sincronizar los dos programas.Respuestas:
Hay una cosa importante que debe recordar al trabajar con tiempo en un Arudino de cualquier forma:
Su función foo () tomará una cantidad de tiempo. Cuál es ese momento, no podemos decir.
La forma más confiable de lidiar con el tiempo es confiar solo en el tiempo de activación, no en determinar cuándo debería ser la próxima activación.
Por ejemplo, tome lo siguiente:
La variable
last
será el tiempo que se activó la rutina * más el tiempo quedoSomething
tardó en ejecutarse. Digamos queinterval
es 100, ydoSomething
tarda 10 ms en ejecutarse, obtendrá disparos a 101 ms, 212 ms, 323 ms, etc. No los 100 ms que esperaba.Entonces, una cosa que puede hacer es usar siempre el mismo tiempo, independientemente de recordarlo en un momento específico (como sugiere Juraj):
Ahora el tiempo que
doSomething()
lleva no tendrá efecto en nada. Por lo tanto, obtendrá disparos a 101 ms, 202 ms, 303 ms, etc. Aún no alcanza los 100 ms que deseaba, porque está buscando que hayan pasado más de 100 ms, y eso significa 101 ms o más. En su lugar, debe usar>=
:Ahora, suponiendo que no suceda nada más en su bucle, obtiene disparos a 100 ms, 200 ms, 300 ms, etc. Pero tenga en cuenta ese bit: "mientras no suceda nada más en su bucle" ...
¿Qué sucede si una operación que dura 5 ms ocurre a 99 ms ...? Su próximo disparo se retrasará hasta 104 ms. Eso es una deriva. Pero es fácil de combatir. En lugar de decir "El tiempo grabado es ahora", usted dice "El tiempo grabado es 100 ms más tarde de lo que era". Eso significa que, independientemente de los retrasos que obtenga en su código, su activación siempre será a intervalos de 100 ms, o se desplazará dentro de un tic de 100 ms.
Ahora obtendrá disparos a 100 ms, 200 ms, 300 ms, etc. O si hay retrasos en otros bits de código, puede obtener 100 ms, 204 ms, 300 ms, 408 ms, 503 ms, 600 ms, etc. Siempre intenta ejecutarlo lo más cerca posible el intervalo posible, independientemente de los retrasos. Y si tiene retrasos que son mayores que el intervalo, ejecutará automáticamente su rutina suficientes veces para ponerse al día con la hora actual.
Antes de que tuvieras deriva . Ahora tienes nerviosismo .
fuente
Porque reinicia el temporizador después de la operación.
fuente
Para lo que está intentando hacer, delay () es la forma adecuada de implementar el código. La razón por la que desearía usar if (millis ()) es si desea permitir que el bucle principal continúe en bucle para que su código o algún otro código fuera de ese bucle pueda realizar otro procesamiento.
Por ejemplo:
Esto ejecutaría foo () en el intervalo especificado mientras permite que el ciclo continúe ejecutándose en el medio. Puse el cálculo de next_trigger_time antes de la llamada a foo () para ayudar a minimizar la deriva, pero es inevitable. Si la deriva es una preocupación importante, use un temporizador de interrupción o algún tipo de sincronización reloj / temporizador. También recuerde que millis () se ajustará después de un período de tiempo y no lo tomé en cuenta para mantener el ejemplo de código simple.
fuente
long m - millis()
no hace lo que pretendes hacer? Eso está en la casa.Su código es correcto.
el problema con el que se encuentra es con millis (): tendrá un recuento insuficiente levemente (el recuento insuficiente máximo es apenas de 1 ms, por invocación).
la solución es con garrapatas más finas, como micros (), pero eso también contará un poco.
fuente