0

I had written some code that involved doing something after 10 milliseconds had elapsed, however it was performing unexpectedly. Upon debugging, I think I have identified the error, and I wrote some code with just that block:

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;
}
    
}

The serial monitor "freezes on 150. it shows the values 0,10,20...as expected but it freezes on 150...and then nothing happens.

What exactly is causing this?

10
  • You should not relay on that if statement to be called once ever millisecond. Check for >= instead
    – Sim Son
    Apr 29 at 16:33
  • i didnt properly understand your first comment...
    – satan 29
    Apr 29 at 16:35
  • In my original program, I was doing something when exactly 10 milliseconds had elapsed..
    – satan 29
    Apr 29 at 16:36
  • Your sketch requires that the if statement is called ever millisecond. If timeis 9 in one iteration and 11 in the next iteration, then the code in the if block will never be executed.
    – Sim Son
    Apr 29 at 16:37
  • "when exactly 10 milliseconds" - you can't do it this way, you have to check if at leaest 10 ms have elapsed. If you need exact timing you have to use interrupts.
    – Sim Son
    Apr 29 at 16:40
3

The problem is, that you are filling up the Serial buffer rather fast, because you try to send ASCII numbers every 10ms at only 9600ms. When the buffer is full, Serial.println() will wait, until there is enough space free in the buffer for the current data. That makes your loop lasting significantly longer.

In that case the time, where the time is exactly 10 is missed. Thus the code does nothing at that point, until time rolls over and gets 10 again (48 days I think).

While you can mitigate the problem by using a higher baudrate, the main problem is still

if(time==10){

You have only provided an example code. Your real code might sometimes take longer than 10ms out of some other reason (actually this already gets critical, when the loop takes longer than 1ms, since it then might already miss the one moment, where time is 10). To futureproof your code and make sure, that you don't hunt down the same bug again and again, you should do, what you were told in the comments, and use

if(time>=10){

Depending on your code the event will still happen after 10ms the absolute most of the time. But this variant also doesn't break, if the loop takes longer than 10ms sometimes.

2
  • "might sometimes take longer than 10ms" - actually the if(time==10) version becomes critical as soon as loop() takes longer than 1 ms, because it has to compare time with ever tick of millis() ;)
    – Sim Son
    Apr 30 at 22:13
  • @SimSon You are totally right. I will add that to the answer
    – chrisl
    Apr 30 at 22:30
2

your logic is just tricky to confuse. It is repeatable because along as you not change the if logic, the code is going to run till it displays 150. then it will stop. You can also check the same behaviour here

Once the time difference is not exactly equal to 10, the if part will not be executed. Hence, the prevtime will not catch up with the newtime anymore. newTime will soon grow to be bigger and the difference will always be greater than 10.

I suggest visiting https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay to get some hints on tracking time in a safer way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.