LED Strip Button looping code issue

Hi All,

I'm really new to Arduino and am probably missing something super simple.

The below code works fine for my project with one small issue...
I want the LED strip to light up and then fade over and over if I hold down the button.

Currently, if I hold down the button it will light the LED strip once, fade down and then stays off. I want it to fade then come on again after a second.

I've been trying for a day but can't figure it out. Any help would be greatly appreciated :slight_smile:

Here's my code:

#include <FastLED.h>
#include <ezButton.h>

#define NUM_LEDS 30
#define DATA_PIN 5
ezButton button(7);  
CRGB leds[NUM_LEDS];

void setup() {
 FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
}

void loop(){

 FastLED.clear ();
 button.loop(); 
//int btnState = button.getState();
//delay(50);
 if(button.isPressed())
   for( int colorStep=0; colorStep<255; colorStep++ ) {
 

     int r = 0;  
     int b = 255-colorStep++;  
     int g = 0;          

     for(int x = 0; x < NUM_LEDS; x++){
         leds[x] = CRGB(r,g,b);
}
     FastLED.show();{
}
}
}

don't do the

for( int colorStep=0; colorStep<255; colorStep++ )

inside the If button is pressed block, just do 1 step if button is pressed and at the next loop, if the button is still pressed you modify colorStep and build the display again

Hi Jackson,

Thanks for your reply.

I don't really understand what you mean unfortunately :frowning:

As I said I'm new to this.

I've added get button state but can't get it to work.

Here's where I'm at...

Really appreciate the help :slightly_smiling_face:

#include <FastLED.h>
#include <ezButton.h>
#define NUM_LEDS 30
#define DATA_PIN 5
//#define CLOCK_PIN 13
ezButton button(7);  
CRGB leds[NUM_LEDS];

void setup() {
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
  Serial.begin(9600);
}

void loop(){

 
  button.loop(); {
int btnState = button.getState();
if (btnState = 0);
FastLED.clear ();}

  if(button.isPressed())
    for( int colorStep=0; colorStep<255; colorStep+1 ) {
  

      int r = 0;  
      int b = 255-colorStep++;  
      int g = 0;          

      for(int x = 0; x < NUM_LEDS; x++){
          leds[x] = CRGB(r,g,b);
}
     { FastLED.show();}{
}
}
}

Try something like this

#include <FastLED.h>
#define NUM_LEDS 30
#define DATA_PIN 5
CRGB leds[NUM_LEDS];

const byte buttonPin = 7;
byte colorStep = 0;
unsigned long lastUpdate;
const unsigned long updatePeriod = 100;

void fillStrip(byte c) {
  for (byte px = 0; px < NUM_LEDS; px++)
    leds[px] = CRGB(0, c, 0);
  FastLED.show();
}

void setup()
{
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP); // wire pin D7 --- button --- GND
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
  FastLED.clear ();
  lastUpdate = millis();
}

void loop() {
  if (digitalRead(buttonPin) == LOW) { // pressed
    if (millis() - lastUpdate >= updatePeriod) {
      fillStrip(++colorStep); // get to the next color.
      lastUpdate = millis();
    }
  }
}

wire your button like this: pin D7 --- button --- GND
(typed here, so no guarantee)

I'm not using ezButton.h, I think it's not the best library out there in terms of capabilities. I'd recommend @bricoleau's library in French or the OneButton library from Matthias Hertel or Bounce2 from Thomas Fredericks

Hi Jackson,

Thanks for the code, it's helped a bunch but I'm still not quite there.

I have reversed parts of the code so that the leds light up full then fade out. I have adjusted the fade speed to as fast as I can but I still need to increase it more.
Also, I need the leds to go completely off and then a delay between the next fade.

If I try and introduce a delay the code breaks and the leds just stay lit.

Here's your modified code:

Thanks for helping me with this :upside_down_face:

#include <FastLED.h>
#define NUM_LEDS 30
#define DATA_PIN 5
CRGB leds[NUM_LEDS];

