LED Sign blinking, chaseing, BEETLEJUICE

I am making a Beetlejuice prop for Halloween and after 20 hours of research and going nuts I decided to ask for help.
I need 11 lights of the "arrow" to chase each other. Then the outside of this sign will have LEDS wired in sets of 3 so they can chase on their own without interferring from the 11 chasing leds. I have figured out how to use Arrays to get the 11 to chase. I have figured out how to get all 3 outside LEDS to come and off on their own time at the same time. I can't get LED 28 to light, then LED 30, then LED 32, repeat (one at a time BTW).
Please help. Attached is a picture of the sign I am making.

int pinArray[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};  // arrow lights
int count = 0;
int timer = 100;

int pinArray1[] = {28, 30, 32};   //outside sign lights
int count1 = 0;
int timer1 = 1500;


int ledState = LOW;  //blink the outside lights variable

unsigned long previousMillis = 0;        // will store last time LED was updated
const long interval = 200;           // interval at which to blink (milliseconds)


void setup(){
  // we make all the declarations at once
  for (count=0;count<11;count++) {
    pinMode(pinArray[count], OUTPUT);
  }
 for (count1=0;count1<3;count1++) {
    pinMode(pinArray1[count1], OUTPUT);
  }
}

void loop() {
 
    
  for (count=0;count<11;count++) {   //chase sequence for arrows works
   digitalWrite(pinArray[count], HIGH);
   delay(timer);
   digitalWrite(pinArray[count], LOW);

  }
 
  //code to make the outside sign lights blink without delay
 unsigned long currentMillis = millis();

  
  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
        }

    // set the LED with the ledState of the variable:
      for (count1=0;count1<3;count1++) {
  digitalWrite(pinArray1[count1], HIGH);
  digitalWrite(pinArray1[count1], LOW);
      }
     } 
     
     }
   delay(timer);

Don't do that! You've locked up your code for a long period doing just one thing.

Think about states. What state am I in now? How long have I been in that state? Is it time to change to another state?

You can have multiple state machines happening independently. This millisecond it's time to change the outer LED's. At some other millisecond the inner LEDs will change. Maybe they both change in the same millisecond but the humans watching won't be able to tell that the second one was 0.001 seconds late to occur.

Yeah I know that delay is not ideal to use. I just can't figure out how to use mills. I have researched and researched and I have not found code of someone's chase that doesn't use delay and only goes in one direction. I have found code that goes left and right but I could not edit it to only go one direction.
Can you toss me a bit of code to get started? :slight_smile:

I just can't figure out how to use mills.

Using millis() for timing. A beginners guide

Don't forget that you can have two (or more) periods being timed inside loop() using millis(). Just remember to use different variables apart from the one for current time.

This should work...

int arrowArray[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};  // arrow lights
int arrowLen = 11;       //the number of lights in the array above
int arrowCount = 0;      //keeps the state of the arrow lights (which LED is currently on)
int arrowInterval = 100; //milliseconds - interval between changes on the arrow section

int outsideArray[] = {28, 30, 32};   //outside sign lights
int outsideLen = 3;       //the number of lights in the array above
int outsideState = LOW;   //blink the outside lights variable
int outsideOnTime = 50;   //milliseconds - time the outside lights are on for the flash
int outsideOffTime = 200; //milliseconds - time the outside lights are OFF for the flash

unsigned long arrowMillis = 0;        
unsigned long outsideMillis = 0;        

void doArrow(unsigned long currentMillis) {
  //animating the arrow is easy - only one output pin is on at one time (you may connect some pins to more than one light)
  if(currentMillis - arrowMillis >= arrowInterval) {
    arrowMillis += arrowInterval; 

    digitalWrite(arrowArray[arrowCount], LOW);  //turn off the light that is currently on
    arrowCount++;                               //advance the counter
    if(arrowCount >= arrowLen) arrowCount = 0;  //if we went off the end, start at the beginning
    digitalWrite(arrowArray[arrowCount], HIGH); //turn on the current light
  }  
}

void outsideAllChange(int LEDState) {
  // set the LED with the ledState of the variable:
  for (int count = 0; count1 < outsideLen; count++) {
    digitalWrite(outsideArray[count], LEDState);
  }
  
}

void doOutside(unsigned long currentMillis) {
  //animating the blink/flash is slightly different, because you may want the on/off times to be different

  if(outsideState == LOW) {
    if(currentMillis - outsideMilllis >= outsideOffTime) {
      outsideMillis += outsideOffTime;
      outsideState = HIGH;
      outsideAllChange(outsideState);
    }
  } else { //outside lights are on
    if(currentMillis - outsideMilllis >= outsideOnTime) {
      outsideMillis += outsideOnTime;
      outsideState = LOW;
      outsideAllChange(outsideState);
    }    
  }
}



void setup() {
  // we make all the declarations at once
  for (int count = 0; count < arrowLen; count++) {
    pinMode(arrowArray[count], OUTPUT);
  }
  for (int count = 0; count < outsideLen; count++) {
    pinMode(outsideArray[count], OUTPUT);
  }
}


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

  doArrow(currentMillis);

  doOutside(currentMillis);

  //since neither of the above functions are "blocking", which means they only take a few nanoseconds or microseconds to run each time
  //then we can do more work here
  //add some more functions!
}

So, what did I do to your code?

  1. ran the auto-format on it to get the braces lined up
  2. changed the names of the two arrays so that there's no "1" in any variable names
  3. changed the loop() function to just call two functions which do the work
  4. identified that "count" was the state variable which remembered which arrow light is currently on
  5. wrote the doArrow() function to just step through the counter once per X milliseconds
  6. identified that the outside lights are always all-on or all-off and a simple function can do both
  7. wrote the doOutside() function to give you independent on and off times

