[Beginner] Help with FastLED

Hi guys. I am new to coding and just started using Ardunio. I am hoping to learn it while building a project.

Hardware - Freetronics EtherTen with WS2812 (236LEDs)

Project - Start from all LEDs off. Slide LED1 to the end and leave last LED ON at the end of the loop and do that until the LED118 is lit.

Idea is to build further from there and create multiple scenes and control them via Hex string over ethernet. But for now, I am trying to wrap my head around the basics first.

I have picked up an example from library and started building from there. Below code runs fine and leaves the last LED ON at the end of the first loop. But doesn’t turn the second last LED ON at the end of the second loop and so on.

#include <FastLED.h>

#define NUM_LEDS 236

#define DATA_PIN 12

CRGB leds[NUM_LEDS];

void setup() { 
  Serial.begin(9600);
  Serial.println("Loop Begins");
  LEDS.addLeds<WS2812,DATA_PIN,RGB>(leds,NUM_LEDS);
  LEDS.setBrightness(100);
}

void fadeall() { for(int i = 0, j = 1; i < NUM_LEDS-j, j < NUM_LEDS ; i++,j++ ) { leds[i].nscale8(100); } }

void loop() { 
  
  Serial.print("x");
  
  // First slide the led in one direction
  for(int i = 0, j = 0; i < NUM_LEDS-j, j< NUM_LEDS; i++,j++) {
  // Set the i'th led to WHITE 
    leds[i] = leds[i].setRGB(255,255,255);
   
    // Show the leds
    FastLED.show(); 
    FastLED.delay (20);
    FastLED.setDither(0);

    fadeall();
    // Wait a little bit before we loop around and do it again
    delay(10);
  }
  Serial.print("x");

  }

P.S. : This is my first post, I hope I am following guidelines. Please let me know if I missed something.

Thanks,

