Scaling up Neopixels and InfraRed

EL Wire/Tape/Panels, LEDs, pixels and strips, LCDs and TFTs, etc products from Adafruit

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
jHouse82
 
Posts: 21
Joined: Thu Jan 05, 2023 9:37 am

Scaling up Neopixels and InfraRed

Post by jHouse82 »

So here's the previous projecthttps://forum.arduino.cc/t/infared-sele ... ls/1073553.

So, I'm going up from 3 pixels on a diddy, single strip to the 256 Pixels on the matt in the picture; I'm using the same code; the bench power unit is putting out 5v, 10amp; and its an Arduino Uno running the show. I've tested each of the components individually with different programs to ensure that they are all working properly because I have encountered a problem and I'm now wondering about feasibility.

I've read in other parts of the internets that the Uno will have no problems running up to 512 NeoPixels but when I send in the Infra Red signal it appears as it like the IR Receiver just blocks up (giving me a constant lit LED on receiver and I continue to see the loop outputting my serial monitor debugging messages), and the super interesting problem is that this is a problem inherent to using the roll of NeoPixels. Using a strip of Neopixels and putting data into the same amount of Pixels I don't have a crash.

The goal of the build is to go up to all 256 Pixels and ideally the personal challenge is to stay on the one Arduino.

Has anyone got any ideas as to what the cause of this may be? I'm tempted to lean towards memory usage but that doesn't explain the differing strips having differing performance.

Here is some code, unfortunatley the photos and schematics of the physical build are to big for the forum posts

Code: Select all

//Always comment your code like it will be maintained by a violent psychopath who knows where you live.
#include <IRLibAll.h>                                                                       //Infra Red Library
#include <Adafruit_NeoPixel.h>                                                              //Adafruit NeoPixel Library

//======== Constants =============
const int LEDpin = 3;                                                                       //IO pin for the LED strip
const int LEDcount = 5;                                                                     //Number of LED's in the strip
const int IRreceiver = 2;                                                                   //IO pin for the IRreceiver
IRrecvPCI myReceiver(IRreceiver);                                                           //Instantiate the Infra Red receiver 
IRdecode myDecoder;                                                                         //Instatiate a Decoder object (Veriable to hold the recieved data from the button press)
enum  pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, color_WIPE, SCANNER, FADE };            //Limit the results 'pattern' will accept with an enumeration

//======== Variables =============

//=====Classes and Functions =====

class neoPatterns : public Adafruit_NeoPixel                                              //A class to govern the operation of the Neopixel patterns outside of the Main loop
{
  private:
    int steps;
    uint32_t color;
           
  public:

    pattern activePattern;                                                                  //Tracks the pattern that is currently active on the strip
    unsigned long interval;                                                                 //Milliseconds between updates
    unsigned long lastUpdate;                                                               //Records the millisecond of the last update

    uint32_t color1, color2;                                                              //Variables for recording active colors
    uint16_t totalSteps;                                                                    //How many steps of the pattern have been called
    uint16_t index;                                                                         //What step within the pattern we are on

    void (*onComplete)();                                                                   //onComplete callback function - still wondering how much i need this?
    
    neoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)())             //Class constructor to...
    :Adafruit_NeoPixel(pixels, pin, type)                                                   //initialise the Neopixel strip
    {
      onComplete = callback;      
    }

  void update()                                                                             //Function that manages updating the pattern
  {
    Serial.println("update function");                                                                //debugging line for the Serial Monitor
    if((millis() - lastUpdate) > interval)                                                  //Is it time to update?
      {
      lastUpdate = millis();                                                                //Updates 'lastUpdate' to the current milli's value
      switch(activePattern)                                                                 //Switch statement to track which pattern needs its update function
        {
          case RAINBOW_CYCLE:                                                               //If rainbowCycle...
          rainbowCycleUpdate();                                                             //update rainbowCycle
          break;
  
          case THEATER_CHASE:                                                               //If theatreChase...
          theaterChaseUpdate();                                                             //update theatreChase
          break;
  
          case color_WIPE:                                                                 //if colorWipe
          colorWipeUpdate();                                                                //update colorWipe
          break;
  
          case SCANNER:                                                                     //if scanner
          scannerUpdate();                                                                  //update scanner
          break;
  
          case FADE:                                                                        //if fade
          fadeUpdate();                                                                     //update fade
          break;
  
          default:
          break;
        }
      }
  }

  void increment()                                                                          //Function for incrementing values to drive strand tests
  {
    index++;                                                                                //increment index variable
      if (index >= totalSteps)                                                              //if index is greater than or equal to totalsteps...
      {
        index = 0;                                                                          //..reset index to 0 and...
        if (onComplete != NULL)                                                             //... if onComplete has no value...
          {
            onComplete();                                                                   //...call the onComplete callback
          }
      }
  }  

  void rainbowCycle(uint8_t interval)                                                                //Rainbow Cycle strand test pattern
  {
    activePattern = RAINBOW_CYCLE;                                                          //Set current active pattern to Rainbow Cycle...
    interval = interval;                                                                    //reset interval to interval
    totalSteps = 255;                                                                       //set total step variable to 255
    index = 0;                                                                              //set index variable to 0
  }

  void rainbowCycleUpdate()                                                                 //update for Rainbow Cycle
  {
    for(int i=0; i< numPixels(); i++)                                                       //create a variable called 'i' which is equal to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
    {
      setPixelColor(i, wheel(((i * 256 / numPixels()) + index) & 255));                     //set the pixel color to ...
    }
    show();                                                                          //update the orders to the Neopixel strand
    increment();                                                                            //Run the increment function
  }

  void colorWipe (uint32_t color, uint8_t interval)                                       //color wipe funtion
  {
    activePattern = color_WIPE;                                                            //update the current active pattern to color Wipe
    interval = interval;                                                                    //reset the interval variable
    totalSteps = 255;                                                                       //set the total steps variable to 255
    color1 = color;                                                                       //set color to color 1
    index = 0;                                                                              //reset the index variable to 0
  }

  void colorWipeUpdate()                                                                    //Color wipe update function
  {
    setPixelColor(index, color1);                                                           //change the pixel color to color1
    show();                                                                          //update the strand
    increment();                                                                            //run the increment function
  }

  void theaterChase(uint32_t color1, uint32_t color2, uint8_t interval)                   //Theatre Chase funtion
  {
    activePattern = THEATER_CHASE;                                                          //change the current active pattern to Theatre Chase 
    interval = interval;                                                                    //reset the interval variable 
    totalSteps = numPixels();                                                               //update the total steps variable to be equivilent to the number of pixels
    color1 = color1;                                                                      //Reset color1
    color2 = color2;                                                                      //Reset color2
    index = 0;                                                                              //Set index variable to 0
  }    

  void theaterChaseUpdate()                                                                 //Theatre Chase update function
  {
    for(int i=0; i< numPixels(); i++)                                                       //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
      {
        if ((i + index) % 3 == 0)                                                           //if the total of I and index divide equally by 3...
          {
            setPixelColor(i, color1);                                                       //...set the pixelcolor to color 1...
          }
        else                                                                                //...otherwise... 
          {
            setPixelColor(i, color2);                                                       //set the pixel color to color 2
          }
      }
    show();                                                                          //update the neopixel strand
    increment();                                                                            //run the increment function
  }

  void scanner(uint32_t color1, uint8_t interval)                                          //Scanner function
  {
    activePattern = SCANNER;                                                                //update the active pattern to Scanner
    interval = interval;                                                                    //reset the interval variable
    totalSteps = (numPixels() - 1) * 2;                                             //set the total steps variable to by equal to twice that of the number of pixels on the strand less one 
    color1 = color1;                                                                      //reset the color1 variable 
    index = 0;                                                                              //set the index variable to 0
  }

  void scannerUpdate()                                                                      //Scanner update function
  {
    for (int i = 0; i < numPixels(); i++)                                                   //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
    {
      if (i == index)                                                                       //if the i variable is equivilant to the index variable...
      {
        setPixelColor(i, color1);                                                          //set the pixel color to color1
      }
      else if (i == totalSteps - index)                                                     //if the i variable is equivilant to totalsteps less the value of index...
      {
        setPixelColor(i, color1);                                                           //set the pixel color to color1...
      }
      else                                                                                  //otherwise...
      {
        setPixelColor(i, DimColor(getPixelColor(i)));                                       //dim the current pixel value
      }
    }
    show();                                                                          //update the strand
    increment();                                                                            //run the increment function
  }  

  void fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval)           //Fade function
  {
    activePattern = FADE;                                                                   //set the current active pattern to fade
    interval = interval;                                                                    //reset the interval variable
    totalSteps = steps;                                                                     //create a new steps variable and set it to be eqivilant to totalSteps 
    color1 = color1;                                                                      //reset color1
    color2 = color2;                                                                      //reset color2
    index = 0;                                                                              //set index to 0
  }

  void fadeUpdate()                                                                                       //Fade update function
  {
    uint8_t red = ((Red(color1) * (totalSteps - index)) + (Red(color2) * index)) / totalSteps;          
    uint8_t green = ((Green(color1) * (totalSteps - index)) + (Green(color2) * index)) / totalSteps;
    uint8_t blue = ((Blue(color1) * (totalSteps - index)) + (Blue(color2) * index)) / totalSteps;
    colorSet(Color(red, green, blue));
    show();                                                                                        //update the strand
    increment();                                                                                          //run the increment function
  }

  uint8_t Red(uint32_t color)                                                              //Red color function
  {
    return (color >> 16) & 0xFF;    
  }

  uint8_t Green(uint32_t color)                                                            //Green color function
  {
    return (color >> 8) & 0xFF;
  }

  uint8_t Blue(uint32_t color)                                                             //Blue color function
  {
    return color & 0xFF;
  }

  uint32_t DimColor(uint32_t color)                                                        //color dimming function
  {
    uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
    return dimColor;
  }   
  
  uint32_t wheel(byte wheelPos)                                                             //color wheeling function for the rainbow color functions
  {
    wheelPos = 255 - wheelPos;
    if(wheelPos < 85)
    {
      return Color(255 - wheelPos * 3, 0, wheelPos * 3);
    }
    else if(wheelPos < 170)
    {
      wheelPos -= 85;
      return Color(0, wheelPos * 3, 255 - wheelPos * 3);
    }
    else
    {
      wheelPos -= 170;
      return Color(wheelPos * 3, 255 - wheelPos * 3, 0);    
    }
  }
 
  void colorSet(uint32_t color)                                                           //color set function sets all colors to the same synchronus color
  {
    for (int i = 0; i < numPixels(); i++)
    {
      setPixelColor(i, color);    
    }
    show();    
  }

  void IRSelector()                                                                           //Infra Red selection function - takes action based on IR code received        
  {
    if (myDecoder.protocolNum == NEC) {                                                       //ignore any code that is not recieved from a NEC remote control 
      switch(myDecoder.value)                                                                   //Switch statement that makes a decision based upon the value recieved from the Infra Red decoder
      {
        case 0xFFA25D: Serial.println("Untethered button, please select from 0-8"); break;      //=====================================================================
        case 0xFFE21D: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF629D: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF22DD: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF02FD: Serial.println("Untethered button, please select from 0-8"); break;      // ------------- UNASSIGNED BUTTON SELECTIONS -------------------------
        case 0xFFC23D: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFFE01F: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFFA857: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF906F: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF9867: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFFB04F: Serial.println("Untethered button, please select from 0-8"); break;      //=====================================================================
        
        case 0xFF6897:      //"0 - All black (off)"    
          colorWipe(color, interval);     
          Serial.println("0 - Black/off");    
          break;
        case 0xFF30CF:      //"1 - All red"
          colorWipe(color, interval);    
          Serial.println("1 - All red");    
          break;
        case 0xFF18E7:      //"2 - All green" 
          colorWipe(color, interval);         
          Serial.println("2 - All green");    
          break;
        case 0xFF7A85:      //"3 - All blue"
          colorWipe(color, interval);    
          Serial.println("3 - All blue");    
          break;
        case 0xFF10EF:      //"4 - All white"
          colorWipe(color, interval); 
          Serial.println("4 - All white");    
          break;
        case 0xFF38C7:       //"5 - Rainbow Cycle"
          rainbowCycle(interval);                      
          Serial.println("5");    
          break;
        case 0xFF5AA5:       //"6 - Theater Chase"
          theaterChase(color1, color2, interval);                                 
          Serial.println("6");    
          break;
        case 0xFF42BD:       //"7 - Scanner"
          scanner(color1, interval);                                 
          Serial.println("7");    
          break;
        case 0xFF4AB5:      //"8 - Fader"
          fade(color1, color2, steps, interval);                      
          Serial.println("8");    
          break;
        
        case 0xFF52AD: Serial.println("Untethered button, please select from 0-8");    break;      //button 9 - unassigned
        case 0xFFFFFFFF: Serial.println("Please release button and reselect");         break;      //consistant repeat code

        default: 
        Serial.print(" other button   ");                                                          
        Serial.println(myDecoder.value);

      }//End of Switch
    }
  }//End of IRSelector method
}; // End of neoPatterns class

void strandComplete();                                                                         
neoPatterns strand(LEDcount, LEDpin, NEO_RGBW + NEO_KHZ800, &strandComplete);               //Neopattern object to define the strand

void setup(){   /*----( SETUP: RUNS ONCE )----*/
  Serial.begin(9600);                                                                          //engage the serial monitor
  Serial.println("IR Receiver Button Decode");                                                 //print out to the monitor
  myReceiver.enableIRIn();                                                                     //Start the receiver
  strand.begin();                                                                              //start the Neopixel strip
}/*--(end setup )---*/

void loop(){   /*----( LOOP: RUNS CONSTANTLY )----*/
  if (myReceiver.getResults())                                                                 //check to see if we have received an IR signal?
  {
    myDecoder.decode();                                                                        //Decode the recieved signal
    strand.IRSelector();                                                                       //Run the IR selection function
    myReceiver.enableIRIn();                                                                   //reset the receiver for a new code
  }
  strand.update();
  Serial.println("LoopdeLoop");                                                                //debugging line for the Serial Monitor
}/* --(end main loop )-- */

void strandComplete()
{
    // Random color change for next scan
    strand.color1 = strand.wheel(random(255));
}

User avatar
Disciple
 
Posts: 852
Joined: Tue Jan 06, 2015 8:13 pm

Re: Scaling up Neopixels and InfraRed

Post by Disciple »

I apologize that I can't take time to view your project in detail. I'm just stopping by to mention that an Arduino controlled by IR signals to produce lights in motion on 256 NeoPixels is quite feasible. I know this because I built such a circuit from Adafruit components in 2018. It's called I made a scoreboard, and so can you!. Hope it offers something useful.

