Dancing Christmas Light Project (SOLVED)

Hello all. I have a question that I need a bit of help with. My best friend and I (also an Arduino user) are planning a design for his Christmas lights. The idea is, we are going to build a box, in which we have 120v coming into four outlets, each of which will be controlled by a different relay on a Solid State Relay. The relays will be switched via an Arduino program. We are working on different sections of the code, but mine has to be made first as the basis for the program. I am writing the portion we are using as default, wherein all four channels are on, as well as the non-musical program. The non-musical program, I am trying to get to have different patterns of lights, flashing based on a counter. When the counter reaches x, it is supposed to change patterns, and do this for each pattern until the end of the string, at which time, the count is supposed to reset and the pattern begins again. Ive set the three patterns Ive written into functions, and I am using a flashCount variable, but instead of working like I want, the pattern is acting almost random. here is the code I wrote:

int ledPin1 = 2;
int ledPin2 = 3;
int ledPin3 = 4;
int ledPin4 = 5;
int buttonPin = 8;
int buttonState = 1;
int prevButtonState = 0;
int pushButtonCount = 0;
const unsigned long ledInterval = 650;
unsigned long ledTimer = 0;
int led1State = digitalRead(ledPin1);
int led2State = digitalRead(ledPin2);
int led3State = digitalRead(ledPin3);
int led4State = digitalRead(ledPin4);
int flashCount = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode (ledPin1, OUTPUT);
  pinMode (ledPin2, OUTPUT);
  pinMode (ledPin3, OUTPUT);
  pinMode (ledPin4, OUTPUT);
  pinMode (buttonPin, INPUT);
  ledTimer = millis();
}

void loop() {
  // put your main code here, to run repeatedly:

      buttonState = digitalRead(buttonPin);
  
  if (buttonState != prevButtonState){
    if (buttonState == HIGH){
      pushButtonCount ++;
    }
    delay (50);
  }
    prevButtonState = buttonState;
    if (pushButtonCount > 2){
      pushButtonCount = 1;
    }

  switch (pushButtonCount) {
    default:
      digitalWrite(ledPin1, HIGH);
      digitalWrite(ledPin2, HIGH);
      digitalWrite(ledPin3, HIGH);
      digitalWrite(ledPin4, HIGH);
      break;
    case 2:


    flash1();
    flashCount ++;
    
    if (flashCount >= 10)
    {
      flash2();
      flashCount ++;
    }
    if (flashCount >=20)
    {
      flash3();
      flashCount ++;
    }
    if (flashCount == 30)
    {
      flashCount = 0;
    }

      break;
  }
}

void flash1(){
        if ( (millis () - ledTimer) >= ledInterval ) {
         if (led1State == LOW){
     led1State = HIGH;
     led2State = LOW;
     led3State = HIGH;
     led4State = LOW;
      }
         else{ 
     led1State = LOW;
     led2State = HIGH;
     led3State = LOW;
     led4State = HIGH;
         }
   digitalWrite (ledPin1, led1State );
   digitalWrite (ledPin2, led2State);
   digitalWrite (ledPin3, led3State);
   digitalWrite (ledPin4, led4State);
   ledTimer = millis ();
    }
}

void flash2(){
        if ( (millis () - ledTimer) >= ledInterval ) {
         if (led1State == LOW){
     led1State = HIGH;
     led2State = HIGH;
     led3State = LOW;
     led4State = LOW;
      }
         else{ 
     led1State = LOW;
     led2State = LOW;
     led3State = HIGH;
     led4State = HIGH;
         }
   digitalWrite (ledPin1, led1State );
   digitalWrite (ledPin2, led2State);
   digitalWrite (ledPin3, led3State);
   digitalWrite (ledPin4, led4State);
   ledTimer = millis ();
    }
}
    void flash3(){
              if ( (millis () - ledTimer) >= ledInterval ) {
         if (led1State == LOW){
     led1State = HIGH;
     led2State = LOW;
     led3State = LOW;
     led4State = HIGH;
      }
         else{ 
     led1State = HIGH;
     led2State = LOW;
     led3State = LOW;
     led4State = HIGH;
         }
   digitalWrite (ledPin1, led1State );
   digitalWrite (ledPin2, led2State);
   digitalWrite (ledPin3, led3State);
   digitalWrite (ledPin4, led4State);
   ledTimer = millis ();
    }
    
}

Any advice, thoughts, or tips will be much appreciated! Thank you for your time.

Oh, and I should mention, it is set up so that a single button press changes from default to dancing light mode. Which works, but when you start tinkering with things like if/else and while, for some reason it stops working as it should. It doesnt reset the count. I'm 8 hours into writing this.... Ive done a lot of rewriting... :(

You should mention what exactly works properly, and where it goes wrong...and by random led pattern, do you mean flash functions are called randomly or its overall random..

And why

const unsigned long ledInterval = 650;


if ( (millis () - ledTimer) >= ledInterval )

I didnt understand this

