LED Chasing Sequence.

I have this simple function for an led chasing sequence. I want to simplify the code and condense it into less lines. Basically the same piece of code is being repeated 8 times, one time for each led. The only difference is the variable name for the led. I want to know if there is a way to make this into a for loop, and each time the loop runs, the number after (ledPin (), HIGH) can go up by one. Basically I want to add a number beside "ledPin" each time the loop runs. Any thoughts on how to do this? Is it even possible to add things to a variable when using it?

void LEDstartupsequences(){

  digitalWrite(ledPin1, HIGH);
    delay(100);
    digitalWrite (ledPin1, LOW);
    
    digitalWrite(ledPin2, HIGH);
    delay(100);
    digitalWrite (ledPin2, LOW);
    
  
    digitalWrite(ledPin3, HIGH);
    delay(100);
    digitalWrite (ledPin3, LOW);
    delay(10);
  
  digitalWrite(ledPin4, HIGH);
    delay(100);
    digitalWrite (ledPin4, LOW);
    
  
    digitalWrite(ledPin5, HIGH);
    delay(100);
    digitalWrite (ledPin5, LOW);
    
  
    digitalWrite(ledPin6, HIGH);
    delay(100);
    digitalWrite (ledPin6, LOW);
    
 
    digitalWrite(ledPin7, HIGH);
    delay(100);
    digitalWrite (ledPin7, LOW);
    
    
    digitalWrite(ledPin8, HIGH);
    delay(100);
    digitalWrite (ledPin8, LOW);
  
}

The ledPin variable as an array would allow you to use a for loop to iterate through all the pins in a more compact manner.

You need to look up how arrays work. The number is added in square brackets after the variable name and it could be a variable itself.

Thanks for the advice. For anyone else who is trying to do this, I suggest watching this video that I found on arrays. It's really helpful. Arduino Workshop - Chapter 4 - Using Arrays - YouTube

This new for loop runs the chasing sequence once, but I want it to continue looping. The for loop is already inside the void loop so I thought it would keep looping but it doesn't. I tried putting the for loop inside a while True loop but that didn't work either. Any advice on how to fix this?

int ledList[] = {2,3,5,7,8,9,A1,A2};

void loop(){

for (int z; z <= 8; z++){
    digitalWrite(ledList[z], HIGH);
    delay(100);
    digitalWrite(ledList[z], LOW);
  }

}
1 Like

You are not initializing the z variable in the loop. Also bear in mind that array subscripts are zero based so eight elements are numbered 0 to 7. It would be normal practice to use a < 8 condition to stop the loop.

I initialized z = 0 and changed the second argument to < 8 and it worked perfectly. Thanks for the help.
How does this work though? By initializing z = 0, doesn't that mean that each time the loop runs it sets z back to zero? So how does it get to loop through 8 times if z is constantly set back to zero?

Also I want to do this sequence but in reverse. I want the for loop to start from 7 - 0 rather than from 0-7. Is this possible?

It is easier to understand if you think that the for loop just gets translated into something like this

z = 0;  // start condition
while (z < 8)  // end condition
{
  //do stuff
  z++;  // increment statement
}

You actually want the loop to reset back to zero every time it STARTS to run otherwise it won't repeat. By not initialising the value you get whatever is on the stack. As it happens the first time through you will get 0 but from then on it will be whatever is left on the stack from previous operations. If this is >= 8 (likely as the small program is probably going to reuse the same stack address) the loop end before it runs the first iteration (see above).

To run the loop in reverse you can change the start, end conditions and the increment (hint: decrement) for the loop. It is actually covered in the video you mentioned above.

Thanks for all the help. I got it working.

I got it working but I'm having some trouble integrating it with the rest of my code. Basically I want to run the led sequence simultaneously with another loop. I know this isn't possible but read that its possible to write the code in a way that it mimics 2 loops running at the same time. Is this possible for my situation?

I want to run the led sequence while the lcd is printing. Currently, the led sequence runs first, then the while loop runs, and then the led sequence runs again.

void LEDstartupsequences(){

   
  for (int z = 0; z < 8; z++){
    
    digitalWrite(ledList[z], HIGH);
    delay(100);
    digitalWrite(ledList[z], LOW);
    
  }

 
  for (int z = 8; z > -1; z--){
    
    digitalWrite(ledList[z], HIGH);
    delay(100);
    digitalWrite(ledList[z], LOW);
    
  }

}



LEDstartupsequences();


int buttonValue = digitalRead(redbutton);


while(buttonValue == HIGH){


lcd.print("Which mode would you");
lcd.setCursor(0,1);
lcd.print("   like to play?");
delay(4000);

lcd.clear();

lcd.print("    Press red for");
lcd.setCursor(0,1);
lcd.print("    singleplayer");
lcd.setCursor(0,2);
lcd.print("    and blue for");
lcd.setCursor(0,3);
lcd.print("      2-player");
delay(3000);
lcd.clear();
}

You have to get rid of the delays.

Take a look at the blink without delay example.

The delays in the lcd printing right?

You need to get rid of ALL the delays. While you are delaying in between turning on and off the LED the processor is doing nothing. 100ms * 8 times means that it will be completely tied up doing nothing for 800ms at a time, which makes it unresponsive.

What you need to do is turn this into a Finite State Machine so that it becomes non-blocking and other things can run while the LED flashing goes on. This blog article may help you understand what you need to do: Finite State Machine Programming Basics – Part 1 – Arduino++ and Finite State Machine Programming Basics – Part 2 – Arduino++.

Without delay()..

I'd do it something like this.

