Overflow of millis() 100days running program

How can I handle a situation when the max number that can be store is passed?

I have a code that should run for 100 days straight. From what I understand after around 47 days the unsigned long will not be able to hold the millis() related timing

code:

const byte heartbeatLED = 13;
unsigned long heartbeatMillis;
unsigned long previousMillis = 0;

unsigned long interval = 20; //reading every x ms

//mux pin for reading//
int s0 = 2;
int s1 = 3;
int s2 = 4;
int s3 = 5;

const int NUMSENSORS = 14; // change this variable to set the number of sensors

int SIG_pin = A0;
int previousValue[NUMSENSORS] = {0};
bool isOn[NUMSENSORS] = {false};


int pressThreshold = 25; // Change this variable to set the pressThreshold value
byte filter = 5; //whatever is needed

void setup() {
  Serial.begin(115200);
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  pinMode(heartbeatLED, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    readSensors();
    checkHeartbeatTIMER();
  }
}

void readSensors() {
  // Loop through all the sensors
  for (int i = 0; i < NUMSENSORS; i++) {
    // Set the multiplexer to select the correct channel
    digitalWrite(s0, (i & 1));
    digitalWrite(s1, (i & 2) >> 1);
    digitalWrite(s2, (i & 4) >> 2);
    digitalWrite(s3, (i & 8) >> 3);

    // Read the sensor value
    int sensorValue = 1023 -  analogRead(SIG_pin);

    // Check if the sensor value has changed
    if (sensorValue != previousValue[i]) {
      // Check if the change is greater than the filter value
      if (abs(previousValue[i] - sensorValue) > filter) {
        // Update the previous value
        previousValue[i] = sensorValue;

        // Print the sensor value
        Serial.print("value_ch");
        Serial.print(i);
        Serial.print(" ");
        Serial.println(sensorValue);


        // Check if the sensor value is greater than the press threshold
        if (sensorValue > pressThreshold) {
          // Check if the sensor is not already on
          if (!isOn[i]) {
            // Update the on/off state
            isOn[i] = true;
            // Print the on/off state
            Serial.print("ch");
            Serial.print(i);
            Serial.print("on ");
            Serial.println(isOn[i]);
          }
        }
        else {
          if (isOn[i]) {
            isOn[i] = false;
            Serial.print("ch");
            Serial.print(i);
            Serial.print("on ");
            Serial.println(isOn[i]);
          }
        }
      }
    }
  }
}




void checkHeartbeatTIMER()
{
  //*********************************                                heartbeat TIMER
  //is it time to toggle the heartbeatLED ?
  if (millis() - heartbeatMillis >= 500ul)
  {
    //restart this TIMER
    heartbeatMillis = millis();


    //toggle the heartbeatLED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

} //END of   checkHeartbeatTIMER()

So what?
Do you worry that your wall-clock will explode every midnight?

1 Like

Have millis() trigger once every 86400000UL mS and then have the millis() routine count up. When the count reaches 100 boom! drop the mic.

what do you mean? It will not effect my code in undesired way?

How hard would it be to test your code for such an issue?

pretty hard I guess?

So you think you can't test the subtraction of one number from another?
Look, the millis() counter rolls over after ~47 days. Nothing else happens. It just goes to 0 and keeps counting up.
So, test several end-of-count scenarios.
(very large number) - (small number)
(small number) - (very large number)
etc. etc.
And look at what the results might be. Then apply that knowledge to your millis() math.

1 Like

if I change the unsigned long variables to uint32_t it means they will hold for another 47 days?

No.

1 Like

so what can I do in order to solve it? (apart of turning off and on again after 47 days)

will that help? (I asked chat gpt)


void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis < previousMillis) {
    // millis() rolled over, so adjust the previousMillis value accordingly
    previousMillis = currentMillis;
  }
  if (currentMillis - previousMillis >= interval) {
    previousMillis += interval; // increment previousMillis by interval
    readSensors();
    checkHeartbeatTIMER();
  }
}

If you have an ESP32 use the micros cycle counter of the ESP32 which overflows after 207 years.

but I don't... :frowning:

If you are timing intervals that are very long, you have to worry.

If you are timing intervals less than 49.7 days long, no worries. Just do it right.

a7

1 Like

Not a single straight answer everyone acting smart...

1 Like

Hi, as far as I understand your problem, I had to solve it for me as well and I believe many other people had as well. I believe that your problem is related to the fact that you want to subtract two values of millis() and see if the result is bigger than a certain interval you established in order to do some action. This works fine except for each 47 days when the millis() resets to zero and the difference between the two values doesn't work. Is your problem is this then I have good news for you. I have a very simple solution. Instead of subtracting the two values of millis like you do:

if (currentMillis - previousMillis >= interval)

You call a function instead like this:

if (difTempoMillis(currentMillis, previousMllis) >= interval)

and the trick is in this function.....
The function looks like this:

// ********************************************
unsigned long difTempoMillis(unsigned long tMillis, unsigned long tMillisAnt) {
// ********************************************
// Determines the deference between two readings of millis() providing for
// the case of the reset to zero of the millis() function

  if (tMillis >= tMillisAnt) return tMillis - tMillisAnt;
  else return 0xFFFFFFFF - tMillisAnt + tMillis; // Situação de overflow da função millis()
// WARNING: Don't change the order of operations in this statement as it can lead
// to unexpected results due to variable overflow.
}

Hope this help!

No, not really.
Too complicated.

Why isn't ChatGPT better at debugging?

Yeah, thanks for saying. I don't think chatGPT served you well, the comment is nonsense.

Just remove this pointless line

  if (currentMillis < previousMillis) {
    // millis() rolled over, so adjust the previousMillis value accordingly
    previousMillis = currentMillis;
  }

the rest looks plausible.

Only ppl who did not understand how to do it correctly.

There is no rollover problem with millis() when counting off small intervals. Small meaning less than 49.7 days.

No problem at that time, nor before, nor after.

The smarter ppl here have it

No problem to handle. No problem handling no problem.

a7

3 Likes

https://www.norwegiancreations.com/2018/10/arduino-tutorial-avoiding-the-overflow-issue-when-using-millis-and-micros/

2 Likes

If the interval does not exceed 49 days, then there are no problems

3 Likes