Me either, honestly. I was using a copied version of millis code to use until I could understand it. However, I just figured out how to make it work. I had to insert flashCount into my functions rather than my switch case argument. Here is the final version, if anyone wishes to use it:

int ledPin1 = 2;
int ledPin2 = 3;
int ledPin3 = 4;
int ledPin4 = 5;
int buttonPin = 8;
int buttonState = 1;
int prevButtonState = 0;
int pushButtonCount = 0;
const unsigned long ledInterval = 350;
unsigned long ledTimer = 0;
int led1State = digitalRead(ledPin1);
int led2State = digitalRead(ledPin2);
int led3State = digitalRead(ledPin3);
int led4State = digitalRead(ledPin4);
int flashCount = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode (ledPin1, OUTPUT);
  pinMode (ledPin2, OUTPUT);
  pinMode (ledPin3, OUTPUT);
  pinMode (ledPin4, OUTPUT);
  pinMode (buttonPin, INPUT);
  ledTimer = millis();
}

void loop() {
  // put your main code here, to run repeatedly:

      buttonState = digitalRead(buttonPin);
  
  if (buttonState != prevButtonState){
    if (buttonState == HIGH){
      pushButtonCount ++;
    }
    delay (50);
  }
    prevButtonState = buttonState;
    if (pushButtonCount > 2){
      pushButtonCount = 1;
      flashCount = 0;
    }

  switch (pushButtonCount) {
    case 1:
      digitalWrite(ledPin1, HIGH);
      digitalWrite(ledPin2, HIGH);
      digitalWrite(ledPin3, HIGH);
      digitalWrite(ledPin4, HIGH);
      //ledTimer = millis();
      break;
    case 2:
if ((flashCount >= 0) && (flashCount < 10))
    {
      flash1();
    }
 
    
    else if ((flashCount >= 10) && (flashCount < 20))
    {
      flash2();
    }
    else if ((flashCount >=20) && (flashCount < 30))
    {
      flash3();
    }
    else if ((flashCount >= 30) && (flashCount < 40))
    {
      flash4();
    }
    else if ((flashCount >= 40) && (flashCount <  50))
    {
      flash5();
    }
    else if ((flashCount >= 50) && (flashCount <60))
    {
      flash6();
    }
    else if (flashCount == 60)
    {
      flashCount = 0;
    }

      break;
  }
}

void flash1(){
        if ( (millis () - ledTimer) >= ledInterval ) {
         if (led1State == LOW){
     led1State = HIGH;
     led2State = LOW;
     led3State = HIGH;
     led4State = LOW;
      }
         else{ 
     led1State = LOW;
     led2State = HIGH;
     led3State = LOW;
     led4State = HIGH;
         }
   digitalWrite (ledPin1, led1State );
   digitalWrite (ledPin2, led2State);
   digitalWrite (ledPin3, led3State);
   digitalWrite (ledPin4, led4State);
   ledTimer = millis ();
   flashCount ++;
    }
}

void flash2(){
        if ( (millis () - ledTimer) >= ledInterval ) {
         if (led1State == LOW){
     led1State = HIGH;
     led2State = HIGH;
     led3State = LOW;
     led4State = LOW;
      }
         else{ 
     led1State = LOW;
     led2State = LOW;
     led3State = HIGH;
     led4State = HIGH;
         }
   digitalWrite (ledPin1, led1State );
   digitalWrite (ledPin2, led2State);
   digitalWrite (ledPin3, led3State);
   digitalWrite (ledPin4, led4State);
   ledTimer = millis ();
   flashCount ++;
    }
}
    void flash3(){
              if ( (millis () - ledTimer) >= ledInterval ) {
         if (led1State == LOW){
     led1State = HIGH;
     led2State = LOW;
     led3State = LOW;
     led4State = HIGH;
      }
         else{ 
     led1State = LOW;
     led2State = HIGH;
     led3State = HIGH;
     led4State = LOW;
         }
   digitalWrite (ledPin1, led1State );
   digitalWrite (ledPin2, led2State);
   digitalWrite (ledPin3, led3State);
   digitalWrite (ledPin4, led4State);
   ledTimer = millis ();
   flashCount ++;
    }
    
}

    void flash4(){
              if ( (millis () - ledTimer) >= ledInterval ) {
         if (led1State == LOW){
     led1State = HIGH;
     led2State = LOW;
     led3State = HIGH;
     led4State = HIGH;
      }
         else{ 
     led1State = LOW;
     led2State = HIGH;
     led3State = LOW;
     led4State = LOW;
         }
   digitalWrite (ledPin1, led1State );
   digitalWrite (ledPin2, led2State);
   digitalWrite (ledPin3, led3State);
   digitalWrite (ledPin4, led4State);
   ledTimer = millis ();
   flashCount ++;
    }
    
}

    void flash5(){
              if ( (millis () - ledTimer) >= ledInterval ) {
         if (led1State == LOW){
     led1State = HIGH;
     led2State = HIGH;
     led3State = LOW;
     led4State = HIGH;
      }
         else{ 
     led1State = LOW;
     led2State = LOW;
     led3State = HIGH;
     led4State = LOW;
         }
   digitalWrite (ledPin1, led1State );
   digitalWrite (ledPin2, led2State);
   digitalWrite (ledPin3, led3State);
   digitalWrite (ledPin4, led4State);
   ledTimer = millis ();
   flashCount ++;
    }
    
}

    void flash6(){
              if ( (millis () - ledTimer) >= ledInterval ) {
         if (led1State == LOW){
     led1State = HIGH;
     led2State = HIGH;
     led3State = HIGH;
     led4State = LOW;
      }
         else{ 
     led1State = LOW;
     led2State = LOW;
     led3State = LOW;
     led4State = HIGH;
         }
   digitalWrite (ledPin1, led1State );
   digitalWrite (ledPin2, led2State);
   digitalWrite (ledPin3, led3State);
   digitalWrite (ledPin4, led4State);
   ledTimer = millis ();
   flashCount ++;
    }
    
}

