2 Arrays on 1 strip Neopixel Library

Hi first post so I hope I get this right. This is my first project with multiple LED strips and effects. I have coded this project after lots of searching on here but I am a little stuck on two parts.

Hardware - Adafruit Feather M4 express, 2 neopixels strips, push to break button.

Context - I want a button to be pushed which will 'load' an LED onto a LED (strip2), the loaded LED pulses with the button case. Around the button there is also an LED (strip1) which pulses on the button case. After 3 seconds if there are more than 5 LEDs lite the group shoots down the strip to a panel. The panel then fills up with the number of LEDs. The process repeats until the panel is full which then triggers another effect.

The plan was to code strip2 into two arrays to control the effects on them, but I am unsure how to do this or if this is the right thing to do?

The other issues is the pulsing 'load' effect shows on the strip when the chase effect is running.

I will be adding more strips and effects to this project so I would like to minimize the amount of pins used if possible but please advise. Total LED strips is looking like 8 for the finished project, I have the multiplexing board for the feather, but this is with the plan to run one strip as an array with 2 effects running on it.

#include <Adafruit_NeoPixel.h>

const byte Strip1PIN = 6; //  pin strip 1 is connected to
const byte Strip2PIN = 12; //  pin strip 2 is connected to

volatile int IRQcount = 1; // defines a volatile variable called IRQcount
int pin = 5; //attached to pin5
int pin_irq = 5; //IRQ that matches to pin 


#define Strip1PIXELS  49 //number of pixels in strip 1
#define Strip2PIXELS  50  // number of pixels in strip 2

Adafruit_NeoPixel Strip1(Strip1PIXELS, Strip1PIN, NEO_GRB + NEO_KHZ800); // defines type of neopixel strip, pixels and pins for strip 1
Adafruit_NeoPixel Strip2(Strip2PIXELS, Strip2PIN, NEO_GRB + NEO_KHZ800); // defines type of neopixel strip, pixels and pins for strip 2


int counter;

int i = IRQcount; //varialbe called i which is equal to IRQcount



int Strip1dir = 1; //number of which to change the brightness by in each loop of pulsing effect for strip 1
int Strip1bright = 20; // brightness variable for pulsing effect

int Strip2dir = 1; //number of which to change the brightness by in each loop of pulsing effect for strip 2
int Strip2bright = 20; // brightness variable for neopixel effect



// Time periods of blinks in milliseconds (1000 to a second).
const unsigned long Strip1interval = 10;
const unsigned long Strip2Effect1interval = 10;
const unsigned long Strip2Effect2interval = 10;
const unsigned long CheckIRQCountinterval = 3000;
const unsigned long Strip2Effect1clearinterval = CheckIRQCountinterval; //not sure if this is needed as it just equals another variable 

// Variable holding the timer value so far. One for each "Timer"
unsigned long Strip1timer;
unsigned long Strip2Effect1timer;
unsigned long Strip2Effect2timer;
unsigned long CheckIRQCounttimer;
unsigned long Strip2Effect1cleartimer;

void setup () 
  {
  Strip1.begin(); // INITIALIZE NeoPixel Strip1
   Strip2.begin(); // INITIALIZE NeoPixel Strip2
   Strip1.clear(); // clear strip 1
   Strip2.clear(); // clear strip 2
  Strip1timer = millis (); //set timer equal to count in millis
  Strip2Effect1timer = millis ();//set timer equal to count in millis
  Strip2Effect2timer = millis ();//set timer equal to count in millis
   attachInterrupt(pin_irq, IRQcounter, RISING);       // defines the interrupt count when the pin goes high
  Serial.begin(9600);
  }  // end of setup

void IRQcounter() // 
{
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 50ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 50) 
{
  IRQcount++; //add 1 to the IRQcount
 }
  last_interrupt_time = interrupt_time; //reset timer
}

void Strip1Effect ()
  {
 uint32_t bluefade = Strip1.ColorHSV(43650,255,Strip1bright); // defines bluefade effect
 Strip1.fill(bluefade,0,49); //fills strip with blue fade effect instance
 Strip1.show(); // send blue fade to the stip
 Strip1bright = Strip1bright + Strip1dir; // change brightness by dir which is 1 or -1
 if(Strip1bright > 100 || Strip1bright < 20) Strip1dir = Strip1dir * -1; // if brightness goes outside or range (100-20) change 'direction' of fade


  // remember when we last updated strip
  Strip1timer = millis ();  
  }  // end of Strip1 effect 

