Проходя старый проект, у меня был код на двух Arduino Due, который выглядел так
void loop()
{
foo();
delay(time);
}
принимая к сердцу большинства из литературы об использовании delay();
я переделал это как
void loop()
{
static unsigned long PrevTime;
if(millis()-PrevTime>time)
{
foo();
PrevTime=millis();
}
}
Тем не менее, это, кажется, создало ситуацию, когда два устройства дрейфуют в течение периода времени, когда они не делали ранее
Мой вопрос двоякий:
- Почему бы
if(millis()-PrevTime>time)
вызвать больше дрейфа, чемdelay(time)
? - Есть ли способ предотвратить этот дрейф, не возвращаясь к
delay(time)
?
arduino-due
code-review
timing
ATE-Энж
источник
источник
foo; delay;
) имеет период более 100 мс (это 100 мс + времяfoo
). Таким образом, вы будете испытывать дрейф (но это -delay
реализованный SW, который дрейфует). В любом случае, имейте в виду, что даже совершенно равные реализации «дрейфуют», потому что часы не равны; если вам нужна полная синхронизация, используйте сигнал для синхронизации двух программ.Ответы:
Есть одна важная вещь, которую вы должны помнить, работая со временем на Arudino любой формы:
Ваша функция foo () займет некоторое время. Что это за время, мы не можем сказать.
Самый надежный способ справиться со временем - полагаться только на время запуска, а не на выработку следующего запуска.
Например, возьмите следующее:
Переменная
last
будет временем, когда подпрограмма сработала * плюс время,doSomething
затраченное на выполнение. Так, скажемinterval
, 100, иdoSomething
для запуска требуется 10 мс, вы получите срабатывание при 101 мс, 212 мс, 323 мс и т. Д. Не те 100 мс, которые вы ожидали.Поэтому вы можете всегда использовать одно и то же время независимо от запоминания определенного момента (как предлагает Джурадж):
Теперь время, которое
doSomething()
уходит, ни на что не повлияет. Таким образом, вы получите срабатывание при 101 мс, 202 мс, 303 мс и т. Д. Все еще не совсем те 100 мс, которые вы хотели - потому что вы ищете более 100 мс пройденных - и это означает 101 мс или более. Вместо этого вы должны использовать>=
:Теперь, предполагая, что в вашем цикле больше ничего не происходит, вы получаете срабатывание на 100 мс, 200 мс, 300 мс и т. Д. Но обратите внимание на этот бит: «пока в вашем цикле больше ничего не происходит» ...
Что произойдет, если операция, которая занимает 5 мс, происходит при 99 мс ...? Ваш следующий запуск будет отложен до 104 мс. Это дрейф. Но с этим легко бороться. Вместо того чтобы сказать «записанное время сейчас», вы говорите «записанное время на 100 мс позже, чем было». Это означает, что независимо от того, какие задержки вы получаете в своем коде, ваш запуск всегда будет происходить с интервалами в 100 мс или дрейфом в пределах 100 мсек.
Теперь вы получите срабатывание при 100 мс, 200 мс, 300 мс и т. Д. Или, если есть задержки в других битах кода, вы можете получить 100 мс, 204 мс, 300 мс, 408 мс, 503 мс, 600 мс и т. Д. Он всегда пытается запустить его как можно ближе к интервал, насколько это возможно, независимо от задержек. И если у вас есть задержки, превышающие интервал, он автоматически запустит вашу обычную программу достаточно времени, чтобы догнать текущее время.
До того, как вы дрейфовали . Теперь у вас есть дрожание .
источник
Потому что вы сбрасываете таймер после операции.
источник
Для того, что вы пытаетесь сделать, delay () является подходящим способом реализации кода. Причина, по которой вы захотите использовать if (millis ()), заключается в том, что вы хотите, чтобы основной цикл продолжал цикл, чтобы ваш код или какой-либо другой код вне этого цикла мог выполнять другую обработку.
Например:
Это будет запускать foo () в указанный интервал, позволяя циклу продолжать выполнение между ними. Я поместил вычисление next_trigger_time перед вызовом foo (), чтобы помочь минимизировать дрейф, но это неизбежно. Если дрейф является серьезной проблемой, используйте таймер прерывания или какую-либо синхронизацию часов / таймера. Также помните, что millis () будет работать через некоторое время, и я не учел это, чтобы сохранить пример кода простым.
источник
long m - millis()
не делает то, что вы собираетесь делать? Это на дом.ваш код правильный.
проблема, с которой вы сталкиваетесь, связана с функцией millis (): она будет недооценена (максимальный недосчет составляет всего лишь 1 мс на вызов).
Решение заключается в более тонких тиках, таких как micros (), но это также будет немного занижено.
источник