for(int i = 0, j = 0; i < NUM_LEDS-j, j< NUM_LEDS; i++,j++) {

Why that complicated statement? It's the same as

for(int i = 0; i < (NUM_LEDS / 2); i++ ){

Two tips for the future:

  • Let loop() do the looping
  • Use millis() (not drop in!) instead of delay() to be able to do other stuff in the meantime.

septillion:

for(int i = 0, j = 0; i < NUM_LEDS-j, j< NUM_LEDS; i++,j++) {

Why that complicated statement? It's the same as

for(int i = 0; i < (NUM_LEDS / 2); i++ ){

Two tips for the future:

  • Let loop() do the looping
  • Use millis() (not drop in!) instead of delay() to be able to do other stuff in the meantime.

Thank you so much septillion.

for(int i = 0; i < (NUM_LEDS / 2); i++ ){

This perfectly simplifies the code but I am still not getting what I was looking for. Above code starts turning ON the LEDs from LED 118 and slides from there to the end. What I am trying to do is to turn ON only the last LED at the end of first loop, then second last LED in the second loop and so on. Something like water drops filling a tube kind of effect. Sorry if I was not clear in my earlier post.

You do the same silliness with the loop in the fadeall function.
The trick with development is to do one thing at once, test and then when it works add more features. I would advise you not to do the fade bit until you have the position bit working first.

What you have to do when you get advice and you implement it and still have trouble, is to post your new code, say what it does and say what you wanted it to do.

Above code starts turning ON the LEDs from LED 118 and slides from there to the end.

No it doesn't. Not when you make those corrections to the for loops.

If you want to do nested for loops like, it seems you want to, then this is how you do them:-

     for(int j = 0; j< NUM_LEDS; j++) {
        for(int i = 0; i < NUM_LEDS-j ; i++) {
          // this is the inner loop where i changes     
         }
         // this is the outer loop where j changes
      }

Grumpy_Mike:
You do the same silliness with the loop in the fadeall function.
The trick with development is to do one thing at once, test and then when it works add more features. I would advise you not to do the fade bit until you have the position bit working first.

What you have to do when you get advice and you implement it and still have trouble, is to post your new code, say what it does and say what you wanted it to do.
No it doesn't. Not when you make those corrections to the for loops.

If you want to do nested for loops like, it seems you want to, then this is how you do them:-

     for(int j = 0; j< NUM_LEDS; j++) {

for(int i = 0; i < NUM_LEDS-j ; i++) {
         // this is the inner loop where i changes    
        }
        // this is the outer loop where j changes
     }

Thank you so much Grumpy_Mike. You are a bit grumpy but amazing.
Like you said, I dropped Fadeall and started working with a more basic example. Finally I have a basic version of code to show what I want the LEDs to do. Thanks to your idea of using nested for loops.

#include <FastLED.h>

///////////////////////////////////////////////////////////////////////////////////////////
//
// Move a white dot along the strip of leds and leave the last one lit in the loop.
// 

// How many leds are in the strip?

#define NUM_LEDS 236 

#define DATA_PIN 12



// This is an array of leds.  One item for each led in your strip.

CRGB leds[NUM_LEDS];

void setup() {

     delay(1000);

    FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);

}

// This function runs over and over, and is where you do the magic to light
// your leds.
void loop() {
  
 
   for (int k = 0, j = NUM_LEDS-1; k < NUM_LEDS, j > 230 ; j--, k++){   //testing with just last 5 LEDs for now

    
      // Move a single white led
   for(int whiteLed = 0; whiteLed < NUM_LEDS-k; whiteLed = whiteLed + 1) {
    
      // Turn our current led on to white, then show the leds
      leds[whiteLed] = CRGB::White;
 
    
      // Show the leds (only one of which is set to white, from above)
      FastLED.show();

      // Wait a little bit
      delay(50);

      // Turn our current led back to black for the next loop around
 if ( whiteLed != j){
  leds[whiteLed] = CRGB::Black;
 }
 
 }  
 }
     }

Please excuse the use of delay. I am still trying to wrap my head around millis.
Now how to stop the loop after lighting up those 5 LEDs and not to start again until a HEX string is sent via ethernet.
PS : I hope I am not getting too ambitious too soon. :slight_smile:

I hope I am not getting too ambitious too soon

No that sounds alright.

Now how to stop the loop after lighting up those 5 LEDs and not to start again until a HEX string is sent via ethernet.

You wrap the code for lighting up those 5 LEDs in an if statement that checks if a boolean variable is true. Add to the LED code a statement that makes that variable false. In that way the code will only run once when that variable is true.
Then have the code that receives the HEX string sent via Ethernet set that variable to true. A good name for that variable might be "updateLEDs". Then an if statement would read:-

if( updateLEDs ) {
   // do the updating
}

It would make things simpler if you moved that update LEDs code into a function called say doUpdate, then the code in your loop would look like:-

if( updateLEDs ) doUpdate();

Note giving things meaningful names makes the code a lot easier to read.

No that sounds alright.

Thanks Mike for the encouragement.

Looks like there is some problem with my board. Not able to assign IP address. May be some hardware issue, ordered a new one. Meanwhile I decided to test the code using buttons.

You wrap the code for lighting up those 5 LEDs in an if statement that checks if a boolean variable is true. Add to the LED code a statement that makes that variable false. In that way the code will only run once when that variable is true.

I used the bool variables and picked up a switch case example to take some help. Now the code complies fine but nothing happens when I upload it. I am not able to trigger the switch cases using pin input. Looks like some noob mistake somewhere in the code.

Note giving things meaningful names makes the code a lot easier to read.

Tried to give more meaningful names this time around.

Draft1.ino (3.31 KB)

Using code tag.

#include <FastLED.h>    // Include FasteLED library

#define NUM_LEDS 236   // Number of LEDS in strip

#define DATA_PIN 12   // Dout pin conncetion of LED strip

CRGB leds[NUM_LEDS];

const int pin_UP = 3;     // input pin for UP button input  (All LEDs UP)
const int pin_Pre1 = 4;   // input pin for Preset 1 button  (1/2 LEDs ON)
const int pin_Pre2 = 5;   // input pin for Preset 2 button  (1/4 LEDs ON)
const int pin_DOWN = 6;   // input pin for DOWN button      (All LEDs OFF)
const int pin_Random = 7; // input pin for Random button    (Some code to randomly bounce the LEDs around)

bool pushed_UP = HIGH;
bool pushed_Pre1 = false;
bool pushed_Pre2 = false;
bool pushed_DOWN = false;
bool pushed_Random = false;

int showType = 0;
  
void setup (void)
{

  delay(1000);

  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
  FastLED.setBrightness(200); 
  FastLED.clear();
    
  pinMode (pin_UP, INPUT_PULLUP);       // Keep in mind the pull-up means the pushbutton's logic is inverted. It goes HIGH when it's open, and LOW when it's pressed.
  pinMode (pin_Pre1, INPUT_PULLUP);     // Turn on pin 13 when the button is pressed, and off when it's not:
  pinMode (pin_Pre2, INPUT_PULLUP);    
  pinMode (pin_DOWN, INPUT_PULLUP);
  pinMode (pin_Random, INPUT_PULLUP);
  
}
void loop ()
{
  bool prev_UP     = pushed_UP;
  bool prev_Pre1   = pushed_Pre1;
  bool prev_Pre2   = pushed_Pre2;
  bool prev_DOWN   = pushed_DOWN;
  bool prev_Random = pushed_Random;

bool pushed_Up     = digitalRead (pin_UP)     == LOW;
bool pushed_Pre1   = digitalRead (pin_Pre1)   == LOW;
bool pushed_Pre2   = digitalRead (pin_Pre2)   == LOW;
bool pushed_DOWN   = digitalRead (pin_DOWN)   == LOW;
bool pushed_Random = digitalRead (pin_Random) == LOW;
  
  
  if (prev_UP != pushed_UP)       // UP button just pressed               
    {
  showType=1; 
    }
  
  if (prev_Pre1 != pushed_Pre1)     // Pre1_button just pressed               
    {
  showType=2;                
    }
  
  if (prev_Pre2 != pushed_Pre2)     // Pre2_button just pressed               
    {
  showType=3;                
    }

  if (prev_DOWN != pushed_DOWN)     // DOWN_button just pressed               
    {
  showType=4;                
    }

  if (prev_Random != pushed_Random)   // Random_button just pressed               
    {
  showType=5;                
    }
}

void startShow(int showtype) {
  switch(showType){
   
     case 1: 
   for (int k = 0, j = NUM_LEDS-1; k < NUM_LEDS, j > 230 ; j--, k++){         // Put number of LEDs to be turned ON here.

   for(int whiteLed = 0; whiteLed < NUM_LEDS-k; whiteLed = whiteLed + 1) {    // Move a single white led
    
   leds[whiteLed] = CRGB::Blue;                                               // Turn our current led on to white, then show the leds
    
   FastLED.show();                                                            // Show the leds (only one of which is set to white, from above)
  
   delay(10);                                                                 // Wait a little bit
  
   if ( whiteLed != j){    
                                                                              // Turn our current led back to black for the next loop around
   leds[whiteLed] = CRGB::Black;
  
            break;
            delay (20);
 
 }
 }}}}

Yes a rookie mistake.
When you define a variable you get a new variable so you loose the value of the previous one. When you define a variable inside a function they instantly get lost once the function ends.
To stop this from happening define the variable outside a function. This way they become global variables.
You define lots of variables inside the loop function ..... don’t.

Also what are you trying to do here?

 pushed_Up     = digitalRead (pin_UP)     == LOW;

Never seen any one do this before, I know it will compile but it is very odd. What are you expecting this to be?

Your comment is wrong here and other places read my new comment for what it is really doing

 if (prev_Pre1 != pushed_Pre1)     // Pre1_button just pressed or released

Also what are you trying to do here?
Code: [Select]

pushed_Up     = digitalRead (pin_UP)     == LOW;

Found this in some example, trying if it can make my code work. Originally I wrote -

bool pushed_Up     = digitalRead (pin_UP)   ;
bool pushed_Pre1   = digitalRead (pin_Pre1) ;

To stop this from happening define the variable outside a function. This way they become global variables.

Idea is to constantly looking for any change in button state via running loop. If I make any of these global variable, change of state will not be registered. I mean that's what I thought. Any suggestions for this.

void loop ()
{
  bool prev_UP     = pushed_UP;
  bool prev_Pre1   = pushed_Pre1;
  bool prev_Pre2   = pushed_Pre2;
  bool prev_DOWN   = pushed_DOWN;
  bool prev_Random = pushed_Random;

bool pushed_Up     = digitalRead (pin_UP)   ;
bool pushed_Pre1   = digitalRead (pin_Pre1) ;
bool pushed_Pre2   = digitalRead (pin_Pre2) ;
bool pushed_DOWN   = digitalRead (pin_DOWN) ;
bool pushed_Random = digitalRead (pin_Random);

Idea is to constantly looking for any change in button state via running loop. If I make any of these global variable, change of state will not be registered. I mean that's what I thought. Any suggestions for this.

Making the variables global does not preclude using them in a function. In fact a global variable can be used in all functions.
So to use them when they are already defined as a global variable just use:-

 pushed_Up     = digitalRead (pin_UP);
pushed_Pre1   = digitalRead (pin_Pre1);

Just before the setup function write:-

bool pushed_Up ;
bool pushed_Pre1 ;

The same goes for all the other variables you define in a function presently.

If I understood your comments correctly, recommended changes are done but still not able to trigger anything using buttons.

I am using momentary button connected between digital pin and 0V.

I will break down the code as per my understanding. Looks like code is doing something and I think it is doing something else.

Defined global variables -

#include <FastLED.h>    // Include FasteLED library

#define NUM_LEDS 236   // Number of LEDS in strip

#define DATA_PIN 12   // Dout pin conncetion of LED strip

CRGB leds[NUM_LEDS];

const int pin_UP = 3;     // input pin for UP button input  (All LEDs UP)
const int pin_Pre1 = 4;   // input pin for Preset 1 button  (1/2 LEDs ON)
const int pin_Pre2 = 5;   // input pin for Preset 2 button  (1/4 LEDs ON)
const int pin_DOWN = 6;   // input pin for DOWN button      (All LEDs OFF)
const int pin_Random = 7; // input pin for Random button    (Some code to randomly bounce the LEDs around)

bool pushed_UP;
bool pushed_Pre1;
bool pushed_Pre2;
bool pushed_DOWN;
bool pushed_Random;


int showType = 0;

Setup for setting FastLED and pinMode

void setup (void)
{

  delay(1000);

  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
  FastLED.setBrightness(200); 
  FastLED.clear();
    
  pinMode (pin_UP, INPUT_PULLUP);       // Keep in mind the pull-up means the pushbutton's logic is inverted. It goes HIGH when it's open, and LOW when it's pressed.
  pinMode (pin_Pre1, INPUT_PULLUP);     // Turn on pin 12 when the button is pressed, and off when it's not:
  pinMode (pin_Pre2, INPUT_PULLUP);    
  pinMode (pin_DOWN, INPUT_PULLUP);
  pinMode (pin_Random, INPUT_PULLUP);
  
}

Added bool variable (prev_UP) in loop to compare the new pin state with old pin state and only trigger the event in case of state change.

void loop ()
{
  bool prev_UP    = pushed_UP;
  bool prev_Pre1   = pushed_Pre1;
  bool prev_Pre2   = pushed_Pre2;
  bool prev_DOWN   = pushed_DOWN;
  bool prev_Random = pushed_Random;

 pushed_UP     = digitalRead(pin_UP)   ;
 pushed_Pre1   = digitalRead(pin_Pre1) ;
 pushed_Pre2   = digitalRead(pin_Pre2) ;
 pushed_DOWN   = digitalRead(pin_DOWN) ;
 pushed_Random = digitalRead(pin_Random);
  
  if (prev_UP != pushed_UP)       // UP button just pressed              
    {
  showType=1; 
    }

You are still doing it

 bool prev_UP    = pushed_UP;
  bool prev_Pre1   = pushed_Pre1;
  bool prev_Pre2   = pushed_Pre2;
  bool prev_DOWN   = pushed_DOWN;
  bool prev_Random = pushed_Random;

Now you are either having me on or there is something fundamental that you are not understanding from my words.

Adding a bool in front of those variable names creates an other set of variables with the same name as your global ones. The global ones get ignored and these temporary variables are used. Once the loop function finishes these temporary variables are discarded, and when the loop function starts again a fresh set of temporary variables are created and used in that one pass only of the loop.

Remove all the words “bool” from inside your loop function. Why do you not do this simple thing?

Sorry Mike I was not understanding correctly. Thanks for being patient. :slight_smile:

I have now defined all the 'prev' variables before the setup function.

I changed the code accordingly, got rid of switch case for now just to make sure that I am getting the button inputs. Somehow, I am still not able to get the button inputs. I am sure it is again some rookie mistake.

#include <FastLED.h>    // Include FasteLED library

#define NUM_LEDS 236   // Number of LEDS in strip

#define DATA_PIN 12   // Dout pin conncetion of LED strip

CRGB leds[NUM_LEDS];

const int pin_UP = 3;     // input pin for UP button input  (All LEDs UP)
const int pin_Pre1 = 4;   // input pin for Preset 1 button  (1/2 LEDs ON)
const int pin_Pre2 = 5;   // input pin for Preset 2 button  (1/4 LEDs ON)
const int pin_DOWN = 6;   // input pin for DOWN button      (All LEDs OFF)
const int pin_Random = 7; // input pin for Random button    (Some code to randomly bounce the LEDs around)

bool pushed_UP;
bool pushed_Pre1;
bool pushed_Pre2;
bool pushed_DOWN;
bool pushed_Random;

bool prev_UP;
bool prev_Pre1;
bool prev_Pre2;
bool prev_DOWN;
bool prev_Random;

int showType = 0;
  
void setup (void)
{

  delay(1000);

  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
  FastLED.setBrightness(200); 
  FastLED.clear();
    
  pinMode (pin_UP, INPUT_PULLUP);       // Keep in mind the pull-up means the pushbutton's logic is inverted. It goes HIGH when it's open, and LOW when it's pressed.
  pinMode (pin_Pre1, INPUT_PULLUP);     // Turn on pin 12 when the button is pressed, and off when it's not:
  pinMode (pin_Pre2, INPUT_PULLUP);    
  pinMode (pin_DOWN, INPUT_PULLUP);
  pinMode (pin_Random, INPUT_PULLUP);
  
}
void loop ()
{
   prev_UP     = pushed_UP;
   prev_Pre1   = pushed_Pre1;
   prev_Pre2   = pushed_Pre2;
   prev_DOWN   = pushed_DOWN;
   prev_Random = pushed_Random;

 pushed_UP     = digitalRead(pin_UP)   ;
 pushed_Pre1   = digitalRead(pin_Pre1) ;
 pushed_Pre2   = digitalRead(pin_Pre2) ;
 pushed_DOWN   = digitalRead(pin_DOWN) ;
 pushed_Random = digitalRead(pin_Random);
  
  if (prev_UP != pushed_UP)       // UP button just pressed              
    {
  for (int k = 0, j = NUM_LEDS-1; k < NUM_LEDS, j > 230 ; j--, k++){          // Put number of LEDs to be turned ON here.

   for(int whiteLed = 0; whiteLed < NUM_LEDS-k; whiteLed = whiteLed + 1) {    // Move a single white led
    
   leds[whiteLed] = CRGB::Blue;                                               // Turn our current led on to white, then show the leds
    
   FastLED.show();                                                            // Show the leds (only one of which is set to white, from above)
  
   delay(10);                                                                 // Wait a little bit
  
   if ( whiteLed != j){    
                                                                              // Turn our current led back to black for the next loop around
   leds[whiteLed] = CRGB::Black;
  
            break;
            delay (20);
 
 }
 }}}}
if (prev_UP != pushed_UP)       // UP button just pressed

no that would be "// UP button just pressed or released"
Assuming the button returns a HIGH when pressed that code need to be:-
[code]if (prev_UP != pushed_UP) && pushed_UP == High)      // UP button just pressed    [/code]

now you are trying to get too much going too soon.

  for (int k = 0, j = NUM_LEDS-1; k < NUM_LEDS, j > 230 ; j--, k++){          // Put number of LEDs to be turned ON here.

Now we have talked about this before I think. You do not write for loops like this, it is a nonsense. There is only one variable in a for loop. If you want two then you have to use nested for loops. If not then write the code that you want. Write simple code and built it up.

Also don't use the show method for every LED you change ( unless it is an effect you want ) but wait until all the LEDs has been changed, then call the show state.