Help with a push button LED strip fade scene

I need some help with coding a push button LED strip fade sequence. Let me give you guys a little background on my experience, basically no experience, but I have read and researched to my end and need some help. I have pieced some code from here and there to get me where I am currently. You guys might have a better way to do this and I am all ears. I have a circuit with 3 push buttons that activate certain addressable LEDs on a WS2812B LED strip. Button 1 basically sets all LEDs to black (off), button 2 activates certain LEDs to white, and button 3 activates certain LEDs to fade in and fade out from black to white and vice versa. Buttons 1 and 2 works correctly, but button 3 (fade in/out) only works correctly if I hold the button down and not let off of the button. I need it to work the fade in/out function by just a button press and not a button hold. I appreciate your time and help!

#include <FastLED.h>
#define NUM_LEDS 14
#define DATA_PIN 6
#define COLOR_ORDER GRB

int fadeAmount = 5;  // Set the amount to fade I usually do 5, 10, 15, 20, 25 etc even up to 255.
int brightness = 0; 

CRGB leds[NUM_LEDS];


const byte button_1 = 2; // pin to connect button switch to between pin and ground
const byte button_2 = 4; // pin to connect button switch to between pin and ground
const byte button_3 = 8; // pin to connect button switch to between pin and ground


void setup() {
  FastLED.addLeds<WS2812B, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  wipe(); // wipes the LED buffers
  pinMode(button_1, INPUT_PULLUP); // change pattern button
  pinMode(button_2, INPUT_PULLUP); // change pattern button
  pinMode(button_3, INPUT_PULLUP); // change pattern button
}

void loop() {

  if (digitalRead(button_1) == HIGH) {
    wipe();
  }
  if (digitalRead(button_2) == HIGH) {
    sceneOne();
  }
  if (digitalRead(button_3) == HIGH) {
    sceneTwo();
  }
    
}

void wipe(){ // Clear all LEDs
     for (int i = 0; i < NUM_LEDS; i++) {
       leds[i] = CRGB::Black;
       FastLED.show();
  }

}

void sceneOne(){  // First scene

     for(int i = 0; i < 4; i++ ) {
       leds[i] = CRGB::Black;
       FastLED.show();
     }

     for (int i = 5; i < 9; i++) {
       leds[i] = CRGB::White;
       FastLED.show();
  }

     for (int i = 10; i < 14; i++) {
       leds[i] = CRGB::White;
       FastLED.show();
  }

}
  
void sceneTwo(){  // Second scene

     for(int i = 5; i < 9; i++ ) {
   
     leds[i].setRGB(255,255,255);
     leds[i].fadeLightBy(brightness);
     }

     for(int i = 10; i < 14; i++ ) {
   
     leds[i].setRGB(255,255,255);
     leds[i].fadeLightBy(brightness);
     }

     for(int i = 0; i < 4; i++ ) {
   
     leds[i].setRGB(255,255,255);
     leds[i].fadeLightBy(brightness);
     }

     
     FastLED.show();
     brightness = brightness + fadeAmount;
  // reverse the direction of the fading at the ends of the fade: 
     if(brightness == 0 || brightness == 255)
     {
       fadeAmount = -fadeAmount ; 
     }    
     delay(12.3);  // This delay sets speed of the fade. I usually do from 5-75 but you can always go higher.

}

Buttons 1 and 2 works correctly,

Do they? You are using INPUT_PULLUP mode, yet you are checking if the pins are HIGH. They would be LOW when pressed.

PaulRB, thanks for looking at this problem. I am at work at the moment (US Central time) but will provide you with more information when I get home. I will give you a schematic and a video of what I am seeing if you would like. Thanks again for looking at this!

Hello Paul,

I went home and created a schematic of how things are wired up. I also took a few videos so you can see how it performs. The first video is how the circuit performs from the code posted in post 1 - YouTube . The second video - YouTube is I am using INPUT_PULLUP and all 3 if statements (digitalRead(button_x) == LOW)

You show - sort of - the buttons connected to 5 V and to ground via resistors. If you are using INPUT_PULLUP, you should be connecting the buttons between ground and an input, and you may wish to add a pullup from the input to 5 V as well.

you should be connecting the buttons between ground and an input

I originally had it connected that way and the results were the same as the first video I linked to. That did not make a difference.

you may wish to add a pullup from the input to 5 V as well

Are you saying add a 10K resistor on the 5V side as well? By the way this code and buttons will be incorporated into what you designed for me on my other thread. I wasn't sure if I need two threads to help me out with the total design. This thread was to help with the coding part with the push buttons in a micro scale of the led strips that will actually be involved. Please correct me if I did the forum rules wrong.

Are you saying add a 10K resistor on the 5V side as well?

No, just wire the buttons from the pins to ground. No connection to 5V. No resistors. Use INPUT_PULLUP. When a button is pressed, the pin will read LOW.

(The alternative Paul__B suggests is to wire the pins from the buttons to ground, use 10K resistors from the pins to 5V, and use INPUT mode. This is not normally needed, but can be useful when you have very long wires to the button and those wires might pick up electrical noise from the surroundings, which might cause false readings. The lower value external pull ups would make it less susceptible to noise.)

This should get you back to the buttons working like in the first video.

To fix your fading problem, you need to make some code changes. Your code needs to remember which button was last pressed, and perform the fade function if the fade button was the last to be pressed, regardless of whether it is still pressed. Do do this, you could make a new global int variable and set it to 1, 2 or 3 when one of the buttons is pressed.

I wasn't sure if I need two threads to help me out with the total design.

Best to keep to a single topic. You may think you have two separate problems, but you could be wrong. Even if you are not, you will probably have to explain the whole project twice over, answer the same questions twice over etc. This is unproductive for you and those trying to help you. It's called "cross-posting" and there is a forum rule about that.

PaulRB:
The alternative Paul__B suggests is to wire the pins from the buttons to ground, use 10K resistors from the pins to 5V, and use INPUT mode.

No, I did not suggest using "INPUT" for pinMode. It does not make sense. You use INPUT_PULLUP but may use external pullups in addition.

To do this, you could make a new global int variable and set it to 1, 2 or 3 when one of the buttons is pressed.

PaulRB, do you mind giving me a code snippet of what you are talking about here. I sort of understand your logic but not necessarily how to write the code.

Actually, I would mind giving you that snippet. Because as soon as you see it, you would be embarrased how simple and obvious it is! Have a go yourself. You will probably get it right, or almost, and if you don't, we will probably understand better what basic concept or misconception of programming is eluding you, and help you get that sorted in your mind. We love those "eurica" "Eureka!" moments.

Because as soon as you see it, you would be embarrased how simple and obvious it is!

Sounds good. I am at work and will give it a try when I get home tonight. I will keep you posted!

just wire the buttons from the pins to ground. No connection to 5V. No resistors. Use INPUT_PULLUP. When a button is pressed, the pin will read LOW.

I followed your suggestion and this worked perfectly. Thank you!

To fix your fading problem, you need to make some code changes. Your code needs to remember which button was last pressed, and perform the fade function if the fade button was the last to be pressed, regardless of whether it is still pressed. Do do this, you could make a new global int variable and set it to 1, 2 or 3 when one of the buttons is pressed.

I have spent a couple of hours looking into this with no success. I understand a little bit of code and "if/then" statements that I have worked with in the past on BASH scripts. Basically if the code meets a certain condition then execute something. To my understanding, if I press button 3, then the fade scene should execute. Now I know it is not that simple with these electronics. When I press button 3 it goes to LOW and as soon as I let off it goes back to HIGH meaning the state change causes the fade function to stop executing. When button 3 is pressed to a LOW state and released back to a HIGH state, the function needs to continue until another button is pressed to a LOW state including itself (button 3). Now if I could figure out how to code that logic.

You need a "state" variable. You can either have a separate variable for each button which is set (to the value 1 for example) when that button is pressed - and presumably cleared when a different button is pressed - or (better) you use a single variable which is set to "1" for button 1, "2" for button 2 and so on, and then you use that value (can use a "case" construct) to determine which pattern is performed.

Note that you still need to record for each button, its "last" state so you can tell when it is newly pressed. :sunglasses:

Now I know it is not that simple with these electronics.

When you get it, you'll see it is that simple.

When button 3 is pressed to a LOW state and released back to a HIGH state, the function needs to continue until another button is pressed to a LOW

Correct. So "button 3 is currently pressed/LOW" is the wrong criteria to use to control the fade function. The criteria needs to be "is button 3 the last button that was pressed". That means using this new variable I suggested which remembers which button was last pressed.

The criteria needs to be "is button 3 the last button that was pressed"

So in arduino electronics logic, the only way for me to know when a button has been pushed is testing (reading - digitalRead) whether the button has gone into a LOW state? The main reason this is being difficult for me is I have to remember everything is within a loop() function, therefore code within that loop is constantly being executed on certain conditions. So I as the loop () is being processed, we are checking basically 4 states:
State 1: 1, 1, 1 no buttons pushed - initial state
State 2: 0, 1, 1 button 1 is pushed
State 3: 1, 0, 1 button 2 is pushed
State 4: 1, 1, 0 button 3 is pushed but in order for the fade to work this state 1, 1, 1 also needs to be true only after this state 1, 1, 0

Just trying to logically work myself through the algorithm. This seem correct to you guys?

You just seem to be making this more complicated than it is. It is dead simple!

Declare a new variable, perhaps call it "lastButtonPressed".
If button 1 is pressed, set the variable to 1.
If button 2 is pressed, set the variable to 2.
If button 3 is pressed, set the variable to 3.
If the variable is 3, run the fade code.

You just seem to be making this more complicated than it is. It is dead simple!

I know I am and I apologize for my lack of understanding.

//This code block is just for understanding your advice
//Global variables
int lastButtonPressed = 0;

void loop(){

if (digitalRead(button_1) == LOW) lastButtonPressed = 1;
if (digitalRead(button_2) == LOW) lastButtonPressed = 2;
if (digitalRead(button_3) == LOW) lastButtonPressed = 3;
     if (lastButtonPressed == 3)
     {
      fadeCode();
     }
}

I will keep working. Don’t answer back with the full solution. I might ask some more questions as I get farther into thinking I know what I am doing

I think you got it! Now integrate that back into your previous sketch.