millis() timer stalling after 1 minute?


I'm experiencing a strange problem that I can't see the solution to. I have a sequence of events I want to happen, so am using an array to hold the different times in milliseconds, and using a millis() timer to count through. I can get the sequence to work fine using delay(), but the program has to be non-blocking due the other parts yet to be implemented.

I've simplified the timer lengths here in timerLength[], roughly dividing 1000ms into 6 equal parts to get an idea of how long it takes for the program to stall but they vary between 20 and 4000ms.

It seems to work fine for around 40 seconds and then crashes. What am I doing wrong?

I'm using an Arduino Uno. I've swapped the mcu chip out to see if that made a difference, and it doesn't. I was using 1.8.6 up until an hour ago when I updated to 1.8.9, hoping it was a bug, but no change. I'm assuming I'm doing something wrong but the code is so simple that I don't know where.

Any help greatly appreciated!

long timerLength[] = {167, 167, 167, 167, 167, 167};
int spacetime = 0;
int playState = 0;
int loopCount;
void setup() {
  // put your setup code here, to run once:

void loop() {

  if (millis() > timerLength[playState] + spacetime) {
    spacetime = millis();
    playState += 1;

    // Serial.println(playState);
  switch (playState) { //100, 3900, 3920, 4020, 8020, 8030
    case 0:
      digitalWrite(3, HIGH);
      // Serial.println("case0 100ms");

    case 1:
      digitalWrite(3, LOW);
      // Serial.println("case1 3800ms");
    case 2:

      // Serial.println("case2 20ms");
    case 3:

      // Serial.println("case3 4000ms");
    case 4:
      digitalWrite(2, HIGH);
      // Serial.println("case4 4000ms");
    case 5:
      digitalWrite(2, LOW);
      //Serial.println("case5 10ms");
      playState = 0;
      loopCount += 1;
      Serial.print("loop count = ");
      playState = 0;
      Serial.print("get here?");


  // put your main code here, to run repeatedly:


spacetime is an int.
millis returns a unsigned long

hero!!!!!! That makes total sense. An int will expire in 32 seconds. I knew it'd be something simple.

Thanks so much!!!

 if (millis() > timerLength[playState] + spacetime) {

Also use millis() in a subtractive way to avoid problems with roll over

if (millis() - spacetime >  timerLength[playState]) {

nice one, I'll try that. Cheers

Also note, you will ever execute 'playState' == 0 because you do the increment at the start.

septillion: Also use millis() in a subtractive way to avoid problems with roll over

Hi septillion, what is the roll over problem you mentioned? Can you share an example?

millis() is an unsigned long so the max value is 4.294.967.295. Let's say the last even was at 4.294.967.200 and you want an interval of 100. Now millis() is at 4.294.967.250

const unsigned long Period = 100;
unsigned long previousMillis = 4294967200

if(millis() > previousMillis + Period) //becomes
//if(4294967250 > (4294967200 + 100))
//which after doing the integer math in unsigned long is:
//if(4294967250 > 5)  because the math rolled over
//which is true even though just 50ms have passed

//now with subtraction:
if(millis() - previousMillis > Period) //becomes
if((4294967250 - 4294967200) > 100)
//which after doing the integer math in unsigned long is:
if(50 > 100)
//which is false aka that is what you want it to be

Thank you for your great explanation, also I found I great tutorial regarding millis() roll over that I want to share