FastLED Controlling Two Strips with Their Own Patterns and Buttons

Hello I'm trying to control two separate LED strips from one Arduino, each strip has it's own button and set of patterns to cycle through.

I follow the Scott Marley FastLED tutorial (specifically, FastLED Basics Episode 5 - Multiple patterns using a timer or button), so I understand how to get the patterns to run when they are uploaded individually. My idea was to add a "_0" and "_1" version of all the variables that needed them and add my two separate patterns.

It seems to get hung up on:

error: 'nextPattern_1' was not declared in this scope
btn_1.attachClick(nextPattern_1);

I can seem to find anything wrong with format at that point.

Am I thinking about this wrong?

Thanks in advance!

#include <FastLED.h>
#include <OneButton.h>

#define NUM_LEDS_PER_STRIP  18
#define BTN_PIN_0  3       
#define BTN_PIN_1  5
#define LED_PIN_0  2
#define LED_PIN_1  4

CRGB leds[NUM_LEDS_PER_STRIP];

uint8_t patternCounter_0 = 0;
uint8_t patternCounter_1 = 0;

OneButton btn_0(BTN_PIN_0, true, true);
OneButton btn_1(BTN_PIN_1, true, true);

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN_0, GRB>(leds, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<WS2812B, LED_PIN_1, GRB>(leds, NUM_LEDS_PER_STRIP);
  Serial.begin(57600);

  btn_0.attachClick(nextPattern_0);
  btn_1.attachClick(nextPattern_1);
}

void loop_0() {
  
  switch (patternCounter_0) {
    case 0:
      movingDots();
      break;
    case 1:
      rainbowBeat();
      break;
    case 2:
      redWhiteBlue();
      break;
  }

  FastLED.show();
  btn_0.tick();
}

  void loop_1() {
   switch (patternCounter_1) {
    case 0:
      brightness_lv1();
      break;
    case 1:
      brightness_lv2();
      break;
    case 2:
      brightness_lv3();
      break;
  }
  
  FastLED.show();
  btn_1.tick();
}

void nextPattern_0() {
  patternCounter_0 = (patternCounter_0 + 1) % 3;           // Change the number after the % to the number of patterns you have

void nextPattern_1() {
  patternCounter_1 = (patternCounter_1 + 1) % 3;           // Change the number after the % to the number of patterns you have
}

//------- Put your patterns below -------//
///---Underglow---///
void movingDots() {
  
  uint16_t posBeat  = beatsin16(30, 0, NUM_LEDS - 1, 0, 0);
  uint16_t posBeat2 = beatsin16(60, 0, NUM_LEDS - 1, 0, 0);

  uint16_t posBeat3 = beatsin16(30, 0, NUM_LEDS - 1, 0, 32767);
  uint16_t posBeat4 = beatsin16(60, 0, NUM_LEDS - 1, 0, 32767);

  // Wave for LED color
  uint8_t colBeat  = beatsin8(45, 0, 255, 0, 0);

  leds[(posBeat + posBeat2) / 2]  = CHSV(colBeat, 255, 255);
  leds[(posBeat3 + posBeat4) / 2]  = CHSV(colBeat, 255, 255);

  fadeToBlackBy(leds, NUM_LEDS, 10);
  FastLED.setBrightness(50);
}


void rainbowBeat() {
  
  uint16_t beatA = beatsin16(30, 0, 255);
  uint16_t beatB = beatsin16(20, 0, 255);
  fill_rainbow(leds, NUM_LEDS, (beatA+beatB)/2, 8);
  FastLED.setBrightness(50);
}


void redWhiteBlue() {

  uint16_t sinBeat   = beatsin16(30, 0, NUM_LEDS - 1, 0, 0);
  uint16_t sinBeat2  = beatsin16(30, 0, NUM_LEDS - 1, 0, 21845);
  uint16_t sinBeat3  = beatsin16(30, 0, NUM_LEDS - 1, 0, 43690);

  leds[sinBeat]   = CRGB::Blue;
  leds[sinBeat2]  = CRGB::Red;
  leds[sinBeat3]  = CRGB::White;
  
  fadeToBlackBy(leds, NUM_LEDS, 10);
  FastLED.setBrightness(50);
}


///---Merch Light---///
void brightness_lv1() {
  
  fill_solid(leds, NUM_LEDS, CRGB::Red);
  FastLED.show();
  FastLED.setBrightness(50);
}


void brightness_lv2() {
  
  fill_solid(leds, NUM_LEDS, CRGB::Red);
  FastLED.show();
   FastLED.setBrightness(25);
}


void brightness_lv3() {

  fill_solid(leds, NUM_LEDS, CRGB::Red);
  FastLED.show();
   FastLED.setBrightness(0);
}

You forgot the closing } for nextPatter_0
after line 63I think.