Hallelujah!
Disciple

User avatar
jseyfert3
 
Posts: 40
Joined: Mon May 02, 2011 11:48 pm

Re: Scaling up Neopixels and InfraRed

Post by jseyfert3 »

Okay, it's been a long time since I did Arduino stuff, but I'm planning to do it again, and stumbled on this. I happen to not be doing anything, so I figured I'd look at it.

I got the Arduino IDE and compiled your code. It's using a lot of RAM. The Arduino IDE reports:
Global variables use 1226 bytes (59%) of dynamic memory, leaving 822 bytes for local variables. Maximum is 2048 bytes.
So you're used up 59% of what little RAM an UNO has, before you start considering local variables.

Where is all this RAM going? Well, with a little more checking, we see that a blank sketch (only setup() and loop(), no libraries, no code at all) uses 9 bytes of RAM.

Next I added #include <IRLibAll.h>, and re-compiled. Now it's using 408 bytes, or 19%. So IRLibAll.h is eating up 1/5th of your RAM, all by itself!

I removed IRLibAll.h, and put in Adafruit_NeoPixel.h. Compiled, and it uses 9 bytes of RAM. So simply including Adafruit_NeoPixel.h doesn't use any RAM. This is good.

So this means your code is using 818 bytes of RAM for global variables.

Finally, on the NeoPixel product page, it says this:
Third, just because you have all those pixels doesn't mean you have the RAM for it - the entire strip must be buffered in memory, and we've found many Arduino UNO projects only have about 1500 bytes of RAM available after all the extras are included - enough for about 500 LED pixels. If you want to drive the entire strip and have some other libraries included, use a Mega.
1500 bytes comes from 1 byte per color per LED, or 3 bytes per LED. So for 256 LEDs, you need 3*256 = 750 bytes of RAM to buffer the LED strip.

If I'm understanding this correctly, that means of the 822 bytes of RAM you have to handle local variables in your code, 750 bytes is needed for buffering the LEDs, leaving you with only 72 bytes for local variables. That...doesn't sound like it's gonna be enough, but I haven't reviewed your code with a fine tooth comb.

So, what can we do, and how can we differentiate between a hardware problem or a code/out of RAM problem?

Well, I haven't used NeoPixels (yet, I just ordered a bunch to sew into a vest to flash to music), but if I recall, and it's been a while, NeoPixels just send data down the line of LEDs bit by bit. So, to check for hardware vs RAM issues, since you said your code works fine with 5 LEDs, connect the strip of 256 but leave

Code: Select all

const int LEDcount = 5; 
set to 5. Don't change it to 256. This may make the strip display improperly, as the strip will be using old data for all LEDs after the 5th, but the first 5 LEDs should display the same as the strip of only 5 LEDs. Your code is exactly the same now, so if you have issues, then you have a hardware problem, not a RAM or code problem. If that's the case, we'll look at your hardware setup in more detail.

Now, assuming you do not have any issues running the strip of 256 Neopixels with the code set to 5 pixels, besides displaying your colors wrong for all but the first 5 pixels, this means the issue is probably that you ran out of RAM, which is what I'm suspecting the issue is at the moment.

If the issue is you're out of RAM, what can you do about it? Well, you have three options:
  • Buy a microcontroller with more RAM than the UNO has.
  • Reduce the number of LEDs from 256 to some lower number.
  • Reduce your RAM usage.
Option 1: You could purchase something like an ESP32 Feather. I have no experience with this, but it can be programmed with the Arduino IDE according to Adafruit, and it has 512 kB of RAM, internally, with 8 MB of external PSRAM that can also be used! Your UNO has 2 kB of RAM. But presumably buying a new microcontroller is not top of your list right now.

Option 2: Reduce number of LEDs. This is obvious, you use 3 kB of RAM for each LED to buffer, so the fewer you use, the less RAM you need. I'm assuming this option is off the table.

Option 3: Reduce your RAM usage. This is getting a bit above me, but we'll give it a go.

Firstly, it would be good to figure out how much RAM we need. You can't (at least easily) see how much RAM is actively being used for local variables. But, you can repeat that first experient I asked you to do, with the 256 LED strip connected, but you left the number of LEDs in the code at 5? Well, if it works at 5, and not at 256, that gives us not a great idea. Try setting it to 128 LEDs in the code (with the entire 256 connected, as before). If the code works properly, set it halfway between 128 and 258, or 192. If the code doesn't work properly, set it to 64. You can repeat this "stepping in halves" to try to find how many you can use. You can stop after a couple times, no need to dive down to the absolute last byte of RAM usage here.

Please note: Out of memory issues can cause unexpected issues, so you may have a different problem when selecting a different number of LEDs than the problem you first had. Try to test all aspects of your code with different numbers of LEDs selected in the code, to ensure you've found a value of LEDs that works without running out of memory.

Now, say you find out that around 140 LEDs work, but no more. This means you need to find a way to eliminate 348 kB of RAM usage in your code.

So how do you reduce the RAM usage? The very first thing that comes to mind is IRLibAll.h. Documentation for that library states that:
The files IRLib2.h and IRLibAll.h have been provided to make it easy to re-create the old "everything at once" approach of IRLib.h version 1.xx. In general WE RECOMMEND YOU DO NOT USE THIS APPROACH. We provide this file for a small measure of backwards compatibility. Use of this file will make your program potentially much larger than necessary.
Hmm, okay. Well looking at examples is a good place to start. Looking at their rawRecv.ino file, we see:

Code: Select all

/* rawR&cv.ino Example sketch for IRLib2
 *  Illustrate how to capture raw timing values for an unknow protocol.
 *  You will capture a signal using this sketch. It will output data the 
 *  serial monitor that you can cut and paste into the "rawSend.ino"
 *  sketch.
 */
// Recommend only use IRLibRecvPCI or IRLibRecvLoop for best results
#include <IRLibRecvPCI.h> 

IRrecvPCI myReceiver(2);//pin number for the receiver

void setup() {
  Serial.begin(9600);
  delay(2000); while (!Serial); //delay for Leonardo
  myReceiver.enableIRIn(); // Start the receiver
  Serial.println(F("Ready to receive IR signals"));
}

void loop() {
  //Continue looping until you get a complete signal received
  if (myReceiver.getResults()) { 
    Serial.println(F("Do a cut-and-paste of the following lines into the "));
    Serial.println(F("designated location in rawSend.ino"));
    Serial.print(F("\n#define RAW_DATA_LEN "));
    Serial.println(recvGlobal.recvLength,DEC);
    Serial.print(F("uint16_t rawData[RAW_DATA_LEN]={\n\t"));
    for(bufIndex_t i=1;i<recvGlobal.recvLength;i++) {
      Serial.print(recvGlobal.recvBuffer[i],DEC);
      Serial.print(F(", "));
      if( (i % 8)==0) Serial.print(F("\n\t"));
    }
    Serial.println(F("1000};"));//Add arbitrary trailing space
    myReceiver.enableIRIn();      //Restart receiver
  }
}
They use the same IRrecvPCI you do, and only need to include IRLibRecvPCI.h.

Same manner, we open hashDecode.ino and see:

Code: Select all

/* hashDecode.ino Example sketch for IRLib2
 * Instead of decoding using a standard encoding scheme
 * (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value.
 * This should produce a unique 32-bit number however that number 
 * cannot be used to retransmit the same code. This is just a quick 
 * and dirty way to detect a unique code for controlling a device 
 * when you don't really care what protocol or values are being sent.
 */
