Blinking 3 LEDs In Sequence

Hello,

I'm working on an "arcade game" for a school project, and have run into an issue I am unable to find an answer for. The project consists of 3 rows of 3 LEDs each, which blink in different ways as the game is played. In the middle row(pins 5, 6, and 7) I want the LEDs to blink one at a time, so that when one turns off, the next turns on. I have based my code on the "using millis() for timing" code found here.

The problem I am running into is that red LEDs 2 and 3 (pins 6 and 7) are blinking at the same time. I tried to get this sequence to work by making separate variables for the timing of each of the 3 red LEDs, then adding time onto the start time for red 2 and 3. It seemed to have worked as LED red 2 blinks after LED red 1, but as I said LED red 3 is blinking at the same time as red 2, not after it.

I'm very new to this so I'm not sure where the problem lies. Also, I know it isn't a wiring issue, as eliminating the time added to red 2 causes red 1 and 2 to blink at the same time, while red 3 blinks after them.

Here is the full version of my code:

int switchState = 0;
unsigned long startMillisR1; //start time red 1
unsigned long startMillisR2; //start time red 2
unsigned long startMillisR3; //start time red 3
unsigned long startMillisY; //start time yellow
unsigned long currentMillisR1; //current time red 1
unsigned long currentMillisR2; //current time red 2
unsigned long currentMillisR3; //current time red 3
unsigned long currentMillisY; //current time yellow
const unsigned long periodR = 250; //delay red
const unsigned long periodY = 1000; //delay yellow

void setup(){
  pinMode(0, OUTPUT); //setting each pin to in or out
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(12, INPUT);
  startMillisR1 = millis();  //initial start time red 1
  startMillisR2 = millis() + 50;  //initial start time red 2
  startMillisR3 = millis() + 100;  //initial start time red 3
  startMillisY = millis();  //initial start time yellow
  
}

void loop(){
  switchState = digitalRead(12);
  currentMillisR1 = millis();  //get the current "time" red 1
  currentMillisR2 = millis();  //get the current "time" red 2
  currentMillisR3 = millis();  //get the current "time" red 3
  currentMillisY = millis();  //get the current "time" yellow

  
  if (switchState == LOW){  //cycle red lights

   if (currentMillisR1 - startMillisR1 >= periodR){  //if delay period is reached
    digitalWrite(5, !digitalRead(5));  //change state of led red
    startMillisR1 = currentMillisR1;  //reset timer red 1
    }
   if (currentMillisR2 - startMillisR2 >= periodR){  //if delay period is reached
    digitalWrite(6, !digitalRead(6));  //change state of led red
    startMillisR2 = currentMillisR2;  //reset timer red 2
    }
   if (currentMillisR3 - startMillisR3 >= periodR){  //if delay period is reached
    digitalWrite(7, !digitalRead(7));  //change state of led red
    startMillisR3 = currentMillisR3;  //reset timer red 3
    }
  }
  
  if (switchState == LOW){  //cycle yellow lights

    if (currentMillisY - startMillisY >= periodY){  //if delay period is reached
    digitalWrite(8, !digitalRead(8));  //change state of led yellow
    startMillisY = currentMillisY;  //reset timer
    }
  }

  
  if (switchState == HIGH && digitalRead(5) == HIGH && digitalRead(8) == HIGH){  //check to see if hit connects
    
    digitalWrite(2, HIGH);  //hit indicator
    delay(50);
    digitalWrite(2, LOW);
    delay(50);
    digitalWrite(2, HIGH);
    delay(50);
    digitalWrite(2, LOW);
    delay(50);
    digitalWrite(2, HIGH);
    delay(50);
    digitalWrite(2, LOW);
    
  }
}

And here is the trimmed down version with only the lines concerning the three red LEDs:

int switchState = 0;
unsigned long startMillisR1; //start time red 1
unsigned long startMillisR2; //start time red 2
unsigned long startMillisR3; //start time red 3
unsigned long currentMillisR1; //current time red 1
unsigned long currentMillisR2; //current time red 2
unsigned long currentMillisR3; //current time red 3
const unsigned long periodR = 250; //delay red

void setup(){
  //setting each pin to in or out
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(12, INPUT);
  startMillisR1 = millis();  //initial start time red 1
  startMillisR2 = millis() + 50;  //initial start time red 2
  startMillisR3 = millis() + 100;  //initial start time red 3
}

void loop(){
  switchState = digitalRead(12);
  currentMillisR1 = millis();  //get the current "time" red 1
  currentMillisR2 = millis();  //get the current "time" red 2
  currentMillisR3 = millis();  //get the current "time" red 3

  
  if (switchState == LOW){  //cycle red lights

   if (currentMillisR1 - startMillisR1 >= periodR){  //if delay period is reached
    digitalWrite(5, !digitalRead(5));  //change state of led red
    startMillisR1 = currentMillisR1;  //reset timer red 1
    }
   if (currentMillisR2 - startMillisR2 >= periodR){  //if delay period is reached
    digitalWrite(6, !digitalRead(6));  //change state of led red
    startMillisR2 = currentMillisR2;  //reset timer red 2
    }
   if (currentMillisR3 - startMillisR3 >= periodR){  //if delay period is reached
    digitalWrite(7, !digitalRead(7));  //change state of led red
    startMillisR3 = currentMillisR3;  //reset timer red 3
    }
  }
}