1 Like

Your next error is to do with NUM_LEDS_PER_STRIP and NUM_LEDS.
That error is impossible to happen if intellisense is turned on and you use the kbd shortcut for 'Trigger Suggest'. On my Mac it's as depicted in the screen grab, Win and *nix will be similar. Try just typing NUM_LED then ^ space.

1 Like

Awe, I could have stared at that for a million years. Thank you!

To run with two strips individually, you need a two separate leds arrays in this line:

You also need to rewrite all your pattern methods so that they can work with the selected array.

That's a bad idea that will make your code twice as long as it should be. You should use array variables.

Rather than

int myVariable_1;
int myVariable_2;

...

Serial.print(myVariable_1);
Serial.print(myVariable_2);

you can write

int myVariable[2];

...

for (byte b=0; b<2; b++) {
  Serial.print(myVariable[b]);
}
1 Like

Ok, I'm working on wrapping my head around PaulRB's code suggestion, I'm very much unseasoned. That being said I was able to clean up the code and compile it. My issue now is I can only get the "underglow" pattern on the first strip to run, the "Merch Light" pattern on the second strip does not light up.

I don't think there is anything wrong with my wiring I included a tinkercad with the basic idea.
Things to note:

  • I have a 12v 30a power supply with three outputs
  • output 1 and 2 have buck converters, set to 5v that go to each LED strip
  • output 3 is to the Arduino (barrel jack)
  • tinkercad's power supply doesn't have a ground so I put it on the negative

I'm unsure of what part of the code is not allowing the second strip to light.

Thanks again!

#include <FastLED.h>
#include <OneButton.h>

#define NUM_LEDS   18
#define BTN_PIN_0  3       
#define BTN_PIN_1  5
#define LED_PIN_0  2
#define LED_PIN_1  7

CRGB leds_0[NUM_LEDS];
CRGB leds_1[NUM_LEDS];

uint8_t patternCounter_0 = 0;
uint8_t patternCounter_1 = 0;

OneButton btn_0(BTN_PIN_0, true, true);
OneButton btn_1(BTN_PIN_1, true, true);

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN_0, GRB>(leds_0, NUM_LEDS);
  FastLED.addLeds<WS2812B, LED_PIN_1, GRB>(leds_1, NUM_LEDS);
//  Serial.begin(57600);

  btn_0.attachClick(nextPattern_0);
  btn_1.attachClick(nextPattern_1);
}

void loop() {
  
  switch (patternCounter_0) {
    case 0:
      movingDots();
      break;
    case 1:
      rainbowBeat();
      break;
    case 2:
      redWhiteBlue();
      break;
  }

  FastLED.show();
  btn_0.tick();
}

  void loop_0() {
   switch (patternCounter_1) {
    case 0:
      brightness_lv1();
      break;
    case 1:
      brightness_lv2();
      break;
    case 2:
      brightness_lv3();
      break;
  }
  
  FastLED.show();
  btn_1.tick();
}

void nextPattern_0() {
  patternCounter_0 = (patternCounter_0 + 1) % 3;           // Change the number after the % to the number of patterns you have
}