#include <idlers.h>
#include <lists.h>
#include <timeObj.h>


// **************************************
//            CHASE CLASS
// **************************************


int ledList[] = {2,3,5,7,8,9,A1,A2};

// The deivation of the class.
class chaseBlinker :  public idler {
   
   public:
                  chaseBlinker(void);
         virtual  ~chaseBlinker(void);

                  void  begin(float timeOnMs = 100);
         virtual  void  idle(void); 

                  int      index;
                  bool     beenSetup;
                  timeObj  onTimer;
};

// Constructor. Not much to do here.
chaseBlinker::chaseBlinker(void) { beenSetup = false;  }


// Destructor, also not much to do.
chaseBlinker::~chaseBlinker(void) {  }


// Initialzer to be called in your setup() funtion.
// You can set the times differently here as well.
void chaseBlinker::begin(float timeOnMs) {

   hookup();
   if (!beenSetup) {
      for (int i=0;i<8;i++) {
         pinMode(ledList[i], OUTPUT);
      }
      beenSetup = true;
   }
   onTimer.setTime(timeOnMs);
   index = 0;
}


// Idle is where you check the timer to see if its time to do somwthing.
// If so, we do that something (swap LEDS) and reset the timer.
void  chaseBlinker::idle(void) {

   if (onTimer.ding()) {                  // If our timer has expired..
      digitalWrite(ledList[index], LOW);  // Turn off the current LED.
      index++;                            // Increment the counter to the next LED.
      if (index>=8) {                     // If we overshot..
         index = 0;                       // We reset to zero.
      }
      digitalWrite(ledList[index], HIGH); // Counter has been incremented, turn on the next LED.
      onTimer.start();                    // Restart the timer for this LED.
   }
}



// **************************************
//         PROGRAM STARTS HERE
// **************************************

chaseBlinker   ourChaser;

void setup(void) {

   ourChaser.begin();
}


void loop(void) {

   idle();
   // Do your stuff, DON"T call delay.
}

That should give you your line of blinkers running in the background. If it works, just add the LCD code to it. NO calls to delay() though!

You'll need the LC_baseTools library installed do compile this.

-jim lee

Wow thanks so much Jim that's awesome! I tested it by printing to the Serial monitor and the led sequence runs at the same time. Just a question, if I don't use any delays when printing to the lcd, won't it just print really quickly to the point where you can't read the text? Also on my original code I had a second for loop that runs the chasing sequence from the 8th led back to 1st. How can I integrate that sequence into your code?

Actually..

If you are using the new version of LC_baseTools (that would be 1.1.1) There is a sleep() call that you can use in your main loop(). sleep(ms) stops your loop() code, just like delay() did. Except, it keeps everything else running. including your LEDs. Try that.

As for running them back and forth this is the bit of the code that controls that..

void  chaseBlinker::idle(void) {

   if (onTimer.ding()) {                  // If our timer has expired..
      digitalWrite(ledList[index], LOW);  // Turn off the current LED.
      index++;                            // Increment the counter to the next LED.
      if (index>=8) {                     // If we overshot..
         index = 0;                       // We reset to zero.
      }
      digitalWrite(ledList[index], HIGH); // Counter has been incremented, turn on the next LED.
      onTimer.start();                    // Restart the timer for this LED.
   }
}

Every time the timer expires..

I shut off the light that's on,
bump up the array index.
check the index, If >= 8? Then rest it to 0.
Lastly, turn on that light.

No loops.

To go back and forth? I would.. Instead of just bumping up index blindly. I'd add a value to it. step

index = index + step; (step would be started at 1)

When you hit 7. Set step = -1.

Then it'll start counting down

When you hit 0. Set step = 1.

How do you add a variable like step to this?

Easy, this part here..

class chaseBlinker :  public idler {
   
   public:
                  chaseBlinker(void);
         virtual  ~chaseBlinker(void);

                  void  begin(float timeOnMs = 100);
         virtual  void  idle(void); 

                  int      index;
                  bool     beenSetup;
                  timeObj  onTimer;
};

See index and beenSetup? These are the classes varibles. Just add int step; to this list and you have it to play with..

In the last line of begin(), you set index = 0; Add the line : step = 1;

Good luck!

-jim lee

It says I have the latest version of the library which is 1.0.7. When I added the sleep() to my code, it said that I was unable to compile for arduino nano. Is not having 1.1.1 a possible reason for this happening?

Can you please elaborate on adding the new variables. Where do I add stepindex = index + step; ? Do I change index>=8 into stepindex>=8 or do I create a new if statement. Sorry these concepts are more complex than what I'm used to.

Ok, first of all, there is no such animal as LC_baseTools 1.0.7. Go back to your library manager. Under the tools menu and do a search on LC_baseTools exactly that. There should be a choice of 1.0.0 and 1.1.1 Those are the only two that have ever been released. You want the 1.1.1 version. That will give you the sleep() call you're looking for.

Lets get this straightened out before dealing with any LED changes.

-jim lee

Oh yeah never mind I have the 1.1.1 version of LC_baseTools. I was looking at liquid crystal for 1.0.7

So.. were you able to compile it with the sleep() function?

-jim lee

No I wasn't able to write the code properly. Can you give me an example of how to add the sleep function to the main loop? I didn't understand the ones that I saw on the lc base tools documentation.

Start with what I gave you..

Add your display stuff to your main loop() using delay() as you wanted to. (Notice when you hit the delay(), the LEDs stop).

Now, just replace your delay() calls with sleep() calls. Easy peasy.

Example: delay(1000); ends up being -> sleep(1000);

-jim lee