WS2812B controlled by button (test)

Hello.I want to control my led strip (ws2812b) with a button.For example, when I push the button (a simple click on it) ,I want to change the color,but the problem is that when I push it,the led strip changes 4 to 6 colors.
See below "array_colors".For instance,when it's red and I push it,it goes to DeepSkyBlue or Olive, intead of green (the next one) color.
I print the buttonState variable to serial monitor every time to see what is going on and I understand that when I push it (I mean instantly) ,I see a lot of "1" ,instead of only once (because I press it only once).I tried to solve this problem with some boolean variables in the if statement ,but the problem didn't solve.
What can I do to figure it out?
I hope you understand my problem.

Code:

#include <FastLED.h>

#define LED_STRIP_PIN 4
#define NUM_OF_LEDS 30

CRGB leds[NUM_OF_LEDS];
int brightness = 255;
int buttonState = 0;         
const int buttonPin = 5;  
   
void setup()
{
  pinMode(buttonPin, INPUT);Serial.begin(9600);
 FastLED.addLeds<WS2812B, LED_STRIP_PIN, GRB>(leds, NUM_OF_LEDS);
}
int k = 0;

CRGB array_colors[] = {CRGB::Red , CRGB::Green , CRGB::Blue , CRGB::Yellow , CRGB::GreenYellow , CRGB::DeepSkyBlue , CRGB::Olive , CRGB::Navy , CRGB::Magenta , CRGB::Orange , 
                       CRGB::DeepPink , CRGB::Chocolate , CRGB::Coral , CRGB::Indigo , CRGB::Cyan , CRGB::Purple , CRGB::White
                      };

void loop() 
{  
    buttonState = digitalRead(buttonPin);
    Serial.println(buttonState);
    if(buttonState == 1) 
    {
      k++;
    }
}

void pick_color()
{
  for(int i = 0; i < NUM_OF_LEDS; i++)
  {
    leds[i] = array_colors[k];
    FastLED.setBrightness(brightness);
    FastLED.show(); 
  }
}

Thanks.

How long do you think your Arduino takes to go through that loop() once? And how long do you think the button is pressed if you 'simply click' it?

I don't know and this is why I tried to put a delay of 200 ms (I didn't mention that)

Well, I couldn't smell it either. Either way, putting delays in there doesn't sound like a good idea. It tends to make systems unresponsive to button presses.

Anyway, did my earlier post give you any clues as to what the cause of your problem might be? If not, read it again, and think a little harder.

Do you know how fast is the loop? VEEEEEEEERY FAST! So while you think you pressed the button once the loop went through k++ many times, hence multiple colour change.

Yes I just understand it.

I'm just thinking of how to solve it

I tried some things, but don't work any of them at all.Any ideas?

Here is one example from Adafruit. A button press will make the pattern change to one of the several options available. I hope it will hep you a little more. If you have specific questions, please ask :grinning:

How on earth are we supposed to know what you tried and why whatever you tried didn't work?

If you want help, shows us what you're doing.

If you just want people to google stuff for you, I recommend learning to use Google yourself; it's not hard and much quicker than asking someone else to do it.

I tried this one:

int prev_but_state = LOW;
void loop() 
{  
    buttonState = digitalRead(buttonPin);
    Serial.println(buttonState);
    if(buttonState == HIGH && prev_but_state == LOW) 
    {
      k++;
      pick_color();
    }
    prev_but_state = buttonState;
}

This is not addressing the problem, which is, you need to allow loop to increase k only once per press, meaning as soon as k is increased by 1 you need to make the loop skip that scope until button is released and pressed again

I tried this one ,but still doesn't work and I can't think anything else:

boolean flag = true;
void loop() 
{  
    buttonState = digitalRead(buttonPin);
    Serial.println(buttonState);
    if(buttonState == 1 && flag) 
    {
      k++;
      flag = false;
      pick_color();
    }
    if(buttonState == 0)
    {
      flag = true;
    }
    
}

Check out the StateChangeDetection example in the IDE

what is not working, code looks ok

I tried exactly what you say (StateChangeDetection example) and didn't work.
Code:

int lastButtonState = 0;     // previous state of the button

void loop() 
{  
    buttonState = digitalRead(buttonPin);
    Serial.println(buttonState);
    if(buttonState != lastButtonState) 
    {
      if(buttonState == 1)
      {
        k++;
      }
      delay(50);
    }
    
    lastButtonState = buttonState;

    pick_color();
}

I print the buttonState variable to see what happens.
In the beginning, prints always "0" ,then
when I push it (instantly) it goes to "1" for several times (because loop code runs faster than the time of the button) , BUT then it goes from "1" to "0" and "0" to "1" for several times and after a bit ,it goes to "0" ,until I push it again.

I can't think anything else...

should be:

    lastButtonState = buttonState;
    }
    

Did they really mess up StateChangeDetection? :slight_smile:

looks like you need to implement some debouncing. only increase k after button has been continuously pressed for a few milliseconds

That isn't the problem, it's because lastButtonState is unconditionally updated... the debounce is the delay(50).

we are talking about different code, this is confusing now