void nextPattern_1() {
  patternCounter_1 = (patternCounter_1 + 1) % 3;           // Change the number after the % to the number of patterns you have
}

//------- Put your patterns below -------//

///---Underglow---///
void movingDots() {
  
  uint16_t posBeat  = beatsin16(30, 0, NUM_LEDS - 1, 0, 0);
  uint16_t posBeat2 = beatsin16(60, 0, NUM_LEDS - 1, 0, 0);

  uint16_t posBeat3 = beatsin16(30, 0, NUM_LEDS - 1, 0, 32767);
  uint16_t posBeat4 = beatsin16(60, 0, NUM_LEDS - 1, 0, 32767);

  // Wave for LED color
  uint8_t colBeat  = beatsin8(45, 0, 255, 0, 0);

  leds_0[(posBeat + posBeat2) / 2]  = CHSV(colBeat, 255, 255);
  leds_0[(posBeat3 + posBeat4) / 2]  = CHSV(colBeat, 255, 255);

  fadeToBlackBy(leds_0, NUM_LEDS, 10);
  FastLED.setBrightness(50);
}


void rainbowBeat() {
  
  uint16_t beatA = beatsin16(30, 0, 255);
  uint16_t beatB = beatsin16(20, 0, 255);
  fill_rainbow(leds_0, NUM_LEDS, (beatA+beatB)/2, 8);
  FastLED.setBrightness(50);
}


void redWhiteBlue() {

  uint16_t sinBeat   = beatsin16(30, 0, NUM_LEDS - 1, 0, 0);
  uint16_t sinBeat2  = beatsin16(30, 0, NUM_LEDS - 1, 0, 21845);
  uint16_t sinBeat3  = beatsin16(30, 0, NUM_LEDS - 1, 0, 43690);

  leds_0[sinBeat]   = CRGB::Blue;
  leds_0[sinBeat2]  = CRGB::Red;
  leds_0[sinBeat3]  = CRGB::White;
  
  fadeToBlackBy(leds_0, NUM_LEDS, 10);
  FastLED.setBrightness(50);
}


///---Merch Light---///
void brightness_lv1() {
  
  fill_solid(leds_1, NUM_LEDS, CRGB::Red);
  FastLED.show();
  FastLED.setBrightness(50);
}


void brightness_lv2() {
  
  fill_solid(leds_1, NUM_LEDS, CRGB::Red);
  FastLED.show();
   FastLED.setBrightness(25);
}


void brightness_lv3() {

  fill_solid(leds_1, NUM_LEDS, CRGB::Red);
  FastLED.show();
   FastLED.setBrightness(0);
}

loop_0 is never executed hence anything it invokes as well. You will need to rewrite loop and loop_0 so they work together.

2 Likes

Ok I think I have everything in place, however when I cycle through with btn_1 for the "Merch Light" patterns on leds_1, the brightness of the LED strip on leds_0 is is being effected (dimming). any ideas?

Thanks

#include <FastLED.h>
#include <OneButton.h>

#define NUM_LEDS   18
#define BTN_PIN_0  3       
#define BTN_PIN_1  5
#define LED_PIN_0  2
#define LED_PIN_1  4
#define FAN_PIN    7

CRGB leds_0[NUM_LEDS];
CRGB leds_1[NUM_LEDS];

uint8_t patternCounter_0 = 0;
uint8_t patternCounter_1 = 0;

// For breathing effect
static float pulseSpeed = 1;  // Larger value gives faster pulse.

uint8_t hueA = 15;  // Start hue at valueMin.
uint8_t satA = 230;  // Start saturation at valueMin.
float valueMin = 120.0;  // Pulse minimum value (Should be less then valueMax).

uint8_t hueB = 95;  // End hue at valueMax.
uint8_t satB = 255;  // End saturation at valueMax.
float valueMax = 255.0;  // Pulse maximum value (Should be larger then valueMin).

