How do I blink multiple LEDs in a sequence using millis?

Hi! I'm a beginner in arduino and I'm having trouble lighting up or blinking LED's in a sequence using millis(). I have 8 LEDs and I want it to light up or blink 2 LEDs at a time starting from the 2 left most LEDs to the 2 rightmost LEDs. It's kind of like the first 2 LEDs will light up and then the next second, the next 2 LEDs will light up while the previous 2 LEDs will turn off so on and so forth. The sketch I've coded lights up 2 LEDs at a time until all 8 LEDs light up. How do I make it like it's running from left to right 2 LEDs lighting up at a time?

int ledPin9 = 9;
int ledPin8 = 8;
int ledPin7 = 7;
int ledPin6 = 6;
int ledPin5 = 5;
int ledPin4 = 4;
int ledPin3 = 3;
int ledPin2 = 2;

unsigned long interval_4 = 4000;
unsigned long interval_3 = 3000;
unsigned long interval_2 = 2000;
unsigned long interval_1 = 1000;
unsigned long previousTime_1 = 0;
unsigned long previousTime_2 = 0;
unsigned long previousTime_3 = 0;
unsigned long previousTime_4 = 0;

void setup()
{
pinMode(ledPin9, OUTPUT);
pinMode(ledPin8, OUTPUT);
pinMode(ledPin7, OUTPUT);
pinMode(ledPin6, OUTPUT);
pinMode(ledPin5, OUTPUT);
pinMode(ledPin4, OUTPUT);
pinMode(ledPin3, OUTPUT);
pinMode(ledPin2, OUTPUT);
}

void loop(){

unsigned long currentMillis = millis();

if (currentMillis - previousTime_1 >= interval_1){
digitalWrite(ledPin9, HIGH);
digitalWrite(ledPin8, HIGH);
previousTime_1 = currentMillis;
}
if (currentMillis - previousTime_2 >= interval_2){

	digitalWrite(ledPin7, HIGH);
	digitalWrite(ledPin6, HIGH);
previousTime_2 = currentMillis;

}

if (currentMillis - previousTime_3 >= interval_3){


    digitalWrite(ledPin5, HIGH);
	digitalWrite(ledPin4, HIGH);
  previousTime_3 = currentMillis;
}
 
if (currentMillis - previousTime_4 >= interval_4){
  	
    digitalWrite(ledPin2, HIGH);
	digitalWrite(ledPin3, HIGH);
   previousTime_4 = currentMillis;
}

}

Rather than have multiple millis() time checks, have one state variable and based on the value, do whatever step is needed (step 1 = light first 2, step 2 = light 2nd two, turn off first 2, etc.) When your state variable reaches the end, set it back to zero.

You can also make your code mush simpler if you study/learn how to use arrays rather than a whole series of ledPinX variables. Then, you can calculate the index into the array based on your state

