Issue with simple timer based on millis()

Hello everyone,
Sorry to bother but I am at my wits end. I'm experimenting with timers, and starting very simple. The following code is supposed to print the content of a variable each time an interval of time has passed, then update that variable. But for some reason I'm getting no output on the serial monitor.
I have used the serial monitor before on other projects without issue, so I'm not sure what the problem could be.
Is there any error in my code?

unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
const long interval = 1000;

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (currentMillis - previousMillis >= interval) {
    Serial.println(previousMillis);
    previousMillis = currentMillis;
  }
  else {
    ;
  }
}

//  previousMillis += interval;

Your problem is simple...

... You need to put the part "currentmillis = millis() ;"
In the void loop...
... At the moment your arduino runs this code only ones, when turned on and not in every run threw...

Thank you very much for the answer, I assumed it updated automatically as millis() changed, but instead it just stores a static picture at the point of assignment?

To add to what is in Reply #1, this code will not even initialise the value of currentMillis

unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
const long interval = 1000;

void setup() {
  Serial.begin(9600);
}

because the values that are given to the variables (such as previousMillis = 0) are given by the compiler before the program is uploaded to the Arduino whereas the function millis() cannot have any value until the program is running - i.e. after it has been uploaded to the Arduino.

The first part of the running code is in the function setup() - but it only runs once and you need the value of currentMillis to be updated regularly which is why you need the line currentMillis = millis(); in the loop() function.

...R

Hi Robin,

Thanks for your reply. It's great to see you still browsing these forums; I've just been reading your posts about doing things simultaneously, and now planning a project. Both are awesome so thank you for your time creating them.

That's where I got to the idea to do this experiment, because I couldn't figure out how these 2 lines are (roughly) equivalent as you suggested

previousMillis = currentMillis;
 
previousMillis += interval;

To my uneducated mind it seems that in the 2nd instance if the action is being triggered at a time period significantly longer than the interval variable, they would act differently. For example if you wait a minute, in the 1st instance you could only trigger the action once before you have to wait for the full duration of interval; in the 2nd instance if you wait a minute you could trigger the action more than once before you have to wait for the full duration of interval.

zheygrudov:
That's where I got to the idea to do this experiment, because I couldn't figure out how these 2 lines are (roughly) equivalent as you suggested

previousMillis = currentMillis;

previousMillis += interval;

Like a lot of programming problems you need to have a clear understanding of what you want to achieve - that must come before any code is written.

I can think of two substantially different situations. In one case you might want to blink an LED at a regular interval - for example every time millis() counts to an extra 1000. In the other (very different) case you might start something NOW which takes an appreciable time to complete - perhaps you need to drive a stepper motor for 8000 steps. And you want the next group of 8000 steps to start (say) 5 seconds after the first lot finishes.

In the first of these cases the simple use of previousMillis updated to match millis() like this is appropriate

if (currentMillis - previousMillis >= 1000) {
    previousMillis = currentMillis;
    blinkMyLed();
}

but in the second case doing that would start the clock when the stepper motor starts moving rather than when it finishes. In that case the code needs to be something like this

if (currentMillis - previousMillis >= 5000) {
    startStepperMoving
}
if (stepperIsFinished) {
      previousMillis = millis();
}
}

The choice between previousMillis = currentMillis and previousMillis += interval is for dealing with a different type of problem.

With the code if (currentMillis - previousMillis >= 1000) it is possible that the actual interval might be 1001 msecs and if the accumulation of those small errors matters then previousMillis += interval will keep the timing accurate. However the complication with this approach is that if the interval is very short (perhaps 10 or 20 msecs) and if the code in setup() takes (say) 2000 msecs you will get a series of instant repeats while the value of previousMillis increments from 0 to whatever millis() has reached. On one occasion I spent 3 or 4 hours before I realised this was the problem. Consequently I now use previousMillis = currentMillis unless the timing really is critical.

...R

With the code if (currentMillis - previousMillis >= 1000) it is possible that the actual interval might be 1001 msecs and if the accumulation of those small errors matters then previousMillis += interval will keep the timing accurate. However the complication with this approach is that if the interval is very short (perhaps 10 or 20 msecs) and if the code in setup() takes (say) 2000 msecs you will get a series of instant repeats while the value of previousMillis increments from 0 to whatever millis() has reached. On one occasion I spent 3 or 4 hours before I realised this was the problem. Consequently I now use previousMillis = currentMillis unless the timing really is critical.

Wow what a specific issue, impressive that you even thought to consider it. Also a great point about being clear what your code needs to do before you start writing it.

I have RSI and I'm trying to create an assistive device for myself, so your help is much appreciated.

Also note we will ALWAYS use > or >= when looking at millis() values, never ==. This for two reasons.

  1. your process may take more than 1 ms before it comes back and miss that exact point in time,
  2. millis() does not update exactly every 1 ms, it is a little slower (980 counts per second) and the missing milliseconds are added to keep up, using leap-milliseconds so to say. So not every single value millis() could take, it will take, and there is a chance the value you happen to pick, happens to be skipped.

Good point, thanks for sharing.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.