//First will create a decoder that handles only NEC, Sony and the hash
// decoder. If it is not NEC or Sony that it will return a 32 bit hash.
#include <IRLibDecodeBase.h> 
#include <IRLib_P01_NEC.h>   
#include <IRLib_P02_Sony.h>  
#include <IRLib_HashRaw.h>  //Must be last protocol
#include <IRLibCombo.h>     // After all protocols, include this
// All of the above automatically creates a universal decoder
// class called "IRdecode" containing only the protocols you want.
// Now declare an instance of that decoder.
IRdecode myDecoder;

// Include a receiver either this or IRLibRecvPCI or IRLibRecvLoop
#include <IRLibRecv.h> 
IRrecv myReceiver(2);    //create a receiver on pin number 2

void setup() {
  Serial.begin(9600);
  delay(2000); while (!Serial); //delay for Leonardo
  myReceiver.enableIRIn(); // Start the receiver
  Serial.println(F("Ready to receive IR signals"));
}

void loop() {
  if(myReceiver.getResults()) {
    myDecoder.decode();
    if(myDecoder.protocolNum==UNKNOWN) {
      Serial.print(F("Unknown protocol. Hash value is: 0x"));
      Serial.println(myDecoder.value,HEX);
    } else {
      myDecoder.dumpResults(false);
    };
    myReceiver.enableIRIn(); 
  }
}
This example code shows 5 headers needed for decoding. So we'll remove IRLibAll.h from your code, add the previous 6 headers, and we get this:

Code: Select all

//Always comment your code like it will be maintained by a violent psychopath who knows where you live.
//#include <IRLibAll.h>                                                                       //Infra Red Library
#include <IRLibRecvPCI.h>   //required for receiving IR signals

// the following 5 libraries are for decoding the IR signal, based on example code in hasDecode.ino
#include <IRLibDecodeBase.h> 
#include <IRLib_P01_NEC.h>   
#include <IRLib_P02_Sony.h>  
#include <IRLib_HashRaw.h>  //Must be last protocol
#include <IRLibCombo.h>

#include <Adafruit_NeoPixel.h>                                                              //Adafruit NeoPixel Library

//======== Constants =============
const int LEDpin = 3;                                                                       //IO pin for the LED strip
const int LEDcount = 5;                                                                     //Number of LED's in the strip
const int IRreceiver = 2;                                                                   //IO pin for the IRreceiver
IRrecvPCI myReceiver(IRreceiver);                                                           //Instantiate the Infra Red receiver 
IRdecode myDecoder;                                                                         //Instatiate a Decoder object (Veriable to hold the recieved data from the button press)
enum  pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, color_WIPE, SCANNER, FADE };            //Limit the results 'pattern' will accept with an enumeration

//======== Variables =============

//=====Classes and Functions =====

class neoPatterns : public Adafruit_NeoPixel                                              //A class to govern the operation of the Neopixel patterns outside of the Main loop
{
  private:
    int steps;
    uint32_t color;
           
  public:

    pattern activePattern;                                                                  //Tracks the pattern that is currently active on the strip
    unsigned long interval;                                                                 //Milliseconds between updates
    unsigned long lastUpdate;                                                               //Records the millisecond of the last update

    uint32_t color1, color2;                                                              //Variables for recording active colors
    uint16_t totalSteps;                                                                    //How many steps of the pattern have been called
    uint16_t index;                                                                         //What step within the pattern we are on

    void (*onComplete)();                                                                   //onComplete callback function - still wondering how much i need this?
    
    neoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)())             //Class constructor to...
    :Adafruit_NeoPixel(pixels, pin, type)                                                   //initialise the Neopixel strip
    {
      onComplete = callback;      
    }

  void update()                                                                             //Function that manages updating the pattern
  {
    Serial.println("update function");                                                                //debugging line for the Serial Monitor
    if((millis() - lastUpdate) > interval)                                                  //Is it time to update?
      {
      lastUpdate = millis();                                                                //Updates 'lastUpdate' to the current milli's value
      switch(activePattern)                                                                 //Switch statement to track which pattern needs its update function
        {
          case RAINBOW_CYCLE:                                                               //If rainbowCycle...
          rainbowCycleUpdate();                                                             //update rainbowCycle
          break;
  
          case THEATER_CHASE:                                                               //If theatreChase...
          theaterChaseUpdate();                                                             //update theatreChase
          break;
  
          case color_WIPE:                                                                 //if colorWipe
          colorWipeUpdate();                                                                //update colorWipe
          break;
  
          case SCANNER:                                                                     //if scanner
          scannerUpdate();                                                                  //update scanner
          break;
  
          case FADE:                                                                        //if fade
          fadeUpdate();                                                                     //update fade
          break;
  
          default:
          break;
        }
      }
  }

  void increment()                                                                          //Function for incrementing values to drive strand tests
  {
    index++;                                                                                //increment index variable
      if (index >= totalSteps)                                                              //if index is greater than or equal to totalsteps...
      {
        index = 0;                                                                          //..reset index to 0 and...
        if (onComplete != NULL)                                                             //... if onComplete has no value...
          {
            onComplete();                                                                   //...call the onComplete callback
          }
      }
  }  

  void rainbowCycle(uint8_t interval)                                                                //Rainbow Cycle strand test pattern
  {
    activePattern = RAINBOW_CYCLE;                                                          //Set current active pattern to Rainbow Cycle...
    interval = interval;                                                                    //reset interval to interval
    totalSteps = 255;                                                                       //set total step variable to 255
    index = 0;                                                                              //set index variable to 0
  }

  void rainbowCycleUpdate()                                                                 //update for Rainbow Cycle
  {
    for(int i=0; i< numPixels(); i++)                                                       //create a variable called 'i' which is equal to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
    {
      setPixelColor(i, wheel(((i * 256 / numPixels()) + index) & 255));                     //set the pixel color to ...
    }
    show();                                                                          //update the orders to the Neopixel strand
    increment();                                                                            //Run the increment function
  }

  void colorWipe (uint32_t color, uint8_t interval)                                       //color wipe funtion
  {
    activePattern = color_WIPE;                                                            //update the current active pattern to color Wipe
    interval = interval;                                                                    //reset the interval variable
    totalSteps = 255;                                                                       //set the total steps variable to 255
    color1 = color;                                                                       //set color to color 1
    index = 0;                                                                              //reset the index variable to 0
  }

  void colorWipeUpdate()                                                                    //Color wipe update function
  {
    setPixelColor(index, color1);                                                           //change the pixel color to color1
    show();                                                                          //update the strand
    increment();                                                                            //run the increment function
  }

  void theaterChase(uint32_t color1, uint32_t color2, uint8_t interval)                   //Theatre Chase funtion
  {
    activePattern = THEATER_CHASE;                                                          //change the current active pattern to Theatre Chase 
    interval = interval;                                                                    //reset the interval variable 
    totalSteps = numPixels();                                                               //update the total steps variable to be equivilent to the number of pixels
    color1 = color1;                                                                      //Reset color1
    color2 = color2;                                                                      //Reset color2
    index = 0;                                                                              //Set index variable to 0
  }    

  void theaterChaseUpdate()                                                                 //Theatre Chase update function
  {
    for(int i=0; i< numPixels(); i++)                                                       //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
      {
        if ((i + index) % 3 == 0)                                                           //if the total of I and index divide equally by 3...
          {
            setPixelColor(i, color1);                                                       //...set the pixelcolor to color 1...
          }
        else                                                                                //...otherwise... 
          {
            setPixelColor(i, color2);                                                       //set the pixel color to color 2
          }
      }
    show();                                                                          //update the neopixel strand
    increment();                                                                            //run the increment function
  }

  void scanner(uint32_t color1, uint8_t interval)                                          //Scanner function
  {
    activePattern = SCANNER;                                                                //update the active pattern to Scanner
    interval = interval;                                                                    //reset the interval variable
    totalSteps = (numPixels() - 1) * 2;                                             //set the total steps variable to by equal to twice that of the number of pixels on the strand less one 
    color1 = color1;                                                                      //reset the color1 variable 
    index = 0;                                                                              //set the index variable to 0
  }

  void scannerUpdate()                                                                      //Scanner update function
  {
    for (int i = 0; i < numPixels(); i++)                                                   //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
    {
      if (i == index)                                                                       //if the i variable is equivilant to the index variable...
      {
        setPixelColor(i, color1);                                                          //set the pixel color to color1
      }
      else if (i == totalSteps - index)                                                     //if the i variable is equivilant to totalsteps less the value of index...
      {
        setPixelColor(i, color1);                                                           //set the pixel color to color1...
      }
      else                                                                                  //otherwise...
      {
        setPixelColor(i, DimColor(getPixelColor(i)));                                       //dim the current pixel value
      }
    }
    show();                                                                          //update the strand
    increment();                                                                            //run the increment function
  }  

  void fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval)           //Fade function
  {
    activePattern = FADE;                                                                   //set the current active pattern to fade
    interval = interval;                                                                    //reset the interval variable
    totalSteps = steps;                                                                     //create a new steps variable and set it to be eqivilant to totalSteps 
    color1 = color1;                                                                      //reset color1
    color2 = color2;                                                                      //reset color2
    index = 0;                                                                              //set index to 0
  }

  void fadeUpdate()                                                                                       //Fade update function
  {
    uint8_t red = ((Red(color1) * (totalSteps - index)) + (Red(color2) * index)) / totalSteps;          
    uint8_t green = ((Green(color1) * (totalSteps - index)) + (Green(color2) * index)) / totalSteps;
    uint8_t blue = ((Blue(color1) * (totalSteps - index)) + (Blue(color2) * index)) / totalSteps;
    colorSet(Color(red, green, blue));
    show();                                                                                        //update the strand
    increment();                                                                                          //run the increment function
  }

  uint8_t Red(uint32_t color)                                                              //Red color function
  {
    return (color >> 16) & 0xFF;    
  }

  uint8_t Green(uint32_t color)                                                            //Green color function
  {
    return (color >> 8) & 0xFF;
  }

  uint8_t Blue(uint32_t color)                                                             //Blue color function
  {
    return color & 0xFF;
  }

  uint32_t DimColor(uint32_t color)                                                        //color dimming function
  {
    uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
    return dimColor;
  }   
  
  uint32_t wheel(byte wheelPos)                                                             //color wheeling function for the rainbow color functions
  {
    wheelPos = 255 - wheelPos;
    if(wheelPos < 85)
    {
      return Color(255 - wheelPos * 3, 0, wheelPos * 3);
    }
    else if(wheelPos < 170)
    {
      wheelPos -= 85;
      return Color(0, wheelPos * 3, 255 - wheelPos * 3);
    }
    else
    {
      wheelPos -= 170;
      return Color(wheelPos * 3, 255 - wheelPos * 3, 0);    
    }
  }
 
  void colorSet(uint32_t color)                                                           //color set function sets all colors to the same synchronus color
  {
    for (int i = 0; i < numPixels(); i++)
    {
      setPixelColor(i, color);    
    }
    show();    
  }

  void IRSelector()                                                                           //Infra Red selection function - takes action based on IR code received        
  {
    if (myDecoder.protocolNum == NEC) {                                                       //ignore any code that is not recieved from a NEC remote control 
      switch(myDecoder.value)                                                                   //Switch statement that makes a decision based upon the value recieved from the Infra Red decoder
      {
        case 0xFFA25D: Serial.println("Untethered button, please select from 0-8"); break;      //=====================================================================
        case 0xFFE21D: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF629D: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF22DD: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF02FD: Serial.println("Untethered button, please select from 0-8"); break;      // ------------- UNASSIGNED BUTTON SELECTIONS -------------------------
        case 0xFFC23D: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFFE01F: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFFA857: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF906F: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF9867: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFFB04F: Serial.println("Untethered button, please select from 0-8"); break;      //=====================================================================
        
        case 0xFF6897:      //"0 - All black (off)"    
          colorWipe(color, interval);     
          Serial.println("0 - Black/off");    
          break;
        case 0xFF30CF:      //"1 - All red"
          colorWipe(color, interval);    
          Serial.println("1 - All red");    
          break;
        case 0xFF18E7:      //"2 - All green" 
          colorWipe(color, interval);         
          Serial.println("2 - All green");    
          break;
        case 0xFF7A85:      //"3 - All blue"
          colorWipe(color, interval);    
          Serial.println("3 - All blue");    
          break;
        case 0xFF10EF:      //"4 - All white"
          colorWipe(color, interval); 
          Serial.println("4 - All white");    
          break;
        case 0xFF38C7:       //"5 - Rainbow Cycle"
          rainbowCycle(interval);                      
          Serial.println("5");    
          break;
        case 0xFF5AA5:       //"6 - Theater Chase"
          theaterChase(color1, color2, interval);                                 
          Serial.println("6");    
          break;
        case 0xFF42BD:       //"7 - Scanner"
          scanner(color1, interval);                                 
          Serial.println("7");    
          break;
        case 0xFF4AB5:      //"8 - Fader"
          fade(color1, color2, steps, interval);                      
          Serial.println("8");    
          break;
        
        case 0xFF52AD: Serial.println("Untethered button, please select from 0-8");    break;      //button 9 - unassigned
        case 0xFFFFFFFF: Serial.println("Please release button and reselect");         break;      //consistant repeat code

        default: 
        Serial.print(" other button   ");                                                          
        Serial.println(myDecoder.value);

      }//End of Switch
    }
  }//End of IRSelector method
}; // End of neoPatterns class

void strandComplete();                                                                         
neoPatterns strand(LEDcount, LEDpin, NEO_RGBW + NEO_KHZ800, &strandComplete);               //Neopattern object to define the strand

void setup(){   /*----( SETUP: RUNS ONCE )----*/
  Serial.begin(9600);                                                                          //engage the serial monitor
  Serial.println("IR Receiver Button Decode");                                                 //print out to the monitor
  myReceiver.enableIRIn();                                                                     //Start the receiver
  strand.begin();                                                                              //start the Neopixel strip
}/*--(end setup )---*/

void loop(){   /*----( LOOP: RUNS CONSTANTLY )----*/
  if (myReceiver.getResults())                                                                 //check to see if we have received an IR signal?
  {
    myDecoder.decode();                                                                        //Decode the recieved signal
    strand.IRSelector();                                                                       //Run the IR selection function
    myReceiver.enableIRIn();                                                                   //reset the receiver for a new code
  }
  strand.update();
  Serial.println("LoopdeLoop");                                                                //debugging line for the Serial Monitor
}/* --(end main loop )-- */