const int ledPin[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
const int numPins = sizeof(ledPin) / sizeof(ledPin[0]);
const int numStates = numPins / 2;

const unsigned long interval = 1000;
unsigned long previousTime;
int state;

void setup()
{
  for ( int i = 0; i < numPins; ++i ) {
    pinMode(ledPin[i], OUTPUT);
    digitalWrite(ledPin[i], LOW );
  }
  digitalWrite(ledPin[0], HIGH );
  digitalWrite(ledPin[1], HIGH );
}

void loop() {

  unsigned long currentMillis = millis();

  if (currentMillis - previousTime >= interval) {
    previousTime = currentMillis;
    digitalWrite(ledPin[state*2], LOW);
    digitalWrite(ledPin[state*2+1], LOW);
    state++;
    if ( state >= numStates ) {
      state = 0;
    }
    digitalWrite(ledPin[state*2], HIGH);
    digitalWrite(ledPin[state*2+1], HIGH);
  }
}
3 Likes

You never write a LOW to the pin after writing a HIGH to it.

1 Like

How to write Timers and Delays in Arduino covers millis and timers,
But as noted by @blh64 you probably only need one timer and a variable to change leds.
If you want variable led on times see the Led Sequence example in the above link.

1 Like

The sketch by @blh64 in Wokwi simulation:

Now everyone can see what it does :smiley:
It is possible to make a step of just one led, or bounce to the led and right. The sketch is a good starting point.

1 Like

Hello
I did it again. I have modified your sketch by adding two arrays containing the LED sequences and the number of the LED pin.

int ledPin9 = 9;
int ledPin8 = 8;
int ledPin7 = 7;
int ledPin6 = 6;
int ledPin5 = 5;
int ledPin4 = 4;
int ledPin3 = 3;
int ledPin2 = 2;
/// new 
byte ledSequ [][8] {
  {1, 1, 0, 0, 0, 0, 0, 0},
  {0, 1, 1, 0, 0, 0, 0, 0},
  {0, 0, 1, 1, 0, 0, 0, 0},
  {0, 0, 0, 1, 1, 0, 0, 0},
  {0, 0, 0, 0, 1, 1, 0, 0},
  {0, 0, 0, 0, 0, 1, 1, 0},
  {0, 0, 0, 0, 0, 0, 1, 1},
};
// new 
byte leds[] {ledPin2, ledPin3, ledPin4, ledPin5, ledPin6, ledPin7, ledPin8, ledPin9};
void setup()
{
  Serial.begin(9600);
  pinMode(ledPin9, OUTPUT);
  pinMode(ledPin8, OUTPUT);
  pinMode(ledPin7, OUTPUT);
  pinMode(ledPin6, OUTPUT);
  pinMode(ledPin5, OUTPUT);
  pinMode(ledPin4, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}
void loop() {
  const unsigned long blink = 1000;
  static unsigned long blinkMillis;
  if (millis() - blinkMillis >= blink ) {
    static int nummer;
    blinkMillis = millis();
    Serial.println("blink");
    for (unsigned int n=0; n<sizeof(leds); n++) digitalWrite(leds[n],ledSequ[nummer][n]);
    nummer++;
    nummer = nummer % (sizeof(ledSequ)/sizeof(leds)); 
  }
}

Try it and have a nice weekend

1 Like

@paulpaulson, you can do better than that.

const byte ledSequ[][8] = {
  {1, 1, 0, 0, 0, 0, 0, 0},
  {0, 1, 1, 0, 0, 0, 0, 0},
  {0, 0, 1, 1, 0, 0, 0, 0},
  {0, 0, 0, 1, 1, 0, 0, 0},
  {0, 0, 0, 0, 1, 1, 0, 0},
  {0, 0, 0, 0, 0, 1, 1, 0},
  {0, 0, 0, 0, 0, 0, 1, 1},
  {0, 0, 0, 0, 0, 1, 1, 0},
  {0, 0, 0, 0, 1, 1, 0, 0},
  {0, 0, 0, 1, 1, 0, 0, 0},
  {0, 0, 1, 1, 0, 0, 0, 0},
  {0, 1, 1, 0, 0, 0, 0, 0},
};

const byte leds[] = {2, 3, 4, 5, 6, 7, 8, 9};

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

  for( auto a:leds)
    pinMode(a, OUTPUT);
}

void loop() {
  const unsigned long interval = 150;
  static unsigned long blinkMillis;
  if (millis() - blinkMillis >= interval) {
    static int index;
    blinkMillis = millis();
    for (unsigned int n=0; n<sizeof(leds); n++) 
      digitalWrite(leds[n], ledSequ[index][n]);
    index++;
    index = index % (sizeof(ledSequ)/sizeof(leds)); 
  }
}
1 Like

Thank you very much. I'll try to learn arrays as I can see that it makes the sketch more neat. I'm having trouble understanding the "state". I'm very much new to Arduino and I really want to learn about it. Thank you very much.

Thank you very much. I'll look into the link as you said. I appreciate it.

Thank you. Is this the same thing as tinkercad?

Thank you very much. I'll definitely try it out.

Thank you very much. I'm very new to arduino. Any advise and help will be appreciated. I'll probably have more questions regarding this in the future, so thank you in advance.

@paolo_gie, I hope you don't mind that we get a little carried away. The best way is what you understand and suits you best.

I wanted to see for myself if it would be possible to have one led bouncing to left and right and another led following. The "follower" would be the second led.

This is how it turned out:

// Let a led bounce from left to right.
// Let another led follow in its footsteps

const byte leds[] = { 2, 3, 4, 5, 6, 7, 8, 9};

unsigned long previousMillis;
const unsigned long interval = 150;
int index = 0;
int direction = 1;       // +1 or -1
int previousIndex = 0;

void setup() 
{
  for( auto a:leds)
    pinMode(a, OUTPUT);
}

void loop() 
{
  unsigned long currentMillis = millis();

  if( currentMillis - previousMillis >= interval) 
  {
    previousMillis = currentMillis;

    // There are three indexes:
    //   The new index for the led that should turn on.
    //   the current index, for the follower led, do nothing with it.
    //   the previous index, that led should be turned off.

    int newIndex = index + direction;

    // Creating the bouncing at the right and the left with the index
    if( newIndex < 0)
    {
      newIndex = 0;
      direction = 1;
    }
    else if( newIndex >= (int) sizeof( leds))
    {
      newIndex = sizeof( leds) -1;
      direction = -1;
    }

    // Turn on the new led
    digitalWrite( leds[newIndex], HIGH);

    // Turn off the previous led, but only if it is not used
    if( previousIndex != newIndex and previousIndex != index)
    {
      digitalWrite( leds[previousIndex], LOW);
    }

    // Set the variables for the next time.
    previousIndex = index;
    index = newIndex;
  }
}

You can see it in Wokwi:

Wokwi is a online simulation for Arduino, and so is Tinkercad. I have compared them here: Virtual Online Arduino Simulator - Wokwi Arduino Simulator - #3 by Koepel

The state in [state*2] and [state*2+1] is to solve a mathematical problem. It calculates the index for the first and the second led. You can put that calculation on a separate line with a extra variable to better understand it. Maybe you want the led pattern to be slightly different, then you need other code to calculate the index of the leds.

1 Like

Yes, I can :v:

1 Like