Неожиданный вывод для простого кода, включающего вычисление временного интервала в 10 мс

Я написал какой-то код, который включал в себя выполнение чего-то после 10 миллисекунд, однако он выполнялся неожиданно. После отладки, я думаю, что я определил ошибку, и я написал некоторый код только с этим блоком:

unsigned long int newtime=0;
unsigned long int prevtime=0;
int time;
void setup()
{
  Serial.begin(9600);
}

void loop()
{
newtime=millis();
time=newtime-prevtime;
if(time==10){
  Serial.println(prevtime);
  prevtime+=10;
}
    
}

Последовательный монитор "замирает на 150. он показывает значения 0,10,20 ... как ожидалось, но он зависает на 150...и тогда ничего не происходит.

Что именно вызывает это?

, 👍0

Обсуждение

Вы не должны полагаться на то, что оператор if будет вызываться один раз в миллисекунду. Проверьте для >= вместо, @Sim Son

я не совсем понял ваш первый комментарий..., @satan 29

В моей первоначальной программе я что-то делал, когда прошло ровно 10 миллисекунд.., @satan 29

Для вашего скетча требуется, чтобы оператор if вызывался когда-либо за миллисекунду. Если "время" равно 9 на одной итерации и " 11 " на следующей итерации, то код в блоке if никогда не будет выполнен., @Sim Son

"когда ровно 10 миллисекунд" - вы не можете сделать это таким образом, вы должны проверить, прошло ли *по крайней мере* 10 мс. Если вам нужно точное время, вы должны использовать прерывания., @Sim Son

10, а не 1. а также, поскольку я сбрасываю значение prevtime, значение переменной time не может превышать 10, @satan 29

Я бы сказал, что с частотой каждые 10 мс вы довольно быстро заполняете последовательный буфер. Вы можете попробовать использовать более высокую скорость (например, 115200), @chrisl

просто чтобы добавить, код отлично работает, когда я заменяю 10 на 100., @satan 29

Если (по какой-либо причине) ваш цикл занимает *немного* больше 1 миллисекунды, то есть вероятность, что оператор if пропустит момент, когда "время==10", и предложение if никогда не станет истинным. По крайней мере, не раньше, чем подбежал millis()., @Sim Son

@крисл, ты right...it работает с такой скоростью передачи данных, @satan 29


2 ответа


Лучший ответ:

3

Проблема в том, что вы заполняете последовательный буфер довольно быстро, потому что вы пытаетесь отправить ASCII-номера каждые 10 мс при 9600 мс. Когда буфер заполнен, Serial.println() будет ждать, пока в буфере не останется достаточно свободного места для текущих данных. Это делает ваш цикл значительно дольше.

В этом случае пропущено время, когда время равно ровно 10. Таким образом, код ничего не делает в этот момент, пока время не перевернется и снова не получит 10 (48 дней, я думаю).

Хотя вы можете смягчить проблему с помощью более высокой скорости, основная проблема все еще остается

if(time==10){

Вы предоставили только пример кода. Ваш реальный код может иногда занять больше 10 мс по какой-то другой причине (на самом деле это уже становится критическим, когда цикл занимает больше 1 мс, так как он может уже пропустить один момент, когда время равно 10). Чтобы защитить свой код и убедиться, что вы не выслеживаете одну и ту же ошибку снова и снова, вы должны делать то, что вам сказали в комментариях, и использовать

if(time>=10){

В зависимости от вашего кода событие все равно произойдет после 10 мс в абсолютном большинстве случаев. Но этот вариант также не ломается, если цикл иногда занимает больше 10 мс.

,

"*иногда может занять больше 10 мс*" - на самом деле версия "если(время==10)" становится критической, как только "цикл ()" занимает больше времени, чем **1** ms, потому что он должен сравнивать "время" с любым тиком " millis()";), @Sim Son

@СимСон, ты совершенно прав. Я добавлю это к ответу, @chrisl


2

вашу логику просто сложно запутать. Это повторяется, потому что, если вы не измените логику if, код будет выполняться до тех пор, пока не отобразится 150. тогда это прекратится. Вы также можете проверить то же поведение здесь

Как только разница во времени не будет точно равна 10, часть if не будет выполнена. Следовательно, prevtime больше не будет догонять new time. новое время скоро станет больше, и разница всегда будет больше 10.

Я предлагаю посетить https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay чтобы получить некоторые подсказки по отслеживанию времени более безопасным способом.

,