Alright, add "(SOLVED)" to this post's title

I will, thank you :)

You're also reading the state of the LED pins in your setup, which isn't hurting anything but it doesn't make much sense.

I think the root problem is (was) you tried to do too much at once... Write some code to read the button and send the results to the serial monitor (there's an example program for that). Then, add another couple of lines and make it count.

Write one or two lines of code, test-compile and test-run (and debug if necessary) before continuing. And, make use of the serial monitor. You can write-out variables or little messages like, "Button pressed", or "Starting light sequence 1".

When you know the button-pressing stuff works, start-over and write a little sketch to make a light pattern (or sequence). When that works, make some more sequences.

When the input (button) and output (light patterns) parts are working, combine them. "Combining code" isn't always simple either so again you'll probably have to add one or two lines of code at a time, testing as you go.

If you can learn to write functions, you'll find it's easier to combine code from different programs. i.e. Adding a function definition shouldn't have any affect (so program should still compile and run), then you just add one line to call the function and test that.


This might be a little advanced for you right now, but for my (sound activated) lighting effects I use*binary* (and hexadecimal*). That way, one variable represents the state of all lights and one bit represents the state of one light. I can do chase/sequencing with bit-shifting. And, I can generate patterns without "hard coding" the patterns or storing the patterns in memory.

Then, I have an output function to read the bits from the variable and write them out to the appropriate I/O pins.

As you probably know, everything in the computer/micro controller is binary, and C/C++ converts variables to regular decimal to make things easier for humans. With binary we often think of a variable as "bit pattern" rather than a '"number", but it's just a different way of thinking about it.

Here's an example of a chase effect using bit shifting and the 4 least-significant bits of a byte: 0001 (binary) = 1 (decimal) = 1 (hex) 0010 (binary) = 2 (decimal) = 2 (hex) 0100 (binary) = 4 (decimal) = 4 (hex) 1000 (binary) = 8 (decimal) = 8 (hex)

If you want to make it loop/repeat, read bit-3 (the left-most bit) before shifting and write it's value into bit-zero (the right-most bit) after shifting.

If you flip the state of bit-3 before writing it into bit-zero you get a Johnson Counter: 0001 0011 0111 1111 1110 1100 1000 0000 0001 0011...

Of course, these effects are easy to reverse by bit-shifting in the other direction.

Another effect I have is to simply generate a new random pattern on every "beat".

* When working with binary, hex is easier than decimal because you can easily to convert variables of any size between hex and binary in your head. With 4-bits decimal is just as easy, but if you get more than that, decimal requires some calculations. Every 4-bits converts exactly to one hex digit, so you just learn 16 conversions and you can handle large hex/binary numbers. You already know zero and 1, and many others are "easy" to learn/remember, so it's not too hard to learn all 16 conversions. BTW - The windows calculator in Programmer View can convert between decimal, binary, hex, and octal.

Im bookmarking that to study and reference later, because I am absolutely certain that will come in handy. Thank you!

Btw, on skype with a programmer friend, and he explained to me this little line of code we were wondering about earlier:

const unsigned long ledInterval = 650;


if ( (millis () - ledTimer) >= ledInterval )

My led interval is set to 650 milliseconds. What the if statement here is doing is saying, if the current amount of milliseconds that has passed, minus the millisecond timer on the led, is greater than or equal to the interval amount, do the if function (in this case, switch the state of the leds.) Which I needed, since installing a delay messed with the button press.

jdreader01: Btw, on skype with a programmer friend, and he explained to me this little line of code we were wondering about earlier:

const unsigned long ledInterval = 650;

if ( (millis () - ledTimer) >= ledInterval )




My led interval is set to 650 milliseconds. What the if statement here is doing is saying, if the current amount of milliseconds that has passed, minus the millisecond timer on the led, is greater than or equal to the interval amount, do the if function (in this case, switch the state of the leds.) Which I needed, since installing a delay messed with the button press.

so is it like: maintain one state or pattern of blink for 650ms, then change?

More or less, yes. It makes sense now, looking at it. My method of learning code is copy/paste, and then read it and understand what it is doing. Which is what I did here.