Any help is appreciated!

Let's say millis() starts at 0:

  startMillisR1 = millis();  // red 1 starts now.
  startMillisR2 = millis() + 50;  // red 2 starts at 50, 50 milliseconds in the future
  startMillisR3 = millis() + 100;  // red 3 starts at 100, 100 milliseconds in the future

The first time you do the calculations you are subtracting some time in the future from the current time:

   if (0 - 0 >= periodR){  // No problem. 0 < 250
    digitalWrite(5, !digitalRead(5));  //change state of led red
    startMillisR1 = currentMillisR1;  //reset timer red 1
    }
   if (0 - 50 >= periodR){  // PROBLEM: unsigned 0 minus unsigned 50 is unsigned 4294967246
    digitalWrite(6, !digitalRead(6));  //change state of led red
    startMillisR2 = currentMillisR2;  //reset timer red 2
    }
   if (0 - 100 >= periodR){  // SAME PROBLEM
    digitalWrite(7, !digitalRead(7));  //change state of led red
    startMillisR3 = currentMillisR3;  //reset timer red 3
    }

After those calculations are done, the Red2 and Red3 LEDs have been toggled and all of the intervals have re-started.

You could put a delay(250); at the end of setup so the 'future' times will be 'past' times but everything will trigger and all three will sync. One way to prevent them from syncing is to put in the delay(250); and use "startMillisR3 += periodR;" instead of "startMillisR3 = currentMillisR3;" That will move the start time forward only one period instead of syncing them. At least I think that will work.

Note: You only need one copy of currentMillis for all calculations.

Thank you! I will try this and report back.

I was able to get it working! Thanks for the help!

The delay in setup worked, but the LEDs "lagged" a bit so there were two or 3 lit at a time instead of just one. Using "startMillisR3 += periodR;" actually caused all 3 to sync up. I was able to solve the lag by adding a command to turn the previous light off when each was turned on. Here is my updated code:

int switchState = 0;
unsigned long startMillisR1; //start time red 1
unsigned long startMillisR2; //start time red 2
unsigned long startMillisR3; //start time red 3
unsigned long startMillisY; //start time yellow
unsigned long currentMillisR1; //current time red 1
unsigned long currentMillisR2; //current time red 2
unsigned long currentMillisR3; //current time red 3
unsigned long currentMillisY; //current time yellow
const unsigned long periodR = 750; //delay red
const unsigned long periodY = 1000; //delay yellow

void setup(){
  pinMode(0, OUTPUT); //setting each pin to in or out
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(12, INPUT);
  startMillisR1 = millis();  //initial start time red 1
  startMillisR2 = millis() + 250;  //initial start time red 2
  startMillisR3 = millis() + 500;  //initial start time red 3
  startMillisY = millis();  //initial start time yellow
  delay(750);
  
}

void loop(){
  switchState = digitalRead(12);
  currentMillisR1 = millis();  //get the current "time" red 1
  currentMillisR2 = millis();  //get the current "time" red 2
  currentMillisR3 = millis();  //get the current "time" red 3
  currentMillisY = millis();  //get the current "time" yellow

  
  if (switchState == LOW){  //cycle red lights

   if (currentMillisR1 - startMillisR1 >= periodR){  //if delay period is reached
    digitalWrite(5, HIGH);  // led red 1 on
    digitalWrite(7, LOW);  // led red 3 off
    startMillisR1 = currentMillisR1;  //reset timer red 1
    }

    
   if (currentMillisR2 - startMillisR2 >= periodR){  //if delay period is reached
    digitalWrite(6, HIGH);  //led red 2 on
    digitalWrite(5, LOW);  // red 1 off
    startMillisR2 = currentMillisR2;  //reset timer red 2
    }

    
   if (currentMillisR3 - startMillisR3 >= periodR){  //if delay period is reached
    digitalWrite(7, HIGH);  // led red 3 on
    digitalWrite(6, LOW);  // led red 2 off
    startMillisR3 = currentMillisR3;  //reset timer red 3
    }

 }
  
  if (switchState == LOW){  //cycle yellow lights

    if (currentMillisY - startMillisY >= periodY){  //if delay period is reached
    digitalWrite(8, !digitalRead(8));  //change state of led yellow
    startMillisY = currentMillisY;  //reset timer
    }
  }

  
  if (switchState == HIGH && digitalRead(5) == HIGH && digitalRead(8) == HIGH){  //check to see if hit connects
    
    digitalWrite(2, HIGH);  //hit indicator
    delay(50);
    digitalWrite(2, LOW);
    delay(50);
    digitalWrite(2, HIGH);
    delay(50);
    digitalWrite(2, LOW);
    delay(50);
    digitalWrite(2, HIGH);
    delay(50);
    digitalWrite(2, LOW);
    
  }
}