void Strip2Effect1 ()
  {
  uint32_t otherfade = Strip2.ColorHSV(13650,255,Strip2bright); // defines othercolour effect for strip 2
 Strip2.fill(otherfade,0,IRQcount); //fills strip with other fade effect instance
 Strip2.show(); // send other fade to the stip
 Strip2bright = Strip2bright + Strip2dir; // change brightness of strip 2 brightness variable by 1?
 if(Strip2bright > 100 || Strip2bright < 20) Strip2dir = Strip2dir * -1; // if strip 2 brightness goes outside or range (100-20) change 'direction' of fade

{
if ( (millis () - Strip2Effect1cleartimer) >= Strip2Effect1clearinterval){ //code to reset load effect after Strip2Effect1clearinterval
  Strip2.clear(); // clear strip
  IRQcount = 1; // set IRQcount back to 1
  Strip2Effect1cleartimer=millis(); //reset effect timer
}
}

  // remember when we last updated strip
  Strip2Effect1timer = millis ();  
  }

void Strip2Effect2(uint32_t c =Strip2.ColorHSV(13650))
  {
    if (IRQcount >= 5){//if 5 of more pixels are 'loaded' do the below
   if ( (millis () - CheckIRQCounttimer) >= CheckIRQCountinterval){ // scheduling for chase effect below
     
      if (i<Strip2.numPixels()+IRQcount) i++;  { // logic test if i is less than the number of pixels in strip 2 + varialbe IRQ count then add 1 to variable i
      Strip2.setPixelColor(i, c); // Draw new pixel with colour c
      Strip2.setPixelColor(i-IRQcount, 0); // Erase pixel IRQcount number back 
      Strip2.show(); // sent info to strip to display
     
      if (i==Strip2.numPixels()+IRQcount){ // if the effect has finished do the below
        CheckIRQCounttimer=millis()- (Strip2Effect2interval *Strip2.numPixels()); //reset the checkIRQ timer to current time - the time it take to do the chase effect
     IRQcount = 1 ; // set IRQcount to 1
     i=1; //set i to 1
     Strip2.clear(); //clear strip of any previous effects
      }
  }
   }

Strip2Effect2timer = millis(); // set effect timer to current counter in millis
        }
  
  }
 
void loop ()
  {
//IRQcount = 6;// for testing without physical interrupt button '//' out for actual
  
  if ( (millis () - Strip1timer) >= Strip1interval)// scheduling for strip 1 effect
     Strip1Effect ();

  
 if ( (millis () - Strip2Effect1timer) >= Strip2Effect1interval) // scheduling for strip 2 effect 1
    Strip2Effect1 ();
  
  
 
  if ( (millis () - Strip2Effect2timer) >= Strip2Effect2interval) // scheduling for strip 2 effect 1
    Strip2Effect2(); 
      
     
 
}  // end of loop
  1. Is there a reason you are not simply chaining each strip from the end of the other (for data - of course power needs to be injected into the strips every 50 LEDs or so)?

  2. Why would you use an interrupt to monitor the button? Why would you respond on "RISING" since the button should be connected between an input and ground?

Thank you for the reply

  1. No reason apart from I was unsure how to code a single strip into different arrays of different lengths. There will be quiet a lot of LEDs overall, 3500+ Would that be an issue.

  2. It is left over from an earlier iteration of the code when I was having issues with blocking as I was not using scheduling. Would it be better to move it into the main loop as an if statement? The button is a push to break emergency stop button - apologies I should have mentioned this in the hardware in post 1.

I seem to recall there are Feather versions with plenty of RAM for LEDs and the M4 does have plenty.

It is however 3.3 V so you should use a 74HCT14 Hex inverter to convert the output to 5 V logic to drive NeoPixels.

Once you write non-blocking code - as you seem to from a cursory inspection - you should have no problem polling the button in the loop.

An "Emergency Stop" button should need no de-bouncing as once pressed, it waits for something else to start the process up again. :+1:

Thanks, it is a non latching e stop button so does bounce quite badly due to the size of the components.

So if I just use one strip with several arrays is it more simple than multiple strips with multiple arrays?

Any tips for the issues shown in the photo where strip2effect1 is still showing but is frozen on a certain brightness(start of the strip) while strip2effect 2 is running which is the chase.

You code continues to call all your "effect" functions every time through loop() based on elapsed time. If you don't want effect1 on strip2 while it is doing effect2, you need to set up a state machine and keep track of what you are doing and use that variable to decide to call effect1 or effect2.

Also, arrays start with index 0, not 1, so things should get set back to 0.

Finally, this code

if (i < Strip2.numPixels() + IRQcount) i++; { // logic test if i is less than the number of pixels in strip 2 + varialbe IRQ count then add 1 to variable i

will increment i outside the array bounds. Luckily for you, the Adafruit library checks all its indices and doesn't allow them to wander. You should fix your code and not rely on libraries to protect you.

Thank you for the tips, I'm just trying to write some code for a state machine.

If I reset the IRQcount to 0 the whole led strip lights up rather than just the first pixel.

I think I understand, are you saying i will continue to increase greater than the number of pixels in the LED strip and I should bound it to a max value?

exactly. You should never attempt to access an array outside its bounds. Strip2 has numPixels() in it which means you can access 0..numPixels()-1, inclusive. If you are trying to light of IRQcount number of pixels as a chase or similar, then i needs to be within [0, numPixels()-IRQcount]

Thanks for the tip, I have only had time to try out the state machine which is now working and will try the arrays and limit for the variable at the weekend.

I have a bit of tidying up to do with the code but thought I would post the result so far.

#include <Adafruit_NeoPixel.h>

const byte Strip1PIN = 6; //  pin strip 1 is connected to
const byte Strip2PIN = 12; //  pin strip 2 is connected to

volatile int IRQcount = 1; // defines a volatile variable called IRQcount
int pin = 5; //attached to pin5
int pin_irq = 5; //IRQ that matches to pin 


#define Strip1PIXELS  49 //number of pixels in strip 1
#define Strip2PIXELS  50  // number of pixels in strip 2

Adafruit_NeoPixel Strip1(Strip1PIXELS, Strip1PIN, NEO_GRB + NEO_KHZ800); // defines type of neopixel strip, pixels and pins for strip 1
Adafruit_NeoPixel Strip2(Strip2PIXELS, Strip2PIN, NEO_GRB + NEO_KHZ800); // defines type of neopixel strip, pixels and pins for strip 2


int counter;

int i = IRQcount ; //varialbe called i which is equal to IRQcount



int Strip1dir = 1; //number of which to change the brightness by in each loop of pulsing effect for strip 1
int Strip1bright = 20; // brightness variable for pulsing effect

int Strip2dir = 1; //number of which to change the brightness by in each loop of pulsing effect for strip 2
int Strip2bright = 20; // brightness variable for neopixel effect

int  Strip2Effect2state = LOW ;



// Time periods of blinks in milliseconds (1000 to a second).
const unsigned long Strip1interval = 5;
const unsigned long Strip2Effect1interval = 5;
const unsigned long Strip2Effect2interval = 50;
const unsigned long CheckIRQCountinterval = 3000;
const unsigned long Strip2Effect1clearinterval = 3000;
//const unsigned long Timefrompushinterval = 3000; // variable for resetting strip 2 effect a certain tiome after first button push needs coding in

// Variable holding the timer value so far. One for each "Timer"
unsigned long Strip1timer;
unsigned long Strip2Effect1timer;
unsigned long Strip2Effect2timer;
unsigned long CheckIRQCounttimer;
unsigned long Strip2Effect1cleartimer;
//unsigned long Strip2Effect2state;
//unsigned long Timefrompushtimer;

void setup () 
  {
  Strip1.begin(); // INITIALIZE NeoPixel Strip1
   Strip2.begin(); // INITIALIZE NeoPixel Strip2
   Strip1.clear(); // clear strip 1
   Strip2.clear(); // clear strip 2
  Strip1timer = millis (); //set timer equal to count in millis
  Strip2Effect1timer = millis ();//set timer equal to count in millis
  Strip2Effect2timer = millis ();//set timer equal to count in millis
 CheckIRQCounttimer = millis ();
   attachInterrupt(pin_irq, IRQcounter, RISING);       // defines the interrupt count when the pin goes high
  Serial.begin(9600);
  Strip2Effect2state = LOW;
  }  // end of setup

void IRQcounter() // 
{
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 50ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 50) 
{
  IRQcount++; //add 1 to the IRQcount

 }
  last_interrupt_time = interrupt_time; //reset timer
}

