Push button to cycle through modes of an RGB LED strip. Skipping the loop!

Hi there all

Having trouble with something here and I think I’m in the right ballpark but can’t crack it.

I’ve got an WS2812 RGB strip and a pushbutton. I’ve written several different functions for how I want the lights to work in the strip, and then I want to press a push button to cycle through the modes.

The snag is, some of my functions incorporate an infinite loop, and the button press can’t break through this to skip to the next one.

I’ve tried a few different things, and in the code below I’ve basically edited the “State Change Detection” tutorial, but no dice :frowning:

I’ve tried looping whilst the button is pulled LOW (open) and skipping when pulled HIGH (closed) but it still gets stuck in the loop.

Any ideas?

/*
  State change detection (edge detection)
 
 created  27 Sep 2005
 modified 30 Aug 2011
 by Tom Igoe

This example code is in the public domain.
  
 http://arduino.cc/en/Tutorial/ButtonStateChange
 
 */

#include <Adafruit_NeoPixel.h>
#include "WS2812_Definitions.h"

#define PIN 4
#define LED_COUNT 60

Adafruit_NeoPixel leds = Adafruit_NeoPixel(LED_COUNT, PIN, NEO_GRB + NEO_KHZ800);

// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to
    // the pin that the LED is attached to
  // Pin 13: Arduino has an LED connected on pin 13
  // Pin 11: Teensy 2.0 has the LED on pin 11
  // Pin  6: Teensy++ 2.0 has the LED on pin 6
  // Pin 13: Teensy 3.0 has the LED on pin 13

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);

leds.begin();  // Call this to start up the LED strip.
leds.show();   // ...but the LEDs don't actually update until you call this.

  // initialize serial communication:
  Serial.begin(9600);
}

void colourWhite() {

      for(int i=0;i<LED_COUNT;i++){

    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    leds.setPixelColor(i, leds.Color(0,0,255)); // Moderately bright green color.

    leds.show(); // This sends the updated pixel color to the hardware.
   }
   delay(10);
}



void colourRed() {

      for(int i=0;i<LED_COUNT;i++){

    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    leds.setPixelColor(i, leds.Color(0,255,0)); // Moderately bright green color.

    leds.show(); // This sends the updated pixel color to the hardware.
   }
   delay(10);
}



void colourAnother() {

      for(int i=0;i<LED_COUNT;i++){

    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    leds.setPixelColor(i, leds.Color(50,115,10)); // Moderately bright green color.

    leds.show(); // This sends the updated pixel color to the hardware.
   }
   delay(10);
}





void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    } 
    else {
      // if the current state is LOW then the button
      // wend from on to off:
      Serial.println("off"); 
    }
  }
  // save the current state as the last state, 
  //for next time through the loop
  lastButtonState = buttonState;

/****************************************************************/
/****************************************************************/



  
  // turns on the LED every four button pushes by 
  // checking the modulo of the button push counter.
  // the modulo function gives you the remainder of 
  // the division of two numbers:
  if (buttonPushCounter  == 1) {
    colourAnother();
  } else if (buttonPushCounter  == 2){
    for (int i=0;i<1;) {
      if (buttonState == HIGH) {
      buttonState = digitalRead(buttonPin);
      colourWhite();
      colourRed();
      } 
    }
  } else if (buttonPushCounter  == 3){
    colourAnother();
    buttonPushCounter = 1;
  }
  
}

What are you trying to do in the

for (int i=0;i<1;)

block? And your comments say something about modulo but I don’t see it…

Why not just put an if block for each button press / color you want and cycle back when done?

lycrake: Hi there all

Having trouble with something here and I think I'm in the right ballpark but can't crack it.

I've got an WS2812 RGB strip and a pushbutton. I've written several different functions for how I want the lights to work in the strip, and then I want to press a push button to cycle through the modes.

Normally, it is very simple, you just need a readPushButton() function which either returns true in the moment when the button is pressed or false in all other cases (holding the button pressed or in released button state).

Then you need a lightMode() function which takes a single mode number as a parameter

The loop function then would look like this for 10 different lighting modes:

void loop() { static byte mode=0; if (buttonPressed()) mode=(mode+1)%10; // this keeps mode variablae in the range 0...9 lightMode(mode); }

The complicated thing then would be: - create a "lightMode() function which takes a parameter from 0 to 9, which operates in "cooperative multitasking". So the lightMode() function is not allowed to use "delay()" or other blocking functions, otherweise you cannot detect pressed buttons while "delay() in your lightMode function is active.

Perhaps describe your lighting modes a bit further: - show fixed color? - simply fading up and down brightness? - simple blinking patterns?

  • or more advanced stuff?

The more complicated your lighting pattern shall appear, the more complicated the programming will become, without using "delay()" in the lightMode function. But without knowing anything about the different lighing modes, it is completely impossible to tell something about how to create a function for it.

So, with the colour modes I’ve tried to keep it simple so far, and I’ve removed all delays to just try and get the simple button change working when multiple functions are being called.

I’ve basically got one mode which swaps between two colours in an infinite for loop for (int i=0;i<1;)

colourWhite();
colourRed();

I did have a delay(500); inbetween those two to give it a more delayed effect, however I’ve edited that out for the second…

I’ve managed to get it so that i can goto the next mode on button press if the button is pressed at just the right time before it loops again, but basically want to be able to press the button at any stage.

I have had my button presses work perfectly if i just call a single function (colour mode).

Right I think I've solved the problem, I've put the above colour mode into a separate function, as opposed to being directly called in the buttonPushCounter == 2 if statement, and that seems to have solved the problem of not detecting the button.

I'll test it and I'll post my updated code later for anyone else. Will experiment with delays as well...