uint8_t hue = hueA;  // Do Not Edit
uint8_t sat = satA;  // Do Not Edit
float val = valueMin;  // Do Not Edit
uint8_t hueDelta = hueA - hueB;  // Do Not Edit
static float delta = (valueMax - valueMin) / 2.35040238;  // Do Not Edit

// Brightness settings for patterns
uint8_t brightness_0 = 50;  // Initial brightness for leds_0
uint8_t brightness_1 = 50;  // Initial brightness for leds_1

// For changing colors on btn_0 press
uint8_t colorCounter_0 = 0;
const CRGB colors_0[] = {CRGB::White, CRGB::Green, CRGB::Blue, CRGB::Red, CRGB::Orange};

// For changing colors on btn_1 press
uint8_t colorCounter_1 = 0;
const CRGB colors_1[] = {CRGB::Red, CRGB::White};

//for heartbeat
uint8_t bloodHue = 96;  // Blood color [hue from 0-255]
uint8_t bloodSat = 255;  // Blood staturation [0-255]
int flowDirection = -1;   // Use either 1 or -1 to set flow direction
uint16_t cycleLength = 1200;  // Lover values = continuous flow, higher values = distinct pulses.
uint16_t pulseLength = 200;  // How long the pulse takes to fade out.  Higher value is longer.
uint16_t pulseOffset = 200;  // Delay before second pulse.  Higher value is more delay.
uint8_t baseBrightness = 0;  // Brightness of LEDs when not pulsing. Set to 0 for off.

OneButton btn_0(BTN_PIN_0, true, true);
OneButton btn_1(BTN_PIN_1, true, true);

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN_0, GRB>(leds_0, NUM_LEDS);
  FastLED.addLeds<WS2812B, LED_PIN_1, GRB>(leds_1, NUM_LEDS);

  btn_0.attachClick(nextPattern_0);
  btn_1.attachClick(nextPattern_1);
  btn_0.attachDoubleClick(changeColor_0); // Attach double-click action for btn_0
  btn_1.attachDoubleClick(changeColor_1); // Attach double-click action for btn_1

  pinMode (FAN_PIN,OUTPUT);

}

void loop() {

digitalWrite(FAN_PIN, HIGH);

  // Handle patterns for leds_0
  switch (patternCounter_0) {
    case 0:
      solidColor();
      break;
    case 1:
      breath();
      break;
    case 2:
      heartBeat();
      break;
    case 3:
      off();
      break;
  }

  btn_0.tick();
  
  // Handle patterns for leds_1
  switch (patternCounter_1) {
    case 0:
      merch_lv1();
      break;
    case 1:
      merch_lv2();
      break;
    case 2:
      merch_lv3();
      break;
  }
  
  FastLED.show();
  btn_1.tick();
}

void nextPattern_0() {
  patternCounter_0 = (patternCounter_0 + 1) % 4; // Change the number after % to the number of patterns you have
}

void nextPattern_1() {
  patternCounter_1 = (patternCounter_1 + 1) % 3; // Change the number after % to the number of patterns you have
}

void changeColor_0() {
  // Change color for leds_0 on double-click
  colorCounter_0 = (colorCounter_0 + 1) % (sizeof(colors_0) / sizeof(colors_0[0]));
  fill_solid(leds_0, NUM_LEDS, colors_0[colorCounter_0]);
}

void changeColor_1() {
  colorCounter_1 = (colorCounter_1 + 1) % (sizeof(colors_1) / sizeof(colors_1[0]));
  fill_solid(leds_1, NUM_LEDS, colors_1[colorCounter_1]);
}

//------- Put your patterns below -------//

///---Underglow---///
void solidColor() {
  fill_solid(leds_0, NUM_LEDS, colors_0[colorCounter_0]); // Change this to cycle through colors
  FastLED.setBrightness(brightness_0);
  FastLED.show();
}

