Go Down

Topic: millis() timer stalling after 1 minute? (Read 101 times) previous topic - next topic

deved

Hi,

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!

Code: [Select]
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:
  Serial.begin(115200);
}

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");

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

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

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

  }

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

}

TheMemberFormerlyKnownAsAWOL

spacetime is an int.
millis returns a unsigned long

deved

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

Thanks so much!!!

septillion

#3
Aug 16, 2019, 10:34 am Last Edit: Aug 16, 2019, 10:34 am by septillion
Code: [Select]
if (millis() > timerLength[playState] + spacetime) {
Also use millis() in a subtractive way to avoid problems with roll over
Code: [Select]
if (millis() - spacetime >  timerLength[playState]) {
Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

deved


septillion

Also note, you will ever execute 'playState' == 0 because you do the increment at the start.
Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

Nikosant03

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?

septillion

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

Code: [Select]
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
Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

Nikosant03

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

https://www.baldengineer.com/arduino-how-do-you-reset-millis.html

Go Up