2 effects on one strip 1 pin

If I have 20 pixels on a ws2812b led strip, can I program something for the first, say, 6 pixels (I'm calling the LEDs pixels for now) , and something else on the rest of the strip, to run independently? Or am I a dreamer and should have put a second data line in my model?

Yes

You can also have more than 1 (one) strip.

Sure, the pixels are numbered 0…n, so you can set up any pattern or animation in your array, then refresh as often as you need.

Limitations are memory, power to the LESs, and the maximum refresh allowed by the WS28xx chips.

Too late, it is already installed into the model. If wore comes to worst, I can add another data line. I think

Jim Smagata
647-890-4397
Freelance Tech Theatre Services

That’s reasonable.

Cut the trace on the strip and use 28AWG (16 strand) silicone insulated wire to the data input side.

What's the problem with doing what you first proposed?

Yeah, that is all in software. You can do absolutely anything with any pixel, they are completely independently programmable. Since they are indexed by number in software, that is the key to partitioning them. Usually that is done with "offsets". So if you had some routine that ran on LEDS 0-5, you can just add 5 and it will do the same pattern on LEDs 5-12.

BTW, Jim, hi neighbor in GTA!

The problem is, I was trying different ways of addressing the pixels I wanted, but I just couldn't seem to get them to work separately- one usually joined the other. I'm just not experienced enough. I just wanted to have some reassurance that it can be done. Pictured: Here's the thing. 0 to 4-breathing red (maybe, if I can figure it out, a little amber mixing action). 5-static white. 6-24 - programmed for a few things that go with a button press. Light up, flash, light off. This last part I got, I just need to figure how to tell it to only address the last 19 pixels instead of NUM_LEDS.
Nacelle_lighting|690x179


Please upload pictures to the forum, don't post external links unnecessarily.

Please post your code, the version where you tried to achieve what you wanted but were unable to make it work. Describe what you wanted and what actually happened. Please auto-format the code and post it using code tags.

Yes it can be done but this is best done by using a state machine so that each animation can run at its own speed. This is a step up in programming for a beginner and is based on the Blink Without Delay example in the IDE.

Here is some code I wrote for doing just what you wanted

// Multiple patterns in a state machine format
// using the FastLED library
// by Mike Cook 2017

#include "FastLED.h"

// first set up the parameters to use in the pattern calling
unsigned long patternInterval [] = { 500, 40, 20, 200, 5 }; // how often each pattern updates
unsigned long lastUpdate [5] ;  // for millis() when last update occurred
boolean patternEnabled [] = {true,true,false,true,true}; // should the pattern be called at all
byte patternState[5]; // state machine variable for patterns - this initialises them to zero

// now set up the LEDs to use
#define NUM_LEDS 64
#define DATA_PIN 3
#define CLOCK_PIN 13


CRGB leds[NUM_LEDS];

// Constants for patterns
// for Fire2012
#define COOLING  20
#define SPARKING 50
#define COLOR_ORDER BGR

// now set up the array of pointers to each pattern
void (*patternPtrs[5])(int index,byte state); //the array of pattern pointers

void setup() {
  //initialises the array of pattern pointers
  patternPtrs[0] = blinkOne; 
  patternPtrs[1] = cylon;
  patternPtrs[2] = fire;
  patternPtrs[3] = colorWipe;
  patternPtrs[4] = rainbowCycle;
  //initialises the FastLED driver you want
  //FastLED.addLeds<APA102,leds, NUM_LEDS); // 13 clock  and 11 data
  FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, BGR>(leds, NUM_LEDS); // 13 clock  and 11 data
  FastLED.setBrightness(8);
}

void loop() {
  for(int i = 0; i<5; i++) { // go through all the patterns and see if it is time to call one
    if(patternEnabled[i] && millis() - lastUpdate[i] > patternInterval[i]){
      lastUpdate[i] = millis();
      callPatterns(i, patternState[i]);
    }
  }
}

void callPatterns(int index, byte state) {
  (*patternPtrs[index])(index,state); //calls the pattern at the index of `index` in the array
}

// These are the pattern functions written as a state machine
// this is the Blink program in FastLED's example folder
void blinkOne(int index,byte state) {
  if(state == 0){
    leds[3] = CRGB::Blue;
    FastLED.show();
    patternState[index] = 1; // move on the state machine for the next call
  }
  if(state == 1){
     leds[3] = CRGB::Black;
     FastLED.show();
     patternState[index] = 0;
   }
  }

// this is the Cylon program in FastLED's example folder
// we will use LEDs 8 to 15 to show this
void cylon(int index,byte state) {
  static int i = 8; // replaces the loop index
  if(state == 0){
    leds[i] = CRGB::Red;
    FastLED.show();
    patternState[index] = 1; // move on the state machine for the next call
  }
   if(state == 1){
    // now that we've shown the leds, reset the i'th led to black
    leds[i] = CRGB::Black;
    i++; // increment what was the loop variable
    if(i >= 16){ // we have finished one direction
     patternState[index] = 2;
     i--;
    }
    else {
    patternState[index] = 0;
    }
   }
   // Now go in the other direction only green
   if(state == 2){
     leds[i] = CRGB::Green;
    FastLED.show();
    patternState[index] = 3; // move on the state machine for the next call
   }
  if(state == 3){
    // now that we've shown the leds, reset the i'th led to black
    leds[i] = CRGB::Black;
    i--; // decrement what was the loop variable
    if(i < 8){ // we have finished the return, go back to the start
     patternState[index] = 0;
     i= 8; // ready to start again
    }
    else {
    patternState[index] = 2;
    } 
    // note that this could be better implemented but it has been written like this to keep it close to the original example
    // so you can see what changes have been made 
  }
}

// this is the Fire2012 program in FastLED's example folder
void fire(int index,byte state) {
// using LEDs 16 to 32
// Array of temperature readings at each simulation cell
  const byte startLED = 16; // first LED in section
  const byte numLEDs = 16;
  static byte heat[numLEDs];

  random16_add_entropy( random());
  // Step 1.  Cool down every cell a little
    for( int i = 0; i < numLEDs; i++) {
      heat[i] = qsub8( heat[i],  random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
    }
  
    // Step 2.  Heat from each cell drifts 'up' and diffuses a little
    for( int k= numLEDs - 1; k >= 2; k--) {
      heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
    }
    
    // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
    if( random8() < SPARKING ) {
      int y = random8(7);
      heat[y] = qadd8( heat[y], random8(160,255) );
    }

    // Step 4.  Map from heat cells to LED colors
    for( int j = 0; j < numLEDs; j++) {
        leds[j+startLED] = HeatColor( heat[j]); // transfer heat array to LEDs
    }
    FastLED.show(); // display this frame
  }

//colorWipe  modified from Adafruit example to make it a state machine
// uses LEDs 32 to 40
void colorWipe(int index,byte state) {
  static int i =0; // used as state variable
  static byte firstLED = 32;
  static byte numLEDs = 8;
    leds[i+firstLED] = CRGB::Yellow;
    FastLED.show();
    i++;
  if(i >= numLEDs){
    i = 0;
    for(int j;j<numLEDs; j++) leds[j+firstLED] = CRGB::Black; // blank out strip
  }
}

 // rainbowCycle modified from Adafruit example to make it a state machine
 // uses LEDs 48 to 64
void rainbowCycle(int index,byte state) {
  static uint16_t j=0; // used as state variable
  static byte firstLED = 48;
  static byte numLEDs = 16;
    for(int i=0; i< numLEDs; i++) {
      leds[i+firstLED].setHSV( (((i * 256 / numLEDs) + j) & 255), 255, 255);
    }
    FastLED.show();
    j++;
    if(j >= 256*5) j=0;
}

Note this example is for the APA102 type addressable strip. If you are using another type then just call the correct initialiser for your type of LED in the setup function.

Thanks. I will.

That's a lot to take in, and thanks. I'll go over this carefully so I can try to understand it all, as I, admittedly, am still learning.

Yes it is I do appreciate this, but this is why I wrote the code in the first place. If there are any bits you don't understand what they are doing then please ask.

For a simplified view of a state machine

See my
http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html
Or Robin2's several things at once
http://forum.arduino.cc/index.php?topic=223286.0

If this is all you want to do then post the code (in code tags) and we can probably tell you an easer way of doing it than a state machine.

Note read
how to get the best out of this forum to learn about posting code here in code tags.

Another trick is to use the CPixelView class from the FastLED library. It allows you to "break" a single physical LED strip into multiple logical strips. The library handles the index offsets for you.

Let say you have 25 LEDs total and want the first logical strip to access physical LEDs 0-5 and the second logical strip to access physical LEDs 6-24:

#include <Arduino.h>
#include <FastLED.h>

const uint8_t ledCount = 25;
const uint8_t startGroup0 = 0;
const uint8_t lengthGroup0 = 6;
const uint8_t startGroup1 = 6;
const uint8_t lengthGroup1 = 19;
const uint8_t ledPin = 3;

CRGB leds[ledCount];
CPixelView<CRGB> group0(leds, startGroup0, lengthGroup0);
CPixelView<CRGB> group1(leds, startGroup1, lengthGroup1);

void setup() {
	FastLED.addLeds<WS2812, ledPin, RGB>(leds, ledCount);

}

So then, you'd update the first group using group0[0] - group0[5] and update the second group using group1[0] - group1[18]. Again, the library will take care of offsetting into the full 'leds' array for you.

After updating all your patterns, FastLED.show() actually writes the new data (i.e. colors) to the entire physical strip at one time.

1 Like

WHATTHEHECK!! That sounds like just the thing.

I was going to upload the code I was trying to get to work, but because none did, I didn't save any. I can still upload the main sketch that I would have to modify for this. We'll see.

Thank you.

Are there any more documentation or examples I can use to see how to incorporate this?
Idealy, I want, at the push of a button, a fade in and effect on group 1, steady on group 2 ( a single pixel) and another effect (counting up to a fill of the rest of the pixels) in sequence. And then at the 4th push of the same button (using cases) the reverse happens.

I have them as separate elements, but I am not sure how to use this setup for my project.

Aside from the actual FastLED source code (where I found these constructs) I'm not aware of any, but I haven't really looked. You might try Googling around.

:ok_hand: :vulcan_salute: :+1:

I just noticed a slight error in the example code I provided. The CPixelView objects should be created as:

CPixelView<CRGB> group0(leds + startGroup0, lengthGroup0);
CPixelView<CRGB> group1(leds + startGroup1, lengthGroup1);

Anyway, you can find the class definition Here.

1 Like