void strandComplete()
{
    // Random color change for next scan
    strand.color1 = strand.wheel(random(255));
}
Hit compile and...we are using 773 bytes, leaving 1275 bytes for local variables. No compile errors. I can't test this, as I don't have your IR receiver, but assuming it works, we just freed up 453 bytes of RAM! Give that code a shot, let me know if it works. If you issue is out of RAM and not hardware, that RAM savings alone may fix the issue. Fingers crossed!

P.S. If you turn on "more" or "all" compiler warnings in the Arduino IDE, the following warnings come up. These don't stop compiling from completing (otherwise they'd show up with the "default" warnings), but may be something to consider down the road. I don't think this would cause any issues until you reached the max positive value of the two-byte int at 32,767, but then it would roll over to -32,768 (I think). Whereas numPixels is an uint16_t (got this by seeing how they declared numPixels() in Adafruit_NeoPixel.h), which is an unsigned 16 bit integer, which goes from 0 to 65,535.

Code: Select all

/home/jonathanseyfert/Arduino/forumCode/forumCode.ino: In member function ‘void neoPatterns::rainbowCycleUpdate()’:
/home/jonathanseyfert/Arduino/forumCode/forumCode.ino:107:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     for(int i=0; i< numPixels(); i++)                                                       //create a variable called 'i' which is equal to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
                   ^
/home/jonathanseyfert/Arduino/forumCode/forumCode.ino: In member function ‘void neoPatterns::theaterChaseUpdate()’:
/home/jonathanseyfert/Arduino/forumCode/forumCode.ino:143:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     for(int i=0; i< numPixels(); i++)                                                       //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
                   ^
/home/jonathanseyfert/Arduino/forumCode/forumCode.ino: In member function ‘void neoPatterns::scannerUpdate()’:
/home/jonathanseyfert/Arduino/forumCode/forumCode.ino:169:23: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     for (int i = 0; i < numPixels(); i++)                                                   //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
                       ^
/home/jonathanseyfert/Arduino/forumCode/forumCode.ino:171:13: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
       if (i == index)                                                                       //if the i variable is equivilant to the index variable...
             ^
/home/jonathanseyfert/Arduino/forumCode/forumCode.ino:175:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
       else if (i == totalSteps - index)                                                     //if the i variable is equivilant to totalsteps less the value of index...
                  ^
/home/jonathanseyfert/Arduino/forumCode/forumCode.ino: In member function ‘void neoPatterns::colorSet(uint32_t)’:
/home/jonathanseyfert/Arduino/forumCode/forumCode.ino:250:23: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     for (int i = 0; i < numPixels(); i++)
                       ^
If you care to, you can fix this warning by changing

Code: Select all

for(int i=0; i< numPixels(); i++)
and similar lines comparing to numPixels() to:

Code: Select all

for(unsigned int i=0; i< numPixels(); i++)
Wow, I really hope the issue is out of memory, cause I spent a lot of time on this. Please come back and update us!

User avatar
jHouse82
 
Posts: 21
Joined: Thu Jan 05, 2023 9:37 am

Re: Scaling up Neopixels and InfraRed

Post by jHouse82 »

First before anything, thank you. This was one of the best, most cogent responses I have ever received on a forum. You are an example!

Thankyou very much, I have implemented these changes and they reduced the usage of RAM by a third, however I do still have the same problem and have discovered a new even battier one. My working theory is that due to the inability to symmetrically run both the IR receiver and the Neopixels (NeoPixels updating issue a stop on all else) is that I either need to write a pause to the Neopixels update whilst receiving or pause the IR whilst updating (I'm thinking of pausing the the update to receive, store the data from IR and mix it back in at either the end of Pixel routine or have the receipt of the variable trigger a stop or something like this). Here is a viewtopic.php?f=25&t=59742 to a differing post which had some success in this area, credit to SeiRruf.

The new batty problem When I ran the tests this morning, also when running the test after your changes, the code is running more Pixels than it is meant to. When the 'LEDcount' is set to 5, it runs 7. When it is set to 9 it runs 12, and set to 12 it runs 16 so why it randomly increments that by a third is what I'm looking at this afternoon.

User avatar
jseyfert3
 
Posts: 40
Joined: Mon May 02, 2011 11:48 pm

Re: Scaling up Neopixels and InfraRed

Post by jseyfert3 »

jHouse82 wrote: Mon Jan 23, 2023 7:46 am First before anything, thank you. This was one of the best, most cogent responses I have ever received on a forum. You are an example!

Thankyou very much, I have implemented these changes and they reduced the usage of RAM by a third, however I do still have the same problem and have discovered a new even battier one.
You are welcome, and thank you!

I'm glad the RAM usage went down, and the program still worked.
jHouse82 wrote: Mon Jan 23, 2023 7:46 am The new batty problem When I ran the tests this morning, also when running the test after your changes, the code is running more Pixels than it is meant to. When the 'LEDcount' is set to 5, it runs 7. When it is set to 9 it runs 12, and set to 12 it runs 16 so why it randomly increments that by a third is what I'm looking at this afternoon.
Which specific NeoPixels did you buy? You have RGBW pixels selected as the type in your code, but they sell RGB and RGBW NeoPixels. RGBW would require 4 bytes per LED, not 3 bytes per LED like RGB ones. Lines up with the extra LEDs you show operating, but seems like you'd get improper colors displayed if that was the case? IDK, the library code is a bit over my head at this point.

User avatar
adafruit_support_bill
 
Posts: 88142
Joined: Sat Feb 07, 2009 10:11 am

Re: Scaling up Neopixels and InfraRed

Post by adafruit_support_bill »

My working theory is that due to the inability to symmetrically run both the IR receiver and the Neopixels (NeoPixels updating issue a stop on all else) is that I either need to write a pause to the Neopixels update whilst receiving or pause the IR whilst updating
Both the Neopixel protocol and the IR protocol are time-critical so it is not possible to have both running concurrently (on most processors*). The Neopixel library disables interrupts for the entire duration of updating the strip. So any IR transmissions during that period will be missed.

* Some processors support DMA output to Neopixels which may be a solution for your case: https://learn.adafruit.com/dma-driven-neopixels
When the 'LEDcount' is set to 5, it runs 7. When it is set to 9 it runs 12, and set to 12 it runs 16
Sounds like you have declared the strip as RGBW, but it is actually RGB. So for 5 pixels it will send out 20 bytes instead of 15. And the extra 5 bytes will light up an extra 2 pixels. (The colors will be wrong also)

User avatar
jseyfert3
 
Posts: 40
Joined: Mon May 02, 2011 11:48 pm

Re: Scaling up Neopixels and InfraRed

Post by jseyfert3 »

Just got my Circuit Playground Bluefruit. I can now mess with my own Neopixels, at least the 10 built-into the board that is.

Anyway, they are RGB, and just like adafruit_support_bill said, you set pixels to 5, it'll light up 7. But the colors get funky. Setting all pixels to red, green, or blue, it displays in order, a red, a green, a blue, and a nothing. Changing from one color to another just shifts the position of these wrong colors by one NeoPixel.

If someone were to have only tried moving color patterns, and were new to NeoPixels, I could see how they may not realize something was wrong, after running the rainbow moving color circle demo on my Circuit Playground Bluefruit. Colors are funky, and some pixels are occasionally off, but it doesn't look immediately wrong like it does if you try to set all of them to a solid primary color.

jHouse82, have you tried setting pixels to a solid red, green, or blue?

User avatar
jHouse82
 
Posts: 21
Joined: Thu Jan 05, 2023 9:37 am

Re: Scaling up Neopixels and InfraRed

Post by jHouse82 »

Hi People,

Yep, made the change to RGB and that smoothed everything back out, however, I think I've either broken the code a bit when I was putting in new lines for debounce and trying some experiments to put the update on hold on IR receipt or I've fried my IR sensor in a short circuit issue. You may have guessed - I'm new to the wires and lamps bit, I'm mainly a code guy. I've also been dragged off to another project and have to play about with Bare Conductive's Touch Board for a bit so I'm sad to say that this is probably going on the shelf for a week or two.

I appreciate all the help I've got here. I'm going to post up the code as it is now and I'll message on this string again when I'm back to messing about with it :)

