Best Practice with millis()?

I have seen code examples using millis 2 different ways and was wondering if one of these is better then the other.

Method 1:

unsigned long previousMillis = 0;     
unsigned long interval = 1000;      

void setup() {
  // setup code here     
}

void loop()
{
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;   
    // do something
    
  }
}

Method 2:

unsigned long previousMillis = 0;     
unsigned long interval = 1000;      

void setup() {
  // setup code here     
}

void loop()
{
  unsigned long currentMillis = millis();
 
  if(currentMillis > nextMillis) {
    nextMillis = currentMillis + interval;   
    // do something
    
  }
}

Method 2 only does the addition/subtraction one time so it would save some cycles every time through the loop, however it looks like it will have issues when the unsigned long rolls over (approximately 50 days).

does Method 1 get around the bound condition when the millis rolls over or is there any other reason to do the code that way instead of method 2?

does Method 1 get around the bound condition when the millis rolls over

Yes, it does, and that is why it is the preferred solution. In terms of time required, the subtraction operation is very fast. Don't worry about "saving clock cycles" here.

thank you.

but look at this code:

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


void loop()
{
  Serial.println( millis()-4294967295 );
}

where 4294967295 is the maximum unsigned long value. The result because of overflow (i suppose) is only the millis() value. So currentMillis - previousMillis can make problems when previousMillis is a big value

How is the upper bits dropping off a problem?

How much is 0x00000100 - 0xFFFFFFE0? which would be a rollover condition?
= 0x00000120, the bits above the long word go away, and result in the answer you want.

While Method 1 is preferred it is not correct...

if(currentMillis - previousMillis >= interval) {

PaulS:

does Method 1 get around the bound condition when the millis rolls over

Yes, it does, and that is why it is the preferred solution. In terms of time required, the subtraction operation is very fast. Don't worry about "saving clock cycles" here.

But so does method 2. Try out this sketch. It does something once per second and uses addition rather than subtraction. I think it's also simpler for beginners to understand, since there's the analogy of "You look at the clock, figure out when it should be done by, then when it's that time, you do it."

// This variable stores the current time returned by millis()
extern volatile unsigned long timer0_millis;

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

    cli(); //disable interrupts

    // Max unsigned long: 4,294,967,295 
    // Set the current time to 5 seconds before wrap around
    //   so we don't have to wait 50 days to test this
    timer0_millis = 4294962295UL;

    sei(); //enable interrupts again
}


// Print out the current time every second

void loop() {
    static unsigned long curTime;
    static unsigned long timeToFire;

    curTime = millis();

    if (curTime >= timeToFire) {
        Serial.print("Current time: "); Serial.println(millis());
        timeToFire = curTime + 1000;
    }
}

WizenedEE:
But so does method 2. Try out this sketch. It does something once per second and uses addition rather than subtraction.

Your analysis is incomplete. Method 2 has a fatal flaw. Method 1 is the correct choice.

And the flaw is this...

Let's say curTime and timeToFire are UINT32_MAX - 900. Then we run this:

        timeToFire = curTime + 1000;

What is timeToFire now? 100. What is curTime? Still UINT32_MAX - 900. Is curTime > timeToFire? You bet. So the following will fire constantly for 900ms.

    if (curTime >= timeToFire) {
        Serial.print("Current time: "); Serial.println(millis());
        timeToFire = curTime + 1000;
    }

And now you have a bug. A subtle bug, a rare bug, a bug that only lasts for 900ms. But still a bug, and why do it when there is a perfectly good method 1 at your disposal?

maniacbug:
...

Oh, I see. Thanks.

CrossRoads:
How is the upper bits dropping off a problem?

How much is 0x00000100 - 0xFFFFFFE0? which would be a rollover condition?
= 0x00000120, the bits above the long word go away, and result in the answer you want.

In that case no problem because the bit above are lost but how if I substract A and B with B bigger than A like this:
A-B= 0x00000100 - 0x0000FFE0 (dec 256-65504 )
I obtain FFFF0120 that in decimal is -65248 only if I use SIGNED number

but how if I substract A and B with B bigger than A like this

Does your Arduino's clock run backwards? The specific discussion going on deals with subtracting an earlier time from a later time to get the interval between the two times. The B value (the earlier time) can not possibly be larger than the A value (the later time).

No, unfortunatly it can, and this is the problem I am thinking about. This happen after millis has reached the maximum unsigned long value. It restarts from 0 and so we can have situations like thisTime=210510 oldTime=4294967200. The problem is about number rappresentation. If you have 2-4 the result is -2 but if the maximum value you can store is (for example) 5 the time elapsed would be 3. In this case the maximum value is 4294967295(the maximum unsigned long value)

The only time (forgive the pun) you'll have a problem is if the interval is more than half the rollover time.

AWOL:
The only time (forgive the pun) you'll have a problem is if the interval is more than half the rollover time.

Exact! For example having as max number 255 (8bit)

d(12-240) --> b(0000 1100-1111 0000) = b0001 1100 d28 OK

d(12-112) --> b(0000 1100-0111 0000) = b1001 1100 d-100 WRONG (result would be 255-112+12=155 )

Exact!

On the other hand, the rollover time is 49+ days. If the events of interest are more than 24 days apart, millis() is not really the tool of choice. An RTC is, for durations like that.

PaulS:
An RTC is, for durations like that.

you're perfectly right!

cantore:

AWOL:
The only time (forgive the pun) you'll have a problem is if the interval is more than half the rollover time.

Exact! For example having as max number 255 (8bit)

d(12-240) --> b(0000 1100-1111 0000) = b0001 1100 d28 OK

d(12-112) --> b(0000 1100-0111 0000) = b1001 1100 d-100 WRONG (result would be 255-112+12=155 )

No, no, no. There is no problem at all if the interval is more than half the rollover time.

Consider the above, with an 8-bit timer. At time 112 was the 'last' event, and 12 is the 'current' time? How much time has elapsed? Well, with uint8_t, 12-112 is 156, and that's exactly right. 156 ticks have passed. 144 ticks passed between the last event and the rollover, and 12 more passed between the rollover and now. No problem.

Consider an extreme case, back to uint32_t's from millis(), where the interval is 4294966296 (aka, -1000). The 'last' event was at 4294967196 (-100), and the 'current' time is 4294966196 (-2100). What is the elapsed time? now-current is 4294965296 (-2000) which is still less than the interval, and so your event won't fire. All is well.