Help programming LED strip custom functions

Hi everyone,

I’ve tried to make the title as clear as possible for this.

I’m new to C++ (your worst nightmare). I’m eager to learn and I’ve been using FastLED and Neopixel examples to break down my learning for led strip specific functions.

I’m also in no hurry whatsoever and I’m more than happy to learn this as thoroughly as possible rather than trying to get instant results but that means asking you guys a lot of questions!

Thanks for everyones help so far and I’ve got as far as connecting an led strip to my Arduino and setting up a simple cyclone code using an example from FastLED:

I’ve also spotted an easily adjustable, trailing version of this from FastLED which I’m happy to take forward. I’ve attempted to strip it out as much as possible so I can understand the function:

#include “FastLED.h”

FASTLED_USING_NAMESPACE

#if FASTLED_VERSION < 3001000
#error “Requires FastLED 3.1 or later; check github for latest code.”
#endif

#define DATA_PIN 6
//#define CLK_PIN 4
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define NUM_LEDS 15
CRGB leds[NUM_LEDS];

#define BRIGHTNESS 1000
#define FRAMES_PER_SECOND 300

void setup() {
delay(3000); // 3 second delay for recovery

// tell FastLED about the LED strip configuration
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
//FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);

// set master brightness control
FastLED.setBrightness(BRIGHTNESS);
}

// List of patterns to cycle through. Each is defined as a separate function below.
typedef void (*SimplePatternList)();
SimplePatternList gPatterns = { sinelon, };

uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
uint8_t gHue = 0; // rotating “base color” used by many of the patterns

void loop()
{
// Call the current pattern function once, updating the ‘leds’ array
gPatternsgCurrentPatternNumber;

// send the ‘leds’ array out to the actual LED strip
FastLED.show();
// insert a delay to keep the framerate modest
FastLED.delay(1000/FRAMES_PER_SECOND);

}

#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))

void sinelon()
{
// a colored dot sweeping back and forth, with fading trails
fadeToBlackBy( leds, NUM_LEDS, 15);
int pos = beatsin16(30,0,NUM_LEDS);
leds[pos] += CRGB( 255, 69, 0);
}

Now, the cyclone function is right at the bottom of course. Is it possible to strip this code further? The original had an array of cycling functions but I only need the one for now. I tried to remove the ‘sinelon’ reference and replace with loop in order to remove the following code:

// List of patterns to cycle through. Each is defined as a separate function below.
typedef void (*SimplePatternList)();
SimplePatternList gPatterns = { sinelon, };

uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
uint8_t gHue = 0; // rotating “base color” used by many of the patterns

void loop()
{
// Call the current pattern function once, updating the ‘leds’ array
gPatternsgCurrentPatternNumber;

The code successfully uploaded to the Arduino but the leds didn’t react. I might just be missing a bracket somewhere perhaps?

This code will hopefully be the basis for my project (custom Mustang sequential taillights) and there’s a couple of adaptations I’d like to achieve once I understand the basics. For example, I’d simply like the cyclone to travel in one direction, over and over, rather than back and forth.

Perhaps I should use a map() function to constrain the direction? If so, I’m not sure how or exactly where to implement it.

Sorry for the long post but any help would be greatly appreciated. I’m so impressed with the Arduino, it’s allowing me to try something I’ve always thought about.

Many thanks,

Kyle

typedef void (*SimplePatternList[])();

defines SimplePatternList as a new type of array of pointers to functions

SimplePatternList gPatterns = { sinelon, };

Creates gPatterns as such an array and initializes it with only one element (thus at position 0) which is the pointer to the function sinelon() that you have somewhere else in your code

Then in the loop() you do

gPatterns[gCurrentPatternNumber]();

Which calls the function at index gCurrentPatternNumber, stored in your array of functions. As gCurrentPatternNumber is 0 it basically calls sinelon() and then refreshes the leds

As you don’t change the value of gCurrentPatternNumber (and anyway you only have one entry in your array of functions) your loop() just keeps calling repetitively sinelon()

If you have a cyclon() function, you can either put that in the array instead if sinelon and that is the one which will be called or you can get rid of the typedef, the array altogether and instead of doing

gPatterns[gCurrentPatternNumber]();

Just do cyclon();

Instead of trimming down, erase everything in void loop and learn how to control one LED at a time.

Start with

led[0]=CRGB (255, 0,0);

This makes the first led red. The first 0 is the position of the led. It starts counting from 0. You only have 15 leds so individually control them all. After you feel like you've understood changing position and colors, you need to learn how to use a 'for loop' which is like one of the most important codes to understand in all of this coding.

Thanks a lot for the help guys!

I think it best to start with the very basics if you guys have the patience to teach me.

How’s this for turning on the first led:

#include “FastLED.h”

// How many leds in your strip?
#define NUM_LEDS 15

// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
#define DATA_PIN 6
#define CLOCK_PIN 13

// Define the array of leds
CRGB leds[NUM_LEDS];

void setup() {

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

}

void loop() {
// Turn the LED on
leds[0] = CRGB::Red;

}

How do I then move to the next led?

Thanks again,

Kyle

That's rocket science but I think you can do it :)

leds[1] = CRGB::Red;

Can you guess now how to acces the 3rd one ??

Don't forget to add

FastLED.show();

To display the changes you made in your leds array once you are done with some changes

Basically your loop can look like this

void loop()
{
  If (it is time to move lights around) {
       Mess around with the leds[] array 
       FastLED.show();
  }
}

Here is some relevant code to help you experiment

   leds[0] = CRGB(255,0,0); //Prepares the first led to be red
   leds[1] = CRGB(0,255,0); //Prepares the second led to be green
   leds[2] = CRGB(0,0,255); //Prepares the third led to be blue
   FastLED.show(); //This is when all the prepared stuff actually gets displayed on your led strip
   delay(1000); //Gives you a second to see the lights being on
   FastLED.showColor(CRGB::Black); //Turns off all leds before starting loop over, otherwise they would just stay on.

the numbers after CRGB are the values of red, blue, and green each led should display. You can change those numbers to experiment with colors. And as just mentioned, the number inside of after leds is how you pick which led in your string you’re going to pick the color for.

Trust me,

This is rocket science for me and I appreciate you guys having the patience for such a novice!

#include “FastLED.h”

// How many leds in your strip?
#define NUM_LEDS 3

// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
#define DATA_PIN 6
#define CLOCK_PIN 13

// Define the array of leds
CRGB leds[NUM_LEDS];

void setup() {

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

}

void loop() {
// Turn the LED on, then pause
leds[0] = CRGB::Red;
leds[1] = CRGB::Red;
leds[2] = CRGB::Red;
FastLED.show();
delay(500);
// Now turn the LED off, then pause
FastLED.showColor(CRGB::Black);
delay(500);
}

So my first three leds are flashing on and off. Whats the next step?

Thanks again guys

What do you want to do?

That’s a good question!

I’m basically achieving what I want already but I don’t know how to adapt/control it:

It’s great to begin to understand the basics so the next step for the last code I posted would be to ‘move’ the led. How do you turn off one and then turn the next one on, in sequence?

The code for the above video does exactly what I want but I don’t understand how it works:

void loop() {
colorWipe(0xff,0xa2,0x00, 40);
colorWipe(0xFF,0x00,0x00, 5);
}

void colorWipe(byte red, byte green, byte blue, int SpeedDelay) {
for(uint16_t i=0; i<NUM_LEDS; i++) {
setPixel(i, red, green, blue);
showStrip();
delay(SpeedDelay);
}
}
void showStrip() {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.show();
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
FastLED.show();
#endif
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.setPixelColor(Pixel, strip.Color(red, green, blue));
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
#endif
}

void setAll(byte red, byte green, byte blue) {
for(int i = 0; i < NUM_LEDS; i++ ) {
setPixel(i, red, green, blue);
}
showStrip();
}

I assume it’s this that’s doing most of the work:

void loop() {
colorWipe(0xff,0xa2,0x00, 40);
colorWipe(0xFF,0x00,0x00, 5);
}

void colorWipe(byte red, byte green, byte blue, int SpeedDelay) {
for(uint16_t i=0; i<NUM_LEDS; i++) {
setPixel(i, red, green, blue);
showStrip();
delay(SpeedDelay);

I don’t know what everything below this is doing.

I could just ask how to modify this to do what I want and you guys could fill bits in for me such as creating a delay between each ‘wipe’ or changing the initial state of the strip to red instead of ‘off’ but I won’t really learn anything.

Eventually, I need to combine this function with some simpler ones and they’ll all be button operated but I definitely needed to slow down and understand the basics!

Kyle

Read up on “for loops” until you understand every part of that line:
for(uint16_t i=0; i<NUM_LEDS; i++)

That is how you ‘move’ the led. You define a behavior you want for one led, such as turn it on and then off. Then the number of the led that you are on increases by 1, so that the next led does the same behavior, etc.

Don’t worry about the “uint16_t”, though, that could just as simply be an “int”, so figure out the parts of:

for(int i=0; i<NUM_LEDS; i++)

This is starting to make a bit more sense. I’ve had a look here:

https://www.arduino.cc/en/Reference/For

I’m still not sure about the structure of where it needs to be placed in the code. I’m struggling with the fundamentals of C++ I guess!

What’s missing from this code?:

#include “FastLED.h”

// How many leds in your strip?
#define NUM_LEDS 15

// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
#define DATA_PIN 6
#define CLOCK_PIN 13

// Define the array of leds
CRGB leds[NUM_LEDS];

void setup() {

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

}

void loop() {
// Turn the LED on, then pause
leds[0] = CRGB::Blue;
for(int i=0; i<NUM_LEDS; i++)
FastLED.show();

}

I am trying!

Hi,

You're getting close. Look at the for loop again and notice how the variable i is increased by increments of 1 (i++). That i variable is the thing to use as the index of your array: leds*. It goes inside the for loop.* best, Michael

Fixing a typo:

leds[i]

--Michael

P.S. Criminy that 5 minute wait to repost is a pain...

Hi guys,

Michael, I’m still not sure what you mean here. I’m sorry you have to spoon feed this to me!

Kyle

Dont use the quote tag to post code

It's frequent to use te letter i as an index in for loops and address into an array and the "array[ i ]" (if you don't have spaces around the letter i) will be interpreted as "turn the text that follows in italic" and that index won't appear so we won't understand the code and think there is an obvious issue there

Here is 3 times the same code, with the code tag, the TT tag and the quote tag

var = Leds[i]; // this text is not in italic
var = Leds[i]; // this text should not be in italic and you should see [ i ] next to Leds

var = Leds*; // this is a mess now, all is in italic and you don't see my [ i ] [/quote]* Long story short Use the code tag to post code...

Ok, thank you, good to know.

I expect there are still many issues with my simple code. I’ve been trying to find a tutorial on how to ‘move’ an led on a strip but I cant for some reason. Maybe going from a absolute beginner with coding to trying to control a single led strip is still too much of a leap but I’d like to persevere.

So here’s the code again:

#include "FastLED.h"

// How many leds in your strip?
#define NUM_LEDS 15

// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN.  For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
#define DATA_PIN 6
#define CLOCK_PIN 13

// Define the array of leds
CRGB leds[NUM_LEDS];

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

void loop() { 
  // Turn the LED on, then pause
  leds[0] = CRGB::Blue;
  for(int i=0; i<NUM_LEDS; i++)
  FastLED.show();
  
}

When I run this code, nothing happens on the strip so what’s missing from this? Sorry again Michael, I’m not sure what you meant.

Thanks again,

Kyle

Ah, I see what you mean about now! That being said, I don't have that in my code anyway I don't think? Maybe that's the problem? I'm making this a lot more difficult than it should be! Kyle

this sets the first led to blue

  leds[0] = CRGB::Blue;

then

  for(int i=0; i<NUM_LEDS; i++)  FastLED.show();

this calls FastLED.show(); NUM_LEDS times but you don’t change anything in the LEDs, so not much happens :slight_smile:

then you loop and you set again the first LED to blue and etc…

if you were to do something like this

void loop() { 
  // Turn the LED on, then pause
  for(int i=0; i<NUM_LEDS; i++) {
     leds[i] = CRGB(random(0, 255), random(0, 255), random(0, 255));  // random colors
  }
  FastLED.show();
  delay(100);
}

then what this does for each loop is update the leds array with random colors. The for loop will move between 0 and 14 and so each led gets a different random color. random(0, 255) returns a random number between 0 and 255 - so I set a random value for R, G and B) and then I call FastLED.show(); to display my colors and pause 100ms for you to see it and then I loop again and go create a new random arrangement etc…

makes sense?

Thanks a lot,

I’ve tried to read up some more about for loops and found this which has helped to explain things in the most basic way for me:

This is more basic than anyone here has time to do!

I see that I wasn’t defining i You’ve defined it as:

leds[i] = CRGB(random(0, 255), random(0, 255), random(0, 255));  // random colors

Is that right?

also, in my code, this part wasn’t really connected to anything:

leds[0] = CRGB::Blue;

Is that right?

So the code you gave fills the whole strip with a rainbow effect updating every 100ms. So now I need to add another for loop to turn off each led in turn? Or do we add another function within the first for loop? I’ll rewatch the above video which should help too and referring back to a previous code might help now I know a little more about for loops:

void loop() { 
  // Turn the LED on, then pause
  for(int i=0; i<NUM_LEDS; i++) {
     leds[i] = CRGB(random(0, 255), random(0, 255), random(0, 255));  // random colors
  }
  FastLED.show();
  delay(100);
}

In this example:

#include "FastLED.h"

// How many leds in your strip?
#define NUM_LEDS 64 

// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN.  For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806, define both DATA_PIN and CLOCK_PIN
#define DATA_PIN 7
#define CLOCK_PIN 13

// Define the array of leds
CRGB leds[NUM_LEDS];

void setup() { 
	Serial.begin(57600);
	Serial.println("resetting");
	LEDS.addLeds<WS2812,2,RGB>(leds,NUM_LEDS);
	LEDS.setBrightness(84);
}

void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } }

void loop() { 
	static uint8_t hue = 0;
	Serial.print("x");
	// First slide the led in one direction
	for(int i = 0; i < NUM_LEDS; i++) {
		// Set the i'th led to red 
		leds[i] = CHSV(hue++, 255, 255);
		// Show the leds
		FastLED.show(); 
		// now that we've shown the leds, reset the i'th led to black
		// leds[i] = CRGB::Black;
		fadeall();
		// Wait a little bit before we loop around and do it again
		delay(10);
	}
	Serial.print("x");

	// Now go in the other direction.  
	for(int i = (NUM_LEDS)-1; i >= 0; i--) {
		// Set the i'th led to red 
		leds[i] = CHSV(hue++, 255, 255);
		// Show the leds
		FastLED.show();
		// now that we've shown the leds, reset the i'th led to black
		// leds[i] = CRGB::Black;
		fadeall();
		// Wait a little bit before we loop around and do it again
		delay(10);
	}
}

is the fadeall(); part telling the leds to turn off in sequence?

Based on

void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } }

??

Thanks again guys!

You’ve defined it as:

Code: [Select]
leds = CRGB(random(0, 255), random(0, 255), random(0, 255)); // random colors
Is that right?
also, in my code, this part wasn’t really connected to anything:
Code: [Select]
leds[0] = CRGB::Blue;[/quote]
leds[i] tells the compiler you want to modify the ith element of the leds array (starting counting at 0). So if you have i as the element changing in a for loop, then it sets every element of the array.
In your code
leds[0] = CRGB::Blue;
Was just setting the first (index 0) led to blue.
If you want to turn them off so that there is blinking, yes you can add another loop after my delay to fill in all the LEDs with color black. I think there is a fill_solid function in the library doing that for you though. Check it out in the doc.
fadeall is a function as you can see that mess around with the LEDs