const byte buttonPin = 7;
byte colorStep = 1;
unsigned long lastUpdate;
const unsigned long updatePeriod = 1;

void fillStrip(byte c) {
  for (byte px = 0; px < NUM_LEDS; px++)
    leds[px] = CRGB(0, c, 0);
  FastLED.show(); 
}
void setup()
{
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP); // wire pin D7 --- button --- GND
  FastLED.addLeds<WS2811, DATA_PIN, BRG>(leds, NUM_LEDS);
  FastLED.clear ();
  lastUpdate = millis();
}
void loop() 

{{FastLED.clear ();}

  if (digitalRead(buttonPin) == LOW) { // pressed
    if (millis() - lastUpdate >= updatePeriod) {
      fillStrip(--colorStep);// get to the next color.
      lastUpdate = millis();
      
      if (digitalRead(buttonPin) == HIGH) {
        fillStrip(colorStep=0);
      }
    }
  }
}

let's take a step back and look at the requirements

  • no press = strip is back
  • press = strip goes through various shades of green repetitively as fast as possible but with a pause if you come back to black

correct?

(Jackson is not my name, that's just a badge. Jean-Marc is better :slight_smile: )

Hi Jean-Marc :slight_smile:

  • no press = strip is black - YES

  • Press and hold button - Blue Leds come on full brightness then fade to black quickly then repeat with slight delay in-between.

Does that make sense? :man_facepalming:

OK so you don't want any pause in between updates, just when you hit black again. Try something like this (typed here, untested)

#include <FastLED.h>
#define NUM_LEDS 30
#define DATA_PIN 5
CRGB leds[NUM_LEDS];

const byte buttonPin = 7;
byte colorStep = 0;
unsigned long lastUpdate;
const unsigned long pauseDuration = 1000; // in ms ie 1 second

void fillStrip(byte c) {
  for (byte px = 0; px < NUM_LEDS; px++)
    leds[px] = CRGB(0, c, 0);
  FastLED.show();
}

void black() {
  FastLED.clear ();
  FastLED.show(); // not sure if this is neeed after clear
}

void setup()
{
  pinMode(buttonPin, INPUT_PULLUP); // wire pin D7 --- button --- GND
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
  black();
  lastUpdate = millis();
}

void loop() {
  if (digitalRead(buttonPin) == LOW) { // pressed
    if (colorStep == 0) {      // if we are at 0, there is a pause check if we waited long enough
      if (millis() - lastUpdate >= pauseDuration) {
        fillStrip(++colorStep);
      }
    } else {
      fillStrip(++colorStep); // get to the next color (no waiting time, as fast as loop spins)
      lastUpdate = millis();
    }
  } else {
    black();
  }
}
1 Like

Hi Jean-Marc,

Getting there now - Thanks so much.

Is there an easy way to adjust the fade time?

I've attached the code with my adjustments again.

#include <FastLED.h>
#define NUM_LEDS 30
#define DATA_PIN 5
CRGB leds[NUM_LEDS];

const byte buttonPin = 7;
byte colorStep = 0;
unsigned long lastUpdate;
const unsigned long pauseDuration = 500; // in ms ie 1 second

void fillStrip(byte c) {
  for (byte px = 0; px < NUM_LEDS; px++)
    leds[px] = CRGB(0, c, 0);
  FastLED.show();
}

void black() {
  FastLED.clear ();
  FastLED.show(); // not sure if this is neeed after clear
}

void setup()
{
  pinMode(buttonPin, INPUT_PULLUP); // wire pin D7 --- button --- GND
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
  black();
  lastUpdate = millis();
}

void loop() {
  if (digitalRead(buttonPin) == LOW) { // pressed
    if (colorStep == 0) {      // if we are at 0, there is a pause check if we waited long enough
      if (millis() - lastUpdate >= pauseDuration) {
        fillStrip(--colorStep);
      }
    } else {
      fillStrip(--colorStep); // get to the next color (no waiting time, as fast as loop spins)
      lastUpdate = millis();
    }
  } else {
    black();
  }
}

If you want to adjust the fade time you need to either put a delay when you display something of if you want this to be non blocking (will react faster to button changes) do as was done in the first code by testing against millis

Actually I want to speed the fade up :slight_smile:

This is as fast as it gets if you only decrement by 1, there is no delay involved unless you are at black level.
Try going 5 by 5 (careful on the initial value if you want go hit 0)

Sorry to be such a newbie. I am trying to learn while doing this...

Where would I put the decrement ? :man_shrugging:

You are a :man_superhero: btw

Thatโ€™s the decrement

So youโ€™ll need to do

colorStep = colorStep - 5; // mind byte type being always positive and circling between 0 and 255

And not use the - - in the call

Added the colorStep decrement but if I only press the button once it doesn't do the fade. I tried a delay but no success :frowning:
Any ideas?
Soooo close

Post your code

Going nuts here...

#include <FastLED.h>
#define NUM_LEDS 30
#define DATA_PIN 5
CRGB leds[NUM_LEDS];

const byte buttonPin = 7;
byte colorStep = 0;
unsigned long lastUpdate;
const unsigned long pauseDuration = 300; // in ms ie 1 second

void fillStrip(byte c) {
  for (byte px = 0; px < NUM_LEDS; px++)
    leds[px] = CRGB(c, 0, 0);
  FastLED.show();
}

void black() {
  FastLED.clear ();
 FastLED.show(); // not sure if this is neeed after clear
}

void setup()
{
  pinMode(buttonPin, INPUT_PULLUP);// wire pin D7 --- button --- GND
  FastLED.addLeds<WS2811, DATA_PIN, BGR>(leds, NUM_LEDS);
  black();
  lastUpdate = millis();
}

void loop() {
  if (digitalRead(buttonPin) == LOW) { // pressed
    if (colorStep == 0) {      // if we are at 0, there is a pause check if we waited long enough
      
      if (millis() - lastUpdate >= pauseDuration) {
        fillStrip(colorStep = colorStep - 2);
      }
    } else {
      fillStrip(colorStep = colorStep - 2); // get to the next color (no waiting time, as fast as loop spins)
      lastUpdate = millis();
    }
  } else {
    black();
  }

shorter.mov.zip (2.1 MB)

Here's a vid of the leds. First 3 flashes are me pressing the button quickly 3 times and then from there I was holding the button down.

Hopefully you can see what I mean...

Try this, typing from iPhone so...


#include <FastLED.h>
#define NUM_LEDS 30
#define DATA_PIN 5
CRGB leds[NUM_LEDS];

const byte buttonPin = 7;
int colorStep = 0;
unsigned long lastUpdate;
const unsigned long pauseDuration = 300; // in ms

void fillStrip(byte c) {
  for (byte px = 0; px < NUM_LEDS; px++)
    leds[px] = CRGB(c, 0, 0);
  FastLED.show();
}

void black() {
  FastLED.clear ();
 FastLED.show(); // not sure if this is neeed after clear
}

void setup()
{
  pinMode(buttonPin, INPUT_PULLUP);// wire pin D7 --- button --- GND
  FastLED.addLeds<WS2811, DATA_PIN, BGR>(leds, NUM_LEDS);
  black();
  lastUpdate = millis();
}

void loop() {
  if (digitalRead(buttonPin) == LOW) { // pressed
    if (colorStep <= 0) {      // if we are at 0, there is a pause check if we waited long enough
      black();
      if (millis() - lastUpdate >= pauseDuration) {
        colorStep = 255;
        fillStrip(colorStep);
      }
    } else {
      fillStrip(colorStep); // get to the next color (no waiting time, as fast as loop spins)
       colorStep = colorStep - 2;
      lastUpdate = millis();
    }
  } else {
    black();
  }

It would be easier to read with a small state machine and there would be no useless displays. Left as an exercise :wink:

No change unfortunately. If there was no fade and no delay it would be super easy :grin: