Multiple NeoPixel Led Strips

hi guys,

I have multiple led strips (WS2812B) and I'm having a hard time coding them.
Can anyone make a code that does 6 different effects on 6 different neopixel led strips?

Thanks!

What did you try ?

Not certain if this is what you were thinking of, it sort of stops the data stream. It dose give a neat effect on four channels with a fifth being the original signal. I only went to four as it matches the inputs of a standard AND gate. I found that fast_LED worked well unlike Neo_Pixels. Note* Red is a "analogWrite" and will give a very different look.

// using a positive AND gate with this code will disrupt the digital signal of a Fast_LED Arduino.
// A input of AND gate to the arduino with fast_LED running
// B input of AND gate to the arduino with "disrupter code" running.
// Y output of AND gate to the WS2812b.
// ws2812b will store the last code receved and hold it until signal returns

int ledcolor = 0;
int a = 3000; //this sets how long the stays one color or sequence for
int red = 5; //this sets the red led pin NOTE: it is analogWrite on digital pin, gives difrint effect.
int green = 8; //this sets the green led pin
int blue = 7; //this sets the blue led pin
int yellow = 6; //this sets the yellow led pin

void setup() { //this sets the output pins

pinMode(red, OUTPUT);
pinMode(green, OUTPUT);
pinMode(blue, OUTPUT);
pinMode(yellow, OUTPUT);

Serial.begin(9600);
}

void loop() {
int ledcolor = random(16); //this randomly selects a number between 0 and 15

Serial.print(ledcolor);

switch (ledcolor) {

case 0: //if ledcolor equals 0 then the led will turn red
analogWrite(red, HIGH);
delay(a);
analogWrite(red, LOW);
break;

case 1: //if ledcolor equals 1 then the led will turn green
digitalWrite(green, HIGH);
delay(a);
digitalWrite(green, LOW);
break;

case 2: //if ledcolor equals 2 then the led will turn blue
digitalWrite(blue, HIGH);
delay(a);
digitalWrite(blue, LOW);
break;

case 3: //if ledcolor equals 3 then the led will turn yellow
analogWrite(red, HIGH);
digitalWrite(green, HIGH);
delay(a);
analogWrite(red, LOW);
digitalWrite(green, LOW);
break;

case 4: //if ledcolor equals 4 then the led will turn cyan
analogWrite(red, HIGH);
digitalWrite(blue, HIGH);
delay(a);
analogWrite(red, LOW);
digitalWrite(blue, LOW);
break;

case 5: //if ledcolor equals 5 then the led will turn red
digitalWrite(yellow, HIGH);
delay(a);
digitalWrite(yellow, LOW);

case 6: //if ledcolor equals 6 then the led will turn magenta
digitalWrite(green, HIGH);
digitalWrite(blue, HIGH);
delay(a);
digitalWrite(green, LOW);
digitalWrite(blue, LOW);
break;

case 7: //if ledcolor equals 7 then the led will turn white 3 on
analogWrite(red, HIGH);
digitalWrite(green, HIGH);
digitalWrite(blue, HIGH);
delay(a);
analogWrite(red, LOW);
digitalWrite(green, LOW);
digitalWrite(blue, LOW);
break;

//4 led new

case 8: //if ledcolor equals 8 then the led will turn cyan
analogWrite(red, HIGH);
digitalWrite(blue, HIGH);
digitalWrite(yellow, HIGH);
delay(a);
digitalWrite(yellow, LOW);
analogWrite(red, LOW);
digitalWrite(blue, LOW);
break;

case 9: //if ledcolor equals 9 then the led will turn magenta
digitalWrite(green, HIGH);
digitalWrite(blue, HIGH);
delay(a);
digitalWrite(green, LOW);
digitalWrite(blue, LOW);
break;

case 10: //if ledcolor equals 10 then the led will turn 3 on
analogWrite(red, HIGH);
digitalWrite(green, HIGH);
digitalWrite(blue, HIGH);
digitalWrite(yellow, HIGH);
delay(a);
digitalWrite(yellow, LOW);
analogWrite(red, LOW);
digitalWrite(green, LOW);
digitalWrite(blue, LOW);
break;

case 11: //if ledcolor equals 11 then the led will turn 3 on
analogWrite(red, HIGH);
digitalWrite(green, HIGH);
digitalWrite(yellow, HIGH);
delay(a);
analogWrite(red, LOW);
digitalWrite(green, LOW);
digitalWrite(yellow, LOW);
break;

case 12: //if ledcolor equals 12 then the led will turn white 3 on
analogWrite(red, HIGH);
digitalWrite(yellow, HIGH);
digitalWrite(blue, HIGH);
delay(a);
analogWrite(red, LOW);
digitalWrite(yellow, LOW);
digitalWrite(blue, LOW);
break;

case 13: //if ledcolor equals 13 then the led will turn white
digitalWrite(yellow, HIGH);
digitalWrite(green, HIGH);
digitalWrite(blue, HIGH);
delay(a);
digitalWrite(yellow, LOW);
digitalWrite(green, LOW);
digitalWrite(blue, LOW);
break;

case 14: //if ledcolor equals 14 then the led will turn 4 on
analogWrite(red, HIGH);
digitalWrite(green, HIGH);
digitalWrite(blue, HIGH);
digitalWrite(yellow, HIGH);
delay(a);
analogWrite(red, LOW);
digitalWrite(green, LOW);
digitalWrite(blue, LOW);
digitalWrite(yellow, LOW);
break;

case 15: //if ledcolor equals 15 then the led will turn 4 on
analogWrite(red, HIGH);
digitalWrite(green, HIGH);
digitalWrite(blue, HIGH);
digitalWrite(yellow, HIGH);
delay(a);
analogWrite(red, LOW);
digitalWrite(green, LOW);
digitalWrite(blue, LOW);
digitalWrite(yellow, LOW);
}

}

Thank you for your contribution, but please go and read the forum instructions so that you can go back and modify your original post (not re-post it) - using the "More -> Modify" option below the right hand corner of your post - to mark up your code as such using the "</>" icon in the posting window. Just highlight each section of code (or output if you need to post that) from the IDE and click the icon.

In fact, the IDE has a "copy for forum" link to put these markings on a highlighted block for you so you then just paste it here in a posting window. But even before doing that, don't forget to use the "Auto-Format" (Ctrl-T) option first to make it easy to read. If you do not post it as "code" it can as you now see, be quite garbled and is always more difficult to read.

It is inappropriate to attach it as a ".ino" file unless it is clearly too long to include in the post proper. People can usually see the mistakes directly and do not want to have to actually load it in their own IDE. And that would also assume they are using a PC and have the IDE running on that PC.

Your use of blank space is not bad. Do use blank lines, but only between complete functional blocks.

Knight_Sun:
Not certain if this is what you were thinking of, it sort of stops the data stream. It dose give a neat effect on four channels with a fifth being the original signal. I only went to four as it matches the inputs of a standard AND gate. I found that fast_LED worked well unlike Neo_Pixels. Note* Red is a "analogWrite" and will give a very different look.

...
...

I'm not sure how your solution relates to addressable led strips. Am I missing something?

The main problem you are going to have with running six different effects on six different neopixel strips is that the code for generating the effects cannot be blocking. Each time through loop() you will need to check if it is time to update an individual neopixel strip, and if it is then you update the LED pattern for that particular strip, then continue on checking to see if the other strips need updating. You cannot sit in a 'while' or 'for' loop, or use delay(), to generate the effect for any particular strip, because that will prevent updating the others.

Yes that is right.
Here is an example of running two strips with two patterns at the same time.

// using a state machine to drive two patterns on two strings at the same time
// By Mike Cook Jan 2019
// see https://github.com/FastLED/FastLED/wiki/Multiple-Controller-Examples for full discussion

#include "FastLED.h"

#define PIN_FOR_1   6 // pin connected to NeoPixels strip 1
#define PIN_FOR_2   7 // pin connected to NeoPixels strip 2
#define NUM_LEDS1 5   // number of LEDs in strip 1
#define NUM_LEDS2 6   // number of LEDs in strip 1
#define NUM_STRIPS  2 // how many strips you have

CRGB strip1[NUM_LEDS1];
CRGB strip2[NUM_LEDS2];

CLEDController *controllers[NUM_STRIPS];

// how often each pattern updates
unsigned long pattern1Interval  = 400;
unsigned long pattern2Interval  = 900;
// for millis() when last update occurred
unsigned long lastUpdateP1 = 0;
unsigned long lastUpdateP2 = 0;  
// state variables for patterns
int p1State = 0 ; 
int p2State = 0 ;
uint8_t gBrightness = 255;

void setup() {
   controllers[0] = &FastLED.addLeds<WS2812,PIN_FOR_1>(strip1, NUM_LEDS1);
   controllers[1] = &FastLED.addLeds<WS2812,PIN_FOR_2>(strip2, NUM_LEDS2);
   // wipes the LED buffers
    wipe1(0,0,0); 
    wipe2(0,0,0);
}

void loop(){
if(millis() - lastUpdateP1 > pattern1Interval) updatePattern1();
if(millis() - lastUpdateP2 > pattern2Interval) updatePattern2();
}

// Note both patterns are essentially the same sort of display for simplicity - change to suite
void updatePattern1(){ // pattern 1 a walking red led
   strip2[p1State].setRGB(128,0,0); // turn on next led in pattern
   int lastLed = p1State -1;        // find LED to turn off
   if (lastLed < 0) {               // wrap round count
      lastLed = NUM_LEDS1 -1;
   }
   strip1[lastLed] = 0x00;     // turn off last LED we set
   p1State ++;                 // move on state variable for the next time we enter this
   if(p1State >= NUM_LEDS1){   // wrap round the state
    p1State = 0;
   }
   controllers[0]->showLeds(gBrightness); // update display
   lastUpdateP1 = millis();               // to calculate next update
}

void updatePattern2(){ // pattern 2 a walking green LED
   strip2[p2State].setRGB(0,128,0); // turn on next led in pattern  
   int lastLed = p2State -1;        // find LED to turn off
   if (lastLed < 0) {               // wrap round count if needed
      lastLed = NUM_LEDS2 -1;
   }
   strip2[lastLed] = 0x00;    // turn off last LED we set
   p2State ++;                // move on state variable for the next time we enter this
   if(p2State >= NUM_LEDS2){  // wrap round the state
    p2State = 0;
   }
   controllers[1]->showLeds(gBrightness);  // update display
   lastUpdateP2 = millis();                // to calculate next update
}

void wipe1(byte r,byte g, byte b){
     for(int i=0;i<NUM_LEDS1;i++){
       strip1[i].setRGB(r,g,b);
       }
}

void wipe2(byte r,byte g, byte b){
     for(int i=0;i<NUM_LEDS2;i++){
       strip2[i].setRGB(r,g,b);
       }
}

Note these are just simple patterns to illustrate mainly the way of achieving the switching between the two. More complex patterns would still have to be implemented as a state machine.

Also note that the code could be made more compact but it is spread out so that it is easier to follow.

Grumpy_Mike:
Yes that is right.
Here is an example of running two strips with two patterns at the same time.

// using a state machine to drive two patterns on two strings at the same time

// By Mike Cook Jan 2019
// see Multiple Controller Examples · FastLED/FastLED Wiki · GitHub for full discussion

#include "FastLED.h"

#define PIN_FOR_1   6 // pin connected to NeoPixels strip 1
#define PIN_FOR_2   7 // pin connected to NeoPixels strip 2
#define NUM_LEDS1 5   // number of LEDs in strip 1
#define NUM_LEDS2 6   // number of LEDs in strip 1
#define NUM_STRIPS  2 // how many strips you have

CRGB strip1[NUM_LEDS1];
CRGB strip2[NUM_LEDS2];

CLEDController *controllers[NUM_STRIPS];

// how often each pattern updates
unsigned long pattern1Interval  = 400;
unsigned long pattern2Interval  = 900;
// for millis() when last update occurred
unsigned long lastUpdateP1 = 0;
unsigned long lastUpdateP2 = 0;  
// state variables for patterns
int p1State = 0 ;
int p2State = 0 ;
uint8_t gBrightness = 255;

void setup() {
  controllers[0] = &FastLED.addLeds<WS2812,PIN_FOR_1>(strip1, NUM_LEDS1);
  controllers[1] = &FastLED.addLeds<WS2812,PIN_FOR_2>(strip2, NUM_LEDS2);
  // wipes the LED buffers
   wipe1(0,0,0);
   wipe2(0,0,0);
}

void loop(){
if(millis() - lastUpdateP1 > pattern1Interval) updatePattern1();
if(millis() - lastUpdateP2 > pattern2Interval) updatePattern2();
}

// Note both patterns are essentially the same sort of display for simplicity - change to suite
void updatePattern1(){ // pattern 1 a walking red led
  strip2[p1State].setRGB(128,0,0); // turn on next led in pattern
  int lastLed = p1State -1;        // find LED to turn off
  if (lastLed < 0) {               // wrap round count
     lastLed = NUM_LEDS1 -1;
  }
  strip1[lastLed] = 0x00;     // turn off last LED we set
  p1State ++;                 // move on state variable for the next time we enter this
  if(p1State >= NUM_LEDS1){   // wrap round the state
   p1State = 0;
  }
  controllers[0]->showLeds(gBrightness); // update display
  lastUpdateP1 = millis();               // to calculate next update
}

void updatePattern2(){ // pattern 2 a walking green LED
  strip2[p2State].setRGB(0,128,0); // turn on next led in pattern  
  int lastLed = p2State -1;        // find LED to turn off
  if (lastLed < 0) {               // wrap round count if needed
     lastLed = NUM_LEDS2 -1;
  }
  strip2[lastLed] = 0x00;    // turn off last LED we set
  p2State ++;                // move on state variable for the next time we enter this
  if(p2State >= NUM_LEDS2){  // wrap round the state
   p2State = 0;
  }
  controllers[1]->showLeds(gBrightness);  // update display
  lastUpdateP2 = millis();                // to calculate next update
}

void wipe1(byte r,byte g, byte b){
    for(int i=0;i<NUM_LEDS1;i++){
      strip1[i].setRGB(r,g,b);
      }
}

void wipe2(byte r,byte g, byte b){
    for(int i=0;i<NUM_LEDS2;i++){
      strip2[i].setRGB(r,g,b);
      }
}




Note these are just simple patterns to illustrate mainly the way of achieving the switching between the two. More complex patterns would still have to be implemented as a state machine.

Also note that the code could be made more compact but it is spread out so that it is easier to follow.

I realize this thread is over a year old, however my question relates specifically to the code GrumpyMike posted at the end (the bit that is quoted here hopefully). So it seemed to make more sense to reply here, but if moderators would prefer i start a new thread just let me know!

So I stumbled upon this thread in my quest to control three strips of neopixels independently via commands sent from serial data. Even though there is so much information out there about state machines and all things pixels, I was having a hard time putting it together. Then I found this thread, specifically GrumpyMike's code that demonstrates a simple example for using state machine to drive aninmations on two strips. Great!

So I took that code, added a third strip, no biggie. Then tried to add the ability to control the animations via single byte commands sent via serial monitor....and here is where things get sticky. ..

In keeping with the example code from GrumpyMike, I kept the simple one led chaser dot pattern for each strip, with each strip starting r, g, b respectively. I then duplicated these functions, one for each strip, changing the color of the led dot. Thus when sending for example 'A' from serial monitor, the intended result would be that strip1 would change from red dot chaser, to yellow dot chaser - something that is easily verifiable upon correct implementation right?

Well, thats not quite what happens with the code after I modified it. Instead of changing animation sequences from red dot chaser to yellow dot chaser, it appears as if each time i send the command to change the animation, it simply adds the second animation on top of the existing animation...each and every time. So when you start with a single red led dot moving down the length of the strip, each time you send the command to change this animation to the one with a single yellow dot, it adds the yellow chaser sequence on top of the exisiting one...if i press it 10 times.. i end up with what appears to be 10 concurrent animations happening on the same strip at the same time.

(post continued in next post due to exceeding character limit..)

(continued from above...)

This makes sense since I know the code i have is lacking the necessary steps to clear the buffer after each time, or check it or whatever. This is where my coding skills are lacking and while i have an idea of what is missing, I really don't know how i would actually go about implementing it in the sketch.

From my understanding, what I need is:

  • some sort of way to check if the animation for a given strip needs to be updated based on any new serial data that may have been sent.
  • If it has, I need to stop the current animation before being able to update the strip with the new animation.
  • once old animation stopped, update strip with new animation
  • do this for each next strip
  • if no new data sent that requires animation to be changed, keep doing the old animation until data recieved that says otherwise

I don't know if what i'm saying makes sense, so apologies if I am being unclear. I'm new to programming and still learning how to describe the process, so bear with me.

// using a state machine to drive two patterns on two strings at the same time
// By Mike Cook Jan 2019
// see https://github.com/FastLED/FastLED/wiki/Multiple-Controller-Examples for full discussion

#include <FastLED.h>

#define PIN_FOR_1   6  // pin connected to NeoPixels strip 1
#define PIN_FOR_2   5  // pin connected to NeoPixels strip 2
#define PIN_FOR_3   3  // pin connected to NeoPixels strip 3

#define NUM_LEDS1 50   // number of LEDs in strip 1
#define NUM_LEDS2 50   // number of LEDs in strip 2
#define NUM_LEDS3 50   // number of LEDs in strip 3

#define NUM_STRIPS  3  // how many strips you have

CRGB strip1[NUM_LEDS1];
CRGB strip2[NUM_LEDS2];
CRGB strip3[NUM_LEDS3];

CLEDController *controllers[NUM_STRIPS];

// how often each pattern updates
unsigned long pattern1Interval  = 300;
unsigned long pattern2Interval  = 300;
unsigned long pattern3Interval  = 300;

unsigned long pattern11Interval  = 300;
unsigned long pattern22Interval  = 300;
unsigned long pattern33Interval  = 300;

// for millis() when last update occurred
unsigned long lastUpdateP11 = 0;
unsigned long lastUpdateP22 = 0;
unsigned long lastUpdateP33 = 0;

unsigned long lastUpdateP1 = 0;
unsigned long lastUpdateP2 = 0;
unsigned long lastUpdateP3 = 0;
  
// state variables for patterns
int p1State = 0;
int p2State = 0;
int p3State = 0;

int p11State = 0;
int p22State = 0;
int p33State = 0;

uint8_t gBrightness = 255;

void setup() {
   Serial.begin(9600);
   
   controllers[0] = &FastLED.addLeds<WS2811,PIN_FOR_1>(strip1, NUM_LEDS1);
   controllers[1] = &FastLED.addLeds<WS2811,PIN_FOR_2>(strip2, NUM_LEDS2);
   controllers[2] = &FastLED.addLeds<WS2811,PIN_FOR_3>(strip3, NUM_LEDS3);
   
   Serial.println("ready");
   // wipes the LED buffers
    wipe1(0,0,0);
    wipe2(0,0,0);
    wipe3(0,0,0);
}

void loop(){
  readData();
}

// Note both patterns are essentially the same sort of display for simplicity - change to suite

void updatePattern1(){              // pattern 1 a walking red led
   strip1[p1State].setRGB(128,0,0); // turn on next led in pattern
   int lastLed = p1State -1;        // find LED to turn off
   if (lastLed < 0) {               // wrap round count
      lastLed = NUM_LEDS1 -1;
   }
   strip1[lastLed] = 0x00;          // turn off last LED we set
   p1State ++;                      // move on state variable for the next time we enter this
   if(p1State >= NUM_LEDS1){        // wrap round the state
    p1State = 0;
   }
   controllers[0]->showLeds(gBrightness);   // update display
   lastUpdateP1 = millis();                 // to calculate next update
}
void updatePattern11(){
  strip1[p11State].setRGB(128,128,0);
  int lastLed = p11State -1;
  if (lastLed < 0) {
    lastLed = NUM_LEDS1-1;
  }
  strip1[lastLed] = 0x00;
  p11State ++;
  if(p11State >= NUM_LEDS1){
    p11State = 0;
  }
  controllers[0]->showLeds(gBrightness);
  lastUpdateP11 = millis();
}
void updatePattern2(){              // pattern 2 a walking green LED
   strip2[p2State].setRGB(0,128,0); // turn on next led in pattern  
   int lastLed = p2State -1;        // find LED to turn off
   if (lastLed < 0) {               // wrap round count if needed
      lastLed = NUM_LEDS2 -1;
   }
   strip2[lastLed] = 0x00;          // turn off last LED we set
   p2State ++;                      // move on state variable for the next time we enter this
   if(p2State >= NUM_LEDS2){        // wrap round the state
    p2State = 0;
   }
   controllers[1]->showLeds(gBrightness);  // update display
   lastUpdateP2 = millis();                // to calculate next update
}
void updatePattern22(){
  strip2[p22State].setRGB(128,128,0);
  int lastLed=p22State-1;
  if (lastLed <0) {
    lastLed=NUM_LEDS2-1;
  }
  strip2[lastLed] = 0x00;
  p22State++;
  if(p22State>=NUM_LEDS2){
    p22State = 0;
  }
  controllers[1]->showLeds(gBrightness);
  lastUpdateP22= millis();
}
void updatePattern3(){              // pattern 3 a walking blue led
  strip3[p3State].setRGB(0,0,128);  // turn on next led in pattern
  int lastLed = p3State -1;         // find Led to turn off
  if (lastLed < 0) {                // wrap round count if needed
    lastLed = NUM_LEDS3 -1;
  }
  strip3[lastLed] = 0x00;           // turn off last led we set
  p3State ++;                       // move on state variable for the next time we enter this
  if (p3State >= NUM_LEDS3){        // wrap round the state
    p3State =  0;
  }
  controllers[2]->showLeds(gBrightness);   // update display
  lastUpdateP3 = millis();                 // to calculate next update
}
void updatePattern33(){
  strip3[p33State].setRGB(128,0,128);
  int lastLed = p33State -1;
  if(lastLed<0){
    lastLed = NUM_LEDS3-1;
  }
  strip3[lastLed]=0x00;
  p33State ++;
  if (p33State >=NUM_LEDS3){
    p33State = 0;
  }
  controllers[2]->showLeds(gBrightness);
  lastUpdateP33=millis();
}
void wipe1(byte r,byte g, byte b){
     for(int i=0;i<NUM_LEDS1;i++){
       strip1[i].setRGB(r,g,b);
       }
}
void wipe2(byte r,byte g, byte b){
     for(int i=0;i<NUM_LEDS2;i++){
       strip2[i].setRGB(r,g,b);
       }
}
void wipe3(byte r,byte g, byte b){
    for(int i=0;i<NUM_LEDS3;i++){
      strip3[i].setRGB(r,g,b);
      }
}

void readData(){
  int incomingByte = 0;
  if (Serial.available() > 0) {
    incomingByte = Serial.read();
    if (incomingByte == 'A') {
      updatePattern1();
    }
    if (incomingByte =='a') {
      updatePattern11();
    }
    if (incomingByte =='B') {
      updatePattern2();
    }
    if (incomingByte == 'b') {
      updatePattern22();
    }
    if (incomingByte == 'C'){
      updatePattern3();
    }
    if (incomingByte =='c'){
      updatePattern33(); 
    }
  }
  if(millis() - lastUpdateP1 > pattern1Interval) updatePattern1();
  if(millis() - lastUpdateP2 > pattern2Interval) updatePattern2(); 
  if(millis() - lastUpdateP11 > pattern11Interval) updatePattern11();
  if(millis() - lastUpdateP22 > pattern22Interval) updatePattern22(); 
  if(millis() - lastUpdateP3 > pattern3Interval) updatePattern3();
  if(millis() - lastUpdateP33 > pattern33Interval) updatePattern33();
}

In your read data function when a serial command comes in you should not call update the pattern but should use the wipe function to clear the pattern data out of that pattern’s buffer.

But then your code still has both the pattern and the alternative pattern being run at the same time.
What you need is to have a flag ( Boolean variable ) for each pattern that says if it should be running. You use that flag in the if statement that checks if it is time to refresh the pattern to see if it should be running at all. You do this with a compound if statement. That is one that checks two things and is only true if both are true, the two statements are joined together in this way by using the && operation.

Then when you change the pattern as a result of the serial read you set the flag to true and the corresponding alternate pattern’s flag to false as well as wiping the buffer. Also reset the pattern’s state variable here.

Hope that helps.

Grumpy_Mike:
In your read data function when a serial command comes in you should not call update the pattern but should use the wipe function to clear the pattern data out of that pattern’s buffer.

But then your code still has both the pattern and the alternative pattern being run at the same time.
What you need is to have a flag ( Boolean variable ) for each pattern that says if it should be running. You use that flag in the if statement that checks if it is time to refresh the pattern to see if it should be running at all. You do this with a compound if statement. That is one that checks two things and is only true if both are true, the two statements are joined together in this way by using the && operation.

Then when you change the pattern as a result of the serial read you set the flag to true and the corresponding alternate pattern’s flag to false as well as wiping the buffer. Also reset the pattern’s state variable here.

Hope that helps.

Yes!!! Thank you for taking the time to provide your guidance Mike. I was able to implement your suggestions and successfully accomplish my goal of driving three strips independently of each other based on commands sent via serial monitor.

With the basic functionality done, would you mind suggesting ways in which the code could be made more compact? As it is, the code is written out in an easy to follow, but very verbose fashion. I'm interested in learning how to write code more efficiently, I guess take my skills to the next level. Either way, thanks again for your help!

state-machine-tresComas-SERIAL.ino (8.91 KB)

I'm interested in learning how to write code more efficiently

So see all those variables with nearly the same name. You want to use an array and use the index of the array to specify the variable, then you can address each one with one line and a for loop.

So for example:-

// how often each pattern updates
unsigned long pattern1Interval  = 300;
unsigned long pattern2Interval  = 300;
unsigned long pattern3Interval  = 300;

unsigned long pattern11Interval  = 300;
unsigned long pattern22Interval  = 300;
unsigned long pattern33Interval  = 300;

could be just

unsigned long patternInterval [6];
for(int i=0; i<6; i++) patternInterval [i]= 300;
unsigned long patternInterval [6];

for(int i=0; i<6; i++) patternInterval [i]= 300;

probably a stupid question...but having trouble figuring out where to put this in the code...

Nevermind...figured it out. Let's go ahead and call that a brain fart :wink:

Tried doing the same with lastUpdate...but i'm getting an error:

"Assignment of read-only lcoation *(lastUpdate + 9)"
and,..
"invalid operands of types 'long unsigned int' and 'void(int)' to binary 'operator-'"

void lastUpdate() {
  unsigned long lastUpdate[12];
  for (int i=0; i<12; i++) {
    lastUpdate[i]=0;
  }
}


//.............then at end of readData():
if((millis() -  lastUpdate[0] > patternInterval[0]) && (newData1 == true)) updatePattern1(); // for [0]-[11]

pointers are my achilles man...

suggestions?

You will need to post your full updated code. I also suggest that you don't use the same name for functions and variables.

And this does absolutely nothing

void lastUpdate() {
  unsigned long lastUpdate[12];
  for (int i = 0; i < 12; i++) {
    lastUpdate[i] = 0;
  }
}

You create an array (and initialise it) that will go out of scope at the moment that the function ends.

probably a stupid question...but having trouble figuring out where to put this in the code...

unsigned long patternInterval [6];

is a declaration it goes outside any function definition, it is best to put it just above the first function.

for(int i=0; i<6; i++) patternInterval [i]= 300;

Initialises that array so this goes in the setup function.

And this:-

if((millis() -  lastUpdate[0] > patternInterval[0]) && (newData1 == true)) updatePattern1(); // for [0]-[11]

The whole point about arrays is that you use the index in a loop, while there might be occasions where you address the array index with a fixed constant this is not one of those places.
Needs the newData1 variable to be an array. What is more you need a better name than that because it is not describing what it is doing. Maybe you think it is which shows you have not "got" what you are trying to do. I would suggest the name "patternEnable". This is where you can change an array element with a constant, but only in the routine that sets what is running in response to a serial input.

The "updatePattern1 ( )" should also be an array probably called just "updatePattern" and yes it needs initialising with pointers to the functions.

 void (*updatePattern[])(void) = {   
  pattern0,pattern1 , pattern3, // ... and so on up to 10
};

This should be placed at the end of the code when all the functions have been defined
so that line should read:-

for(int i=0; i<11; i++){
if((millis() -  lastUpdate[i] > patternInterval[i]) && (patternEnable[i] == true)) updatePattern[i](); // for [0]-[11]
}

However, why is this running from 0 to 11? If that is want you want then all the arrays need to be 11 elements long. If not you don't get an error message but you do get areas of memory providing data that are set by other variables. This leads to very odd run time behaviors that are almost impossible to track down.

Grumpy_Mike:

unsigned long patternInterval [6];

is a declaration it goes outside any function definition, it is best to put it just above the first function.

for(int i=0; i<6; i++) patternInterval [i]= 300;

I tried some version of this as a declaration initially, but I must have stated something incorrectly hence I ended up making a function with it. I'll go back and declare it properly.

And this:-

if((millis() -  lastUpdate[0] > patternInterval[0]) && (newData1 == true)) updatePattern1(); // for [0]-[11]

The whole point about arrays is that you use the index in a loop, while there might be occasions where you address the array index with a fixed constant this is not one of those places.
Needs the newData1 variable to be an array. What is more you need a better name than that because it is not describing what it is doing. Maybe you think it is which shows you have not "got" what you are trying to do. I would suggest the name "patternEnable". This is where you can change an array element with a constant, but only in the routine that sets what is running in response to a serial input.

The "updatePattern1 ( )" should also be an array probably called just "updatePattern" and yes it needs initialising with pointers to the functions.

 void (*updatePattern[])(void) = {   

pattern0,pattern1 , pattern3, // ... and so on up to 10
};

For whatever reason I'm having a hard time understanding where you can address an array with a fixed constant, and where you can't. This is part of the reason I'm doing this project - figured it would be a good way to tackle learning how to work with arrays.

Looking at the code I knew that most of the repetitive variable declarations could be replaced with arrays of some sort, so I started at the top and intended to work my way down..guess I didn't make it very far did I ? :slight_smile:

As for naming, since there was so many similarly named variables, I went through and renamed them to make it easy to identify what was what when scanning through the code. Having a bunch of variables with "pattern" in the name was making it difficult to easily pick out the ones I was looking for. But I understand the importance of naming variables with names that indicate what they're used for. Thank you for pointing that out.

Because everything in this sketch could be made into a million arrays (exaggerating), it became overwhelming and confusing with regards to knowing where to start.

This should be placed at the end of the code when all the functions have been defined
so that line should read:-

for(int i=0; i<11; i++){

if((millis() -  lastUpdate[i] > patternInterval[i]) && (patternEnable[i] == true)) updatePatterni; // for [0]-[11]
}



However, why is this running from 0 to 11? If that is want you want then all the arrays need to be 11 elements long.

I ended up adding a couple more patterns yesterday, and since I hadn't yet tidy'd everything up into nice little arrays, it meant that each pattern had to be defined for each of the three strips..which came out to 12, or 0-11. Needless to say...the need for repackaging everything in an array became very, very, very apparent lol. Anyway, I'm going to take a step back, remove the extra patterns and work through the code to implement your suggestions. Thanks for the detailed response, and patience... :slight_smile:

I'm having a hard time understanding where you can address an array with a fixed constant, and where you can't.

You can always address an array with both. What you mean is where you should and where you shouldn’t.
If you always use a constant to address an array then it is a waste of time having one in the first place.

It is difficult and you are making great strides. Well done.