void Strip1Effect ()
  {
 uint32_t bluefade = Strip1.ColorHSV(43650,255,Strip1bright); // defines bluefade effect
 Strip1.fill(bluefade,0,49); //fills strip with blue fade effect instance
 Strip1.show(); // send blue fade to the stip
 Strip1bright = Strip1bright + Strip1dir; // change brightness by dir which is 1 or -1
 if(Strip1bright > 200 || Strip1bright < 20) Strip1dir = Strip1dir * -1; // if brightness goes outside or range (100-20) change 'direction' of fade


  // remember when we last updated strip
  Strip1timer = millis ();  
  }  // end of Strip1 effect 

void Strip2Effect1 ()
  {
     if (Strip2Effect2state == LOW){
      
  uint32_t otherfade = Strip2.ColorHSV(13650,255,Strip2bright); // defines othercolour effect for strip 2
 Strip2.fill(otherfade,0,IRQcount); //fills strip with other fade effect instance
 Strip2.show(); // send other fade to the stip
 Strip2bright = Strip2bright + Strip2dir; // change brightness of strip 2 brightness variable by 1?
 if(Strip2bright > 200 || Strip2bright < 20) Strip2dir = Strip2dir * -1; // if strip 2 brightness goes outside or range (100-20) change 'direction' of fade
        }
         else{
    Strip2.clear();
        }
  if (Strip2Effect2state == LOW){     
     
if ( (millis () - (Strip2Effect1cleartimer) >= Strip2Effect1clearinterval)){ //code to reset load effect after Strip2Effect1clearinterval
  Strip2.clear(); // clear strip
  IRQcount = 1;
  Strip2Effect1cleartimer=millis(); //reset effect timer
}
  }




  // remember when we last updated strip
  Strip2Effect1timer = millis ();  
  }

void Strip2Effect2(uint32_t c =Strip2.ColorHSV(13650))
  {
    if (IRQcount >= 5){//if 5 of more pixels are 'loaded' do the below
   if ( (millis () - CheckIRQCounttimer) >= CheckIRQCountinterval){ // scheduling for chase effect below
    
     if (Strip2Effect2state == LOW){
     Strip2Effect2state = HIGH;
     }
     
      if (i<Strip2.numPixels()+IRQcount) i++;  { // logic test if i is less than the number of pixels in strip 2 + varialbe IRQ count then add 1 to variable i
      Strip2.setPixelColor(i, c); // Draw new pixel with colour c
      Strip2.setPixelColor(i-IRQcount, 0); // Erase pixel IRQcount number back 
      Strip2.show(); // sent info to strip to display
      }
      if (i==Strip2.numPixels()+IRQcount){ // if the effect has finished do the below
        CheckIRQCounttimer=millis(); //reset the checkIRQ timer to current time - the time it take to do the chase effect
     IRQcount = 1 ; // set IRQcount to 1
     i=1; //set i to 1
     Strip2.clear(); //clear strip of any previous effects
     Strip2Effect2state = LOW;
     
          }
  }
   }

Strip2Effect2timer = millis(); // set effect timer to current counter in millis
        }
  
  
 
void loop ()
  {
//IRQcount = 6;// for testing without physical interrupt button '//' out for actual
  
  if ( (millis () - Strip1timer) >= Strip1interval)// scheduling for strip 1 effect
     Strip1Effect ();

  
 if ( (millis () - Strip2Effect1timer) >= Strip2Effect1interval) // scheduling for strip 2 effect 1
    Strip2Effect1 ();
  
  
 
  if ( (millis () - Strip2Effect2timer) >= Strip2Effect2interval) // scheduling for strip 2 effect 1
    Strip2Effect2(); 
      
     
 
}  // end of loop

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.