Using a button to switch between programs/loops?

How can I use a button to switch between different programs or void loops? I want to use a button to switch between different types of LED lighting loops

Let's say you have 8 different sequences of light display. Keep a counter from 0 to 7. Then, each time the button is pressed, increment the counter (or loop back to 0 when you reach MAX). Have your program check that counter with every loop. Then call your specific sequence display based on that counter.

This does mean that your light sequences are written without any for-loops and delay() calls. Everything is based on the main loop and timed delays using millis() to see if a certain amount of time has elapsed.

I knew I had done this before … had to dig up a display of two years ago. This is based on single LEDs attached to single pins on a LilyPad. But with a few changes, this can also be applied to driving LED strings.

void blinkLeds(int stage) {
  // This calls the respective LED sequence to be displayed.
  if (millis() - prevMillis > pause) {
    switch (stage) {
      case 1:
        stage_one();
        break;
      case 2:
        stage_two();
        break;
    }
    prevMillis = millis();
  }
}

void loop() {
  // The main loop does two things:
  // a) check for button changes
  // b) call the blinkLeds() routine with the stage/sequence number
  currentMillis = millis();
  reading = digitalRead(inPin)  // this is the pin the button is attached to
  if (reading == HIGH && previous == LOW && millis() - time > debounce) {
    time = millis();
    stage++;
    if (stage > maxStages) stage = 0;
    // maxStages = the amount of different light up sequences that you have.
    // I only showed two here, so maxStages should be initialized as 1 (0 and 1 = 2 stages)
  }
  blinkLeds(stage);
  previous = reading;
}

void resetAll() {
  // This resets all the pins to LOW, effectively turning everything off.
  pause = 0;
  startMillis = 0;
  shortPauseInt = 2000;
  longPauseInt = 3000;
  // This was made for a LilyPad and I have all the pins defined in a myPins[] array, from pin 2 up to 11
  // and using analog pins A0 through A5
  for (p = 0; p < (sizeof(myPins) / sizeof(byte)); p++) {
    digitalWrite(myPins[p], LOW);
  }
}

void stage_one() {
  // Ascending chase, both sides
  // the LilyPad is divided into a left half and right half.
  if (resetDone != 1) {
    resetAll();
    resetDone = 1;
  }
  if (millis() - startMillis > longPause) {
    pause = 50;
    if (n < (sizeof(myPins) / sizeof(byte))) {
      digitalWrite(myPins[n], HIGH);
    }
    if (n > 2) {
      digitalWrite(myPins[n - 3], LOW);
    }
    n++;
    if (n == 19) {
      n = 0;
      startMillis = millis();
      longPause = random(shortPauseInt, longPauseInt);
    }
  }
}

void stage_two() {
  // Descending chase, both sides
  // the LilyPad is divided into a left half and right half.
  if (resetDone != 1) {
    resetAll();
    resetDone = 1;
    n = 18;
  }
  if (millis() - startMillis > longPause) {
    pause = 50;
    if ((n < (sizeof(myPins) / sizeof(byte))) && (n >= 0)) {
      digitalWrite(myPins[n], HIGH);
    }
    if (n < 13) {
      digitalWrite(myPins[n + 3], LOW);
    }
    n--;
    if (n == -4) {
      n = 15;
      startMillis = millis();
      longPause = random(shortPauseInt, longPauseInt);
    }
  }
}

There will be stuff missing as I didn’t copy all of the programming here. There are other things going on at the same time (such as a stage indicater LED also blinking at the same time, so I could tell which stage is currently running since I was sitting behind the actual display.)

Cool. I see where you are coming from, but I barely know any programming.

I’m using this code that I found online to cycle through colors on my RGB led:

const int redPin = 11;
const int greenPin = 10;
const int bluePin = 9;

void setup() {
// Start off with the LED off.
setColourRgb(0,0,0);
}

void loop() {
unsigned int rgbColour[3];

// Start off with red.
rgbColour[0] = 255;
rgbColour[1] = 0;
rgbColour[2] = 0;

// Choose the colours to increment and decrement.
for (int decColour = 0; decColour < 3; decColour += 1) {
int incColour = decColour == 2 ? 0 : decColour + 1;

// cross-fade the two colours.
for(int i = 0; i < 255; i += 1) {
rgbColour[decColour] -= 1;
rgbColour[incColour] += 1;

setColourRgb(rgbColour[0], rgbColour[1], rgbColour[2]);
delay(5);
}
}
}

void setColourRgb(unsigned int red, unsigned int green, unsigned int blue) {
analogWrite(redPin, red);
analogWrite(greenPin, green);
analogWrite(bluePin, blue);
}

I want to make it so when I press a button, it switches between this color loop, one color, a second color, then a third color. (4 different LED lighting patterns total)

kstephens13:
I want to make it so when I press a button, it switches between this color loop, one color, a second color, then a third color. (4 different LED lighting patterns total)

The best way would be to re-design it to not use a for loop or delay as in the above posted example.

A workaround would be to use a state machine and check inside your for loop. If the state value isn't right, break out of the loop and go back to the state machine. You would also need to use an interrupt for the button.

Also in the future, while blue is pretty, it's much better to enclose your code within the designated CODE tags.

Thanks! though how exactly would the program look? I barely have any knowledge of programming :\

That’s why I posted my example. Take your actual light sequence and take it out of the loop(). Make it a callable function. Get rid of the for loop and make it based on a expired timer by using the millis() function.

Your loop should only be doing two things, check for the button, and call the function that is in charge of the light sequence. Basically, something like this:

loop() {
  - check button
  - call sequence control
}

sequence control() {
  call respective sequence
}

sequence 1() {
}

sequence 2() {
}

etc., etc,

This will loop through everything constantly. So by setting a timer inside of your sequences, you can control when it actually blinks an LED. For example, let’s say you want to blink an LED every 50ms, you’d do something like this say inside of the sequence 1 routine:

if (millis() > prevMillis + 50ms) {
  // turn LED on or off
  prevMillis = millis();
}

What that does is check to see if the current time (millis()) is bigger than the previous time the LED changed it’s state (prevMillis) plus the addition of the 50ms. If the elapsed time is not bigger, it will ignore the instructions within the if loop and the LED remains at its current state. If the time is bigger, then it will change the LED again and reset prevMillis to the current time again.

When you loop through that it goes something like this:
Let’s assume prevMillis = 0 and that millis() returns 10 at the first check: if (10 > 0 + 50) { … } - that returns false so it doesn’t enter the IF loop.
Now some time later, millis() would’ve advanced (as any clock would) and now it returns 53: if (53 > 0 + 50) { … } - this now returns true, so it enters the loop and do something to the LED. At the same time it sets prevMillis to 53 as well.
Next loop when millis() returns 54, you get: if (54 > 53 + 50) { … } - that now returns false again so it doesn’t change the LED.

This repeats itself over and over again till mills() is once again larger than the sum of prevMillis and your 50ms pause.

Hope that makes sense.

Realizing this thread is 4 years old, if you're still listening, I have a question.

Is there any impact on the board, performance-wise, by continually storing and checking the clock value? I know that millis() is calculated either way, but by throwing in the ever increasing prevMillis, don't you run the risk of writing a massively large integer (over time) that would cause problems in processing time? Or am I overthinking it?

I'm working on a very similar setup, basically changing the patterns of a small LED chain at the click of a button, but I'll be using a Trinket and I'm a little concerned about overloading the little thing.

Please start a new topic when you need help.
Read this:

jedimasta:
Or am I overthinking it?

Yes

I learned something today. Thanks y'all.