void breath() {
 float dV = ((exp(sin(pulseSpeed * millis()/2000.0*PI)) -0.36787944) * delta);
  val = valueMin + dV;
  hue = map(val, valueMin, valueMax, hueA, hueB);  // Map hue based on current val
  sat = map(val, valueMin, valueMax, satA, satB);  // Map sat based on current val

    // Set hue and saturation to achieve white
    uint8_t hue = 0;  // Hue doesn't matter for white
    uint8_t sat = 0;  // Saturation must be 0 for white

  for (int i = 0; i < NUM_LEDS; i++) {
    leds_0[i] = CHSV(hue, sat, val);

    // You can experiment with commenting out these dim8_video lines
    // to get a different sort of look.
    leds_0[i].r = dim8_video(leds_0[i].r);
    leds_0[i].g = dim8_video(leds_0[i].g);
    leds_0[i].b = dim8_video(leds_0[i].b);
  }
  FastLED.setBrightness(brightness_0);
  FastLED.show();
}

void heartBeat() {
  for (int i = 0; i < NUM_LEDS ; i++) {
    uint8_t bloodVal = sumPulse( (5/NUM_LEDS/2) + (NUM_LEDS/2) * i * flowDirection );
    leds_0[i] = CHSV( bloodHue, bloodSat, bloodVal );
  }
  FastLED.setBrightness(brightness_0);
  FastLED.show();
}

int sumPulse(int time_shift) {
  //time_shift = 0;  //Uncomment to heart beat/pulse all LEDs together
  int pulse1 = pulseWave8( millis() + time_shift, cycleLength, pulseLength );
  int pulse2 = pulseWave8( millis() + time_shift + pulseOffset, cycleLength, pulseLength );
  return qadd8( pulse1, pulse2 );  // Add pulses together without overflow
}

uint8_t pulseWave8(uint32_t ms, uint16_t cycleLength, uint16_t pulseLength) {
  uint16_t T = ms % cycleLength;
  if ( T > pulseLength) return baseBrightness;
  uint16_t halfPulse = pulseLength / 2;
  if (T <= halfPulse ) {
    return (T * 255) / halfPulse;  //first half = going up
  } else {
    return((pulseLength - T) * 255) / halfPulse;  //second half = going down
  }
}

void off() {
  fill_solid(leds_0, NUM_LEDS, CRGB::Black);
  FastLED.setBrightness(brightness_0);
  FastLED.show(); 
}

///---Merch Light---///
void merch_lv1() {
  fill_solid(leds_1, NUM_LEDS, colors_1[colorCounter_1]); // Change this to cycle through colors
  FastLED.setBrightness(brightness_1);
  FastLED.show();
}

void merch_lv2() {
  fill_solid(leds_1, NUM_LEDS, colors_1[colorCounter_1]);
  FastLED.setBrightness(brightness_1 / 3);  // Example for lower brightness
  FastLED.show();
}

void merch_lv3() {
  fill_solid(leds_1, NUM_LEDS, CRGB::Black);
  FastLED.setBrightness(0);
  FastLED.show();
}

Try wiring the power supply directly to the +/- of the LED strips. The breadboard might be shaky with 1A (1080mA = 18LEDs*60ma/LED)

That's the weird thing, I have a 12v 30a power supply with three outputs. Output 1 and 2 have buck converters regulating to 5v and output 3 is for the Arduino. Everything is also grounded to the same rail on the breadboard.

that's why I though it might be something in the code I'm overlooking.

Also, put a 1000uF capacitor across VCC and GND on the LED strips.

Ok, not sure which would be the correct way, Left or Right? I tested both.
Note: In reality my power supply has a ground, so I attach ground to the neg on the power supply in the Tinkercad.

Either way I'm still getting the brightness drop, I'm thinking it could be the LED strips themselves.

Do you mean the choosing between a two GND pins of the Uno? It doesn't matter

Left. Capacitor across VCC and GND of the WS2812 strip with a 470ohm resistor between Arduino data pin and WS2812 data in.

1 Like