Code: Select all

//Always comment your code like it will be maintained by a violent psychopath who knows where you live.
//#include <IRLibAll.h>                                                                       //Infra Red Library
#include <IRLibRecvPCI.h>   //required for receiving IR signals

// the following 5 libraries are for decoding the IR signal, based on example code in hasDecode.ino
#include <IRLibDecodeBase.h> 
#include <IRLib_P01_NEC.h>   
#include <IRLib_P02_Sony.h>  
#include <IRLib_HashRaw.h>  //Must be last protocol
#include <IRLibCombo.h>
#include <Adafruit_NeoPixel.h>                                                              //Adafruit NeoPixel Library

//======== Constants =============
#define OnBoardLED 13
#define BOUNCE_GAP 100
const int LEDpin = 3;                                                                       //IO pin for the LED strip
const int LEDcount = 8;                                                                     //Number of LED's in the strip
const int IRreceiver = 2;                                                                   //IO pin for the IRreceiver
IRrecvPCI myReceiver(IRreceiver);                                                           //Instantiate the Infra Red receiver 
IRdecode myDecoder;                                                                         //Instatiate a Decoder object (Veriable to hold the recieved data from the button press)
enum  pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, color_WIPE, SCANNER, FADE };            //Limit the results 'pattern' will accept with an enumeration

//======== Variables =============
uint32_t newCode;
uint32_t lastCode;
unsigned long deBounce = 0;

//=====Classes and Functions =====

class neoPatterns : public Adafruit_NeoPixel                                              //A class to govern the operation of the Neopixel patterns outside of the Main loop
{
  private:
    int steps;
    uint32_t color;
           
  public:

    pattern activePattern;                                                                  //Tracks the pattern that is currently active on the strip
    unsigned long interval;                                                                 //Milliseconds between updates
    unsigned long pause;                                                                    //another variable for storing milliseconds     
    unsigned long lastUpdate;                                                               //Records the millisecond of the last update

    uint32_t color1, color2;                                                              //Variables for recording active colors
    uint16_t totalSteps;                                                                    //How many steps of the pattern have been called
    uint16_t index;
    unsigned int i;                                                                         //What step within the pattern we are on

    void (*onComplete)();                                                                   //onComplete callback function - still wondering how much i need this?
    
    neoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)())             //Class constructor to...
    :Adafruit_NeoPixel(pixels, pin, type)                                                   //initialise the Neopixel strip
    {
      onComplete = callback;      
    }

  void update()                                                                             //Function that manages updating the pattern
  {
    if (myReceiver.getResults() == 0)
      {      
      //Serial.println("update function");                                                       //debugging line for the Serial Monitor
      if((millis() - lastUpdate) > pause)                                                  //Is it time to update?
        {
        lastUpdate = millis();                                                                //Updates 'lastUpdate' to the current milli's value
        switch(activePattern)                                                                 //Switch statement to track which pattern needs its update function
          {
            case RAINBOW_CYCLE:                                                               //If rainbowCycle...
            rainbowCycleUpdate();                                                             //update rainbowCycle
            break;
    
            case THEATER_CHASE:                                                               //If theatreChase...
            theaterChaseUpdate();                                                             //update theatreChase
            break;
    
            case color_WIPE:                                                                 //if colorWipe
            colorWipeUpdate();                                                                //update colorWipe
            break;
    
            case SCANNER:                                                                     //if scanner
            scannerUpdate();                                                                  //update scanner
            break;
    
            case FADE:                                                                        //if fade
            fadeUpdate();                                                                     //update fade
            break;
    
            default:
            break;
          }
        }
      }  
  }

  void increment()                                                                          //Function for incrementing values to drive strand tests
  {
    index++;                                                                                //increment index variable
      if (index >= totalSteps)                                                              //if index is greater than or equal to totalsteps...
      {
        index = 0;                                                                          //..reset index to 0 and...
        if (onComplete != NULL)                                                             //... if onComplete has no value...
          {
            onComplete();                                                                   //...call the onComplete callback
          }
      }
  }  

  void rainbowCycle(uint8_t interval)                                                                //Rainbow Cycle strand test pattern
  {
    activePattern = RAINBOW_CYCLE;                                                          //Set current active pattern to Rainbow Cycle...
    pause = interval;                                                                    //reset interval to interval
    totalSteps = 255;                                                                       //set total step variable to 255
    index = 0;                                                                              //set index variable to 0
  }

  void rainbowCycleUpdate()                                                                 //update for Rainbow Cycle
  {
    for(i=0; i< numPixels(); i++)                                                       //create a variable called 'i' which is equal to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
    {
      setPixelColor(i, wheel(((i * 256 / numPixels()) + index) & 255));                     //set the pixel color to ...
    }
    show();                                                                          //update the orders to the Neopixel strand
    increment();                                                                            //Run the increment function
  }

  void colorWipe (uint32_t color, uint8_t interval)                                       //color wipe funtion
  {
    activePattern = color_WIPE;                                                            //update the current active pattern to color Wipe
    pause = interval;                                                                    //reset the interval variable
    totalSteps = 255;                                                                       //set the total steps variable to 255
    color1 = color;                                                                       //set color to color 1
    index = 0;                                                                              //reset the index variable to 0
  }

  void colorWipeUpdate()                                                                    //Color wipe update function
  {
    setPixelColor(index, color1);                                                           //change the pixel color to color1
    show();                                                                          //update the strand
    increment();                                                                            //run the increment function
  }

  void theaterChase(uint32_t color1, uint32_t color2, uint8_t interval)                   //Theatre Chase funtion
  {
    activePattern = THEATER_CHASE;                                                          //change the current active pattern to Theatre Chase 
    pause = interval;                                                                    //reset the interval variable 
    totalSteps = numPixels();                                                               //update the total steps variable to be equivilent to the number of pixels
    color1 = color1;                                                                      //Reset color1
    color2 = color2;                                                                      //Reset color2
    index = 0;                                                                              //Set index variable to 0
  }    

  void theaterChaseUpdate()                                                                 //Theatre Chase update function
  {
    for(i=0; i< numPixels(); i++)                                                       //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
      {
        if ((i + index) % 3 == 0)                                                           //if the total of I and index divide equally by 3...
          {
            setPixelColor(i, color1);                                                       //...set the pixelcolor to color 1...
          }
        else                                                                                //...otherwise... 
          {
            setPixelColor(i, color2);                                                       //set the pixel color to color 2
          }
      }
    show();                                                                          //update the neopixel strand
    increment();                                                                            //run the increment function
  }

  void scanner(uint32_t color1, uint8_t interval)                                          //Scanner function
  {
    activePattern = SCANNER;                                                                //update the active pattern to Scanner
    pause = interval;                                                                    //reset the interval variable
    totalSteps = (numPixels() - 1) * 2;                                             //set the total steps variable to by equal to twice that of the number of pixels on the strand less one 
    color1 = color1;                                                                      //reset the color1 variable 
    index = 0;                                                                              //set the index variable to 0
  }

  void scannerUpdate()                                                                      //Scanner update function
  {
    for (i = 0; i < numPixels(); i++)                                                   //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
    {
      if (i == index)                                                                       //if the i variable is equivilant to the index variable...
      {
        setPixelColor(i, color1);                                                          //set the pixel color to color1
      }
      else if (i == totalSteps - index)                                                     //if the i variable is equivilant to totalsteps less the value of index...
      {
        setPixelColor(i, color1);                                                           //set the pixel color to color1...
      }
      else                                                                                  //otherwise...
      {
        setPixelColor(i, DimColor(getPixelColor(i)));                                       //dim the current pixel value
      }
    }
    show();                                                                          //update the strand
    increment();                                                                            //run the increment function
  }  

  void fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval)           //Fade function
  {
    activePattern = FADE;                                                                   //set the current active pattern to fade
    pause = interval;                                                                    //reset the interval variable
    totalSteps = steps;                                                                     //create a new steps variable and set it to be eqivilant to totalSteps 
    color1 = color1;                                                                      //reset color1
    color2 = color2;                                                                      //reset color2
    index = 0;                                                                              //set index to 0
  }

  void fadeUpdate()                                                                                       //Fade update function
  {
    uint8_t red = ((Red(color1) * (totalSteps - index)) + (Red(color2) * index)) / totalSteps;          
    uint8_t green = ((Green(color1) * (totalSteps - index)) + (Green(color2) * index)) / totalSteps;
    uint8_t blue = ((Blue(color1) * (totalSteps - index)) + (Blue(color2) * index)) / totalSteps;
    colorSet(Color(red, green, blue));
    show();                                                                                        //update the strand
    increment();                                                                                          //run the increment function
  }

  uint8_t Red(uint32_t color)                                                              //Red color function
  {
    return (color >> 16) & 0xFF;    
  }

  uint8_t Green(uint32_t color)                                                            //Green color function
  {
    return (color >> 8) & 0xFF;
  }

  uint8_t Blue(uint32_t color)                                                             //Blue color function
  {
    return color & 0xFF;
  }

  uint32_t DimColor(uint32_t color)                                                        //color dimming function
  {
    uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
    return dimColor;
  }   
  
  uint32_t wheel(byte wheelPos)                                                             //color wheeling function for the rainbow color functions
  {
    wheelPos = 255 - wheelPos;
    if(wheelPos < 85)
    {
      return Color(255 - wheelPos * 3, 0, wheelPos * 3);
    }
    else if(wheelPos < 170)
    {
      wheelPos -= 85;
      return Color(0, wheelPos * 3, 255 - wheelPos * 3);
    }
    else
    {
      wheelPos -= 170;
      return Color(wheelPos * 3, 255 - wheelPos * 3, 0);    
    }
  }
 
  void colorSet(uint32_t color)                                                           //color set function sets all colors to the same synchronus color
  {
    for (i = 0; i < numPixels(); i++)
    {
      setPixelColor(i, color);    
    }
    show();    
  }

  void IRSelector()                                                                           //Infra Red selection function - takes action based on IR code received        
  {
      switch(myDecoder.value)                                                                   //Switch statement that makes a decision based upon the value recieved from the Infra Red decoder
      {
        case 0xFFA25D: Serial.println("Untethered button, please select from 0-8"); break;      //=====================================================================
        case 0xFFE21D: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF629D: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF22DD: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF02FD: Serial.println("Untethered button, please select from 0-8"); break;      // ------------- UNASSIGNED BUTTON SELECTIONS -------------------------
        case 0xFFC23D: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFFE01F: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFFA857: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF906F: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFF9867: Serial.println("Untethered button, please select from 0-8"); break;
        case 0xFFB04F: Serial.println("Untethered button, please select from 0-8"); break;      //=====================================================================
        
        case 0xFF6897:      //"0 - All black (off)"    
          colorWipe(color, interval);     
          Serial.println("0 - Black/off");    
          break;
        case 0xFF30CF:      //"1 - All red"
          colorWipe(color, interval);    
          Serial.println("1 - All red");    
          break;
        case 0xFF18E7:      //"2 - All green" 
          colorWipe(color, interval);         
          Serial.println("2 - All green");    
          break;
        case 0xFF7A85:      //"3 - All blue"
          colorWipe(color, interval);    
          Serial.println("3 - All blue");    
          break;
        case 0xFF10EF:      //"4 - All white"
          colorWipe(color, interval); 
          Serial.println("4 - All white");    
          break;
        case 0xFF38C7:       //"5 - Rainbow Cycle"
          rainbowCycle(interval);                      
          Serial.println("5");    
          break;
        case 0xFF5AA5:       //"6 - Theater Chase"
          theaterChase(color1, color2, interval);                                 
          Serial.println("6");    
          break;
        case 0xFF42BD:       //"7 - Scanner"
          scanner(color1, interval);                                 
          Serial.println("7");    
          break;
        case 0xFF4AB5:      //"8 - Fader"
          fade(color1, color2, steps, interval);                      
          Serial.println("8");    
          break;
        
        case 0xFF52AD: Serial.println("Untethered button, please select from 0-8");    break;      //button 9 - unassigned
        case 0xFFFFFFFF: Serial.println("Please release button and reselect");         break;      //consistant repeat code

        default: 
        Serial.print(" other button   ");                                                          
        Serial.println(myDecoder.value);

      }//End of Switch
  }//End of IRSelector method
}; // End of neoPatterns class

void strandComplete();                                                                         
neoPatterns strand(LEDcount, LEDpin, NEO_KHZ400 + NEO_RGB, &strandComplete);               //Neopattern object to define the strand

void setup(){   /*----( SETUP: RUNS ONCE )----*/
  Serial.begin(9600);                                                                          //engage the serial monitor
  Serial.println("IR Receiver Button Decode");                                                 //print out to the monitor
  pinMode(OnBoardLED, OUTPUT);
  myReceiver.enableIRIn();                                                                     //Start the receiver
  strand.begin();                                                                              //start the Neopixel strip
}/*--(end setup )---*/

void loop(){   /*----( LOOP: RUNS CONSTANTLY )----*/
  if (myReceiver.getResults())                                                                 //check to see if we have received an IR signal?
    {if (myDecoder.decode())                              //If the signal received is an NEC code and we have received a signal to decode
      {
        newCode = myDecoder.value;
        if((newCode == lastCode) && (millis() < deBounce))
          {newCode = 0;
          deBounce = millis() + BOUNCE_GAP;
          }
        else
          {lastCode = newCode;
          deBounce = millis() + BOUNCE_GAP;
          digitalWrite(OnBoardLED, HIGH);                       // on board LED on while we process a button-press
          }
        strand.IRSelector();
        digitalWrite(OnBoardLED, LOW);                                                                       //Run the IR selection function                
      }       
    myReceiver.enableIRIn();
    }                                                                    //reset the receiver for a new code
strand.update();
//Serial.println("LoopdeLoop");                                                                //debugging line for the Serial Monitor
}/* --(end main loop )-- */

void strandComplete()
{
    // Random color change for next scan
    strand.color1 = strand.wheel(random(255));
}

Locked
Please be positive and constructive with your questions and comments.

Return to “Glowy things (LCD, LED, TFT, EL) purchased at Adafruit”