Some tricks:
a. The length of the arrays is really important. You don't want to run off the end if you change the number of lights at some point in the future. Make this a variable. Then you can use it in many places in the code.
b. Instead of writing previousMillis = currentMillis, I add the interval. That way it doesn't slip by one or two milliseconds over a long period.

Future ideas:
i. I seem to remember that the Beetlejuice sign was kind of flickery. You could add random stuttering or stumbling by randomly changing the milliseconds interval after each time it's used.
ii. Add more stuff. The Arduino can do a lot of other things at the same time.
iii. Make the lights fade out instead of just going off. This is a pretty big project as you have to use blink-without-delay to simulate PWM on the non-PWM pins. But the different on and off times shown in this example should give you some idea how to do it.

Is this the sign you are trying to simulate?

vinceherman:
Is this the sign you are trying to simulate?
Beetlejuice on Vimeo

Yes. I have attached a picture (hopefully) of my sign.

MORGANS you are a genius! Thank you so much for taking the time to write all that out! Your code compiled on the second try and worked like a charm! Your notes were fabulous and allowed me to really understand what was going on. I had no idea you could write a loop code like you did. Made that super easy.
I ended up making the lights chase and then added another section that allows a solenoid to blink the lights behind the sign itself. I like your idea of adding fading and flickering. I honestly have a ton of stuff to build and might not have time to add that to the code. I will post of a video once I get this thing all soldered together.

Again, this is a great community. I like to think I am intelligent, but really struggle with coding.

If you want to see some of the stuff I am making there are a ton of pics here

//Timing for all the lights
int arrowInterval = 120; //milliseconds - interval between changes on the arrow section
int outsideInterval = 500; //milliseconds - interval between changes on the arrow section
int signOnTime = 1200;   //milliseconds - time the outside lights are on for the flash
int signOffTime = 500; //milliseconds - time the outside lights are OFF for the flash



int arrowArray[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};  // arrow lights
int arrowLen = 11;       //the number of lights in the array above
int arrowCount = 0;      //keeps the state of the arrow lights (which LED is currently on)

int outsideArray[] = {28, 30, 32};   //outside sign lights
int outsideLen = 3;       //the number of lights in the array above
int outsideCount = 0;      //keeps the state of the arrow lights (which LED is currently on)


int signSwitch = 22;    //main sign light
//int signInterval = 300; //milliseconds - interval between changes on the sign
int signState = LOW;   //blink the outside lights variable




unsigned long arrowMillis = 0;        
unsigned long outsideMillis = 0;        
unsigned long signMillis = 0;



void doArrow(unsigned long currentMillis) {
  //animating the arrow is easy - only one output pin is on at one time (you may connect some pins to more than one light)
  if(currentMillis - arrowMillis >= arrowInterval) {
    arrowMillis += arrowInterval; 

    digitalWrite(arrowArray[arrowCount], LOW);  //turn off the light that is currently on
    arrowCount++;                               //advance the counter
    if(arrowCount >= arrowLen) arrowCount = 0;  //if we went off the end, start at the beginning
    digitalWrite(arrowArray[arrowCount], HIGH); //turn on the current light
  }  
}



void doOutside(unsigned long currentMillis) {
  
  if(currentMillis - outsideMillis >= outsideInterval) {
    outsideMillis += outsideInterval; 

    digitalWrite(outsideArray[outsideCount], LOW);  //turn off the light that is currently on
    outsideCount++;                               //advance the counter
    if(outsideCount >= outsideLen) outsideCount = 0;  //if we went off the end, start at the beginning
    digitalWrite(outsideArray[outsideCount], HIGH); //turn on the current light
  }  
}

void signAllChange(int LEDState) {
  // set the LED with the ledState of the variable:
  for (int count = 0; count < outsideLen; count++) {
    digitalWrite(signSwitch, LEDState);
  }
}
  
 void doSignSwitch(unsigned long currentMillis) {
  //flash the sign lights
  if(signState == LOW) {
    if(currentMillis - signMillis >= signOffTime) {
      signMillis += signOffTime;
      signState = HIGH;
      signAllChange(signState);
    }
  } else { //sign lights are on
    if(currentMillis - signMillis >= signOnTime) {
      signMillis += signOnTime;
      signState = LOW;
      signAllChange(signState);
    }    
}}

void setup() {
  // we make all the declarations at once
  for (int count = 0; count < arrowLen; count++) {
    pinMode(arrowArray[count], OUTPUT);
  }
  for (int count = 0; count < outsideLen; count++) {
    pinMode(outsideArray[count], OUTPUT);
  }
  pinMode(signSwitch, OUTPUT);
}


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

  doArrow(currentMillis);

  doOutside(currentMillis);

  doSignSwitch(currentMillis);

  //since neither of the above functions are "blocking", which means they only take a few nanoseconds or microseconds to run each time
  //then we can do more work here
  //add some more functions!
}

  for (int count = 0; count < outsideLen; count++) {

digitalWrite(signSwitch, LEDState);
  }

It's not necessary to write the same value to signSwitch 3 times over in rapid succession. You only need to do it once.

The reason I spotted this is the name of the variables. You use outsideLen and signSwitch in the same part of the code when those two things aren't related to each other in any way.

So I was able to get it all up and running. It worked great once I used the code. I did have to use three transistors and a solenoid in the project as the Arduino was not putting out enough power to make everything function.

You sure do take Halloween seriously. Looks great though, well done.