How to use a button to interrupt a case?

Hello! Little bit new to programming here.

At the moment I have a program that runs an LED strip through various lighting effects, but I want to be

able to interrupt those effects at any time and then switch to a solid color but at 50% brightness.

The button code was taken from the Neopixel Buttoncycler example and so have most of the effects.

void setup() {

 
  // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif
  // END of Trinket-specific code.

  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(255); // Set BRIGHTNESS to about 1/5 (max = 255)
   pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(REDBULB_PIN, OUTPUT);
}


// loop() function -- runs repeatedly as long as board is on ---------------

void loop() {
   int strobe = 0;
 boolean newState = digitalRead(BUTTON_PIN);

  // Check if state changed from high to low (button press).
  if((newState == LOW) && (oldState == HIGH)) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState = digitalRead(BUTTON_PIN);
    if(newState == LOW) {      // Yes, still low
      if(++mode > 8) mode = 0; // Advance to next mode, wrap around after #8
      switch(mode) {    

          case 0:
      OFF();
          break;
          case 1:
          colorWipe(strip.Color(  0,   255,   0), 50);
          brighten();
          darken();
          brighten();
          darken();
          brighten();
          darken();
          for (strobe = 0; strobe <10; strobe++) {
            ON(strip.Color(0,255,0));
            delay(100);
            OFF();            
          }
         
          break;
          case 2:
                 strip.setBrightness(55);
          colorWipe(strip.Color(255,   0,   0), 50);    // Red
          break;





      }
           
      }





  

  }
   oldState = newState;

}

Please let me know if I am in the wrong place, or if I am doing something wrong. Thanks!

Interrupts are disabled in Neopixel code ‘calls’.

I believe GrumpyMike has modified the library to make such things responsive.

Is there a workaround for this?

Yes, rewrite the code in a non-blocking manner. Take advantage of the repetitive invocation of the loop() function rather than using blocking 'for' loops. Control the timing using non-blocking millis() techniques. Read your button input on every pass through loop. If it is asserted, change a state variable to indicate a different action is to be taken every time loop() is invoked.

Do you mean doing something like this?

if so,

What is the difference in how I should use millis vs. delay.

I tried to look up what loop() meant to get a better understanding of it, but I got a 403 access denied.

I think I understand what a state variable is, but I am not sure where to use it.

Just to be clear

Is this the blocking part of the code?

 if((newState == LOW) && (oldState == HIGH)) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState = digitalRead(BUTTON_PIN);
    if(newState == LOW) {      // Yes, still low
      if(++mode > 2) mode = 0; // Advance to next mode, wrap around after #8
      switch(mode) {

or is this the part that I need to change.

 case 0:
          OFF();
          break;
          case 1:
          digitalWrite(REDBULB_PIN, LOW);
          colorWipe(strip.Color(  0,   255,   0), 50);
          brighten();
          darken();
          brighten();
          darken();
          brighten();
          darken();
          for (strobe = 0; strobe <10; strobe++) {
            ON(strip.Color(0,255,0));
            millis(100);
            OFF();            
          }
         
          break;
          case 2:
          digitalWrite(REDBULB_PIN, HIGH);
          strip.setBrightness(55);
          colorWipe(strip.Color(0,   255,   0), 50);    // Red
          break;

Thank you so much for helping. I don’t know anyone who knows arduino really well to ask so getting a response means a lot to me.

MasterFruity:
Do you mean doing something like this?

https://www.arduino.cc/en/tutorial/BlinkWithoutDelay

if so,

What is the difference in how I should use millis vs. delay.

Yes, understanding BWOD is very important in building non-blocking code. Do a site search on ‘millis vs delay’. There are literally thousands of results.

MasterFruity:
I tried to look up what loop() meant to get a better understanding of it, but I got a 403 access denied.

That’s wild! Anyway, setup() is where you do initialization; baud rate, I/O pin config., etc. Think of loop() as your environment where everything else happens, the ocean your code swims in. loop() executes always and continuously once past setup(). Even if it appears nothing is happening loop() continues until reset or power down.

MasterFruity:
I think I understand what a state variable is, but I am not sure where to use it.

State variables are associated with a ‘finite state machine’ - often implemented with the switch/case construct. In this case mode is the state variable. There can be confusion when referring to something like - buttonState - which means is the switch actuated or not?

MasterFruity:
Just to be clear

Is this the blocking part of the code?

if((newState == LOW) && (oldState == HIGH)) {

// Short delay to debounce button.
   delay(20);
   // Check if button is still low after debounce.
   newState = digitalRead(BUTTON_PIN);
   if(newState == LOW) {      // Yes, still low
     if(++mode > 2) mode = 0; // Advance to next mode, wrap around after #8
     switch(mode) {

No, that’s your switch debouncing and state (there’s that word again!) change code. There is a delay() involved but it’s only 20ms, not usually considered a problem. Depending on the type of button it could be reduced.

MasterFruity:
or is this the part that I need to change.

case 0:

OFF();
         break;
         case 1:
         digitalWrite(REDBULB_PIN, LOW);
         colorWipe(strip.Color(  0,   255,   0), 50);
         brighten();
         darken();
         brighten();
         darken();
         brighten();
         darken();
         for (strobe = 0; strobe <10; strobe++) {
           ON(strip.Color(0,255,0));
           millis(100);
           OFF();            
         }
       
         break;

Yes. You can see there’s a 100 millisecond delay inside a for loop which will execute ten times. That’s a whole second during which the code ignores anything like key presses. *IF * brighten() and darken() use delay() that will add to the problem.

Besides BWOD, study the other first four demos in IDE>file/examples/digital. A short tutorial on state machines, hope it helps.

Thank you, I will be sure to do some more research on this because it seems like it is a key part in using I/O in programs.

I also realize that the title for this thread is incorrect, but I was having a hard time articulating what I wanted to get across, oh well.

The deadline on this project has been moved back, so I have more time to work on it. Thank you everybody once again for helping me.

The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

...R