Passando por um projeto antigo, eu tinha código em dois Arduino Due que eram parecidos com este
void loop()
{
foo();
delay(time);
}
levando a sério a maioria da literatura sobre o uso delay();
eu recodifiquei isso como
void loop()
{
static unsigned long PrevTime;
if(millis()-PrevTime>time)
{
foo();
PrevTime=millis();
}
}
No entanto, isso parece ter criado uma situação em que os dois dispositivos flutuam ao longo de um período em que não o faziam anteriormente
Minha pergunta é dupla:
- Por que
if(millis()-PrevTime>time)
causaria mais desvio do quedelay(time)
? - Existe uma maneira de evitar esse desvio sem voltar para
delay(time)
?
arduino-due
code-review
timing
ATE-ENGE
fonte
fonte
foo; delay;
) tem um período maior que 100 ms (é 100 ms + tempo defoo
). Então você experimentará a deriva (mas é odelay
SW implementado que está à deriva). De qualquer forma, lembre-se de que mesmo implementações perfeitamente iguais "flutuam", porque os relógios não são iguais; se você precisar de sincronização completa, use um sinal para, bem, sincronizar os dois programas.Respostas:
Há uma coisa importante que você precisa lembrar ao trabalhar com o tempo em um Arudino de qualquer forma:
Sua função foo () levará um tempo. Que horas são, não podemos dizer.
A maneira mais confiável de lidar com o tempo é confiar apenas no tempo para acionar, e não trabalhar quando o próximo acionamento deve ser.
Por exemplo, tome o seguinte:
A variável
last
será o tempo que a rotina disparou * mais o tempodoSomething
necessário para executar. Digamos queinterval
é 100 edoSomething
leva 10ms para funcionar, você receberá disparos a 101ms, 212ms, 323ms, etc. Não os 100ms que você estava esperando.Portanto, uma coisa que você pode fazer é sempre usar o mesmo tempo, independentemente, lembrando-o em um momento específico (como sugere Juraj):
Agora, o tempo
doSomething()
gasto não terá efeito em nada. Então você terá disparos a 101ms, 202ms, 303ms, etc. Ainda não exatamente os 100ms que você queria - porque você está procurando mais de 100ms - e isso significa 101ms ou mais. Em vez disso, você deve usar>=
:Agora, supondo que nada mais aconteça no seu loop, você recebe disparos a 100ms, 200ms, 300ms, etc. Mas observe o seguinte: "enquanto nada acontecer no seu loop" ...
O que acontece se uma operação que leva 5ms ocorrer a 99ms ...? Seu próximo disparo será atrasado até 104ms. Isso é uma deriva. Mas é fácil de combater. Em vez de dizer "O tempo gravado é agora", você diz "O tempo gravado é 100 ms depois do que era". Isso significa que, independentemente dos atrasos no código, o acionamento será sempre em intervalos de 100 ms ou será desviado dentro de um tick de 100 ms.
Agora você terá disparos em 100ms, 200ms, 300ms, etc. Ou, se houver atrasos em outros bits de código, você poderá obter 100ms, 204ms, 300ms, 408ms, 503ms, 600ms, etc. o intervalo possível, independentemente dos atrasos. E se você tiver atrasos maiores que o intervalo, ela executará automaticamente sua rotina vezes suficientes para acompanhar a hora atual.
Antes de você se desviar . Agora você tem instabilidade .
fonte
Porque você redefine o cronômetro após a operação.
fonte
Para o que você está tentando fazer, delay () é a maneira apropriada de implementar o código. O motivo pelo qual você deseja usar o if (millis ()) é se você deseja permitir que o loop principal continue em loop, para que seu código ou outro código fora desse loop possa executar outro processamento.
Por exemplo:
Isso executaria foo () no intervalo especificado, permitindo que o loop continuasse sendo executado no meio. Eu coloquei o cálculo de next_trigger_time antes da chamada para foo () para ajudar a minimizar a deriva, mas é inevitável. Se a deriva for uma preocupação significativa, use um cronômetro de interrupção ou algum tipo de sincronização de relógio / cronômetro. Lembre-se também de que millis () será resolvido após algum período de tempo e eu não expliquei isso para manter o exemplo de código simples.
fonte
long m - millis()
não faz o que você pretende fazer? Isso é por conta da casa.seu código está correto.
o problema com o qual você se depara é com millis (): ele subconta ligeiramente (a subconta máxima é apenas 1ms, por invocação).
a solução é com ticks mais finos, como micros () - mas isso também subconta um pouco.
fonte