FastLED/NeoPixel examples that are non-blocking?

I have been looking at quite a few examples of the FastLED and NeoPixel library, but they all use make use the delay function a lot (a function that imo should have never been implemented). Causing me to be unable to run other code in the meantime.

So I'm wondering if there are any good examples that are... let's call it non-blocking.

Neopixels require precise timing to work properly so any delays within the Neopixel libraries are probably needed but not delays within the main sketch code.
Tell us more details on what your wanting to do and maybe post the examples code your not happy with.

Yes, I get that. While the code is actually interacting with the strip, you can't do anything else.

But instead of

uint32_t red = strip.Color(255, 0, 0);

void loop() {
  colorWipe_stupid(red);
}

void colorWipe_stupid(uint32_t color) {
  static uint8_t wait = 50;
  for(uint16_t currentLed=0; currentLed<strip.numPixels(); currentLed++) {
    strip.setPixelColor(currentLed, color);
    strip.show();
    delay(50);
  }
}

You can easily write:

uint32_t red = strip.Color(255, 0, 0);

void loop() {
  colorWipe_smart(red);
}

void colorWipe_smart(uint32_t color) {
  static uint8_t wait = 50;
  static unsigned long lastUpdate = 0;
  static uint16_t currentLed = 0;
  
  unsigned long now = millis();
  if (now > lastUpdate+delay) {
    strip.setPixelColor(currentLed, color);
    strip.show();    
    currentLed = currentLed>strip.numPixels() ? 0 : currentLed+1;
    lastUpdate = now;
  }
}

And now all the time that would be wasted by delay() can be used for other things. For example another LED strip that should be change at the same time.

Look in the FastLED example DemoReel100 - there's examples of using the macros EVERY_N_MILLISECONDS and EVERY_N_SECONDS to do what you want (which is, something every few milliseconds or seconds, without constantly calling delay).

This is a version of the AdaFruit strand test that is non blocking and advances through the diffrent patterns at a push of a button.

// StrandTest from AdaFruit implemented as a state machine
// pattern change by push button
// By Mike Cook Jan 2016

#define PINforControl   7 // pin connected to the small NeoPixels strip
#define NUMPIXELS1      256 // number of LEDs on strip

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS1, PINforControl, NEO_GRB + NEO_KHZ800);

unsigned long patternInterval = 20 ; // time between steps in the pattern
unsigned long lastUpdate = 0 ; // for millis() when last update occoured
unsigned long intervals [] = { 20, 20, 50, 100 } ; // speed for each pattern
const byte button = 2; // pin to connect button switch to between pin and ground

void setup() {
  strip.begin(); // This initializes the NeoPixel library.
  wipe(); // wipes the LED buffers
  pinMode(button, INPUT_PULLUP); // change pattern button
}

void loop() {
  static int pattern = 0, lastReading;
  int reading = digitalRead(button);
  if(lastReading == HIGH && reading == LOW){
    pattern++ ; // change pattern number
    if(pattern > 3) pattern = 0; // wrap round if too big
    patternInterval = intervals[pattern]; // set speed for this pattern
    wipe(); // clear out the buffer 
    delay(50); // debounce delay
  }
  lastReading = reading; // save for next time

if(millis() - lastUpdate > patternInterval) updatePattern(pattern);
}

void  updatePattern(int pat){ // call the pattern currently being created
  switch(pat) {
    case 0:
        rainbow(); 
        break;
    case 1: 
        rainbowCycle();
        break;
    case 2:
        theaterChaseRainbow(); 
        break;
    case 3:
         colorWipe(strip.Color(255, 0, 0)); // red
         break;     
  }  
}

void rainbow() { // modified from Adafruit example to make it a state machine
  static uint16_t j=0;
    for(int i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
     j++;
  if(j >= 256) j=0;
  lastUpdate = millis(); // time for next change to the display
  
}
void rainbowCycle() { // modified from Adafruit example to make it a state machine
  static uint16_t j=0;
    for(int i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
  j++;
  if(j >= 256*5) j=0;
  lastUpdate = millis(); // time for next change to the display
}

void theaterChaseRainbow() { // modified from Adafruit example to make it a state machine
  static int j=0, q = 0;
  static boolean on = true;
     if(on){
            for (int i=0; i < strip.numPixels(); i=i+3) {
                strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
             }
     }
      else {
           for (int i=0; i < strip.numPixels(); i=i+3) {
               strip.setPixelColor(i+q, 0);        //turn every third pixel off
                 }
      }
     on = !on; // toggel pixelse on or off for next time
      strip.show(); // display
      q++; // update the q variable
      if(q >=3 ){ // if it overflows reset it and update the J variable
        q=0;
        j++;
        if(j >= 256) j = 0;
      }
  lastUpdate = millis(); // time for next change to the display    
}

void colorWipe(uint32_t c) { // modified from Adafruit example to make it a state machine
  static int i =0;
    strip.setPixelColor(i, c);
    strip.show();
  i++;
  if(i >= strip.numPixels()){
    i = 0;
    wipe(); // blank out strip
  }
  lastUpdate = millis(); // time for next change to the display
}


void wipe(){ // clear all LEDs
     for(int i=0;i<strip.numPixels();i++){
       strip.setPixelColor(i, strip.Color(0,0,0)); 
       }
}

uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
4 Likes

Grumpy_Mike:
This is a version of the AdaFruit strand test that is non blocking and advances through the diffrent patterns at a push of a button.

Thanks for this. I been looking for for this!

Here's some non-blocking code I found

uint32_t red = strip.Color(255, 0, 0);

void loop() {
  colorWipe_smart(red);
}

void colorWipe_smart(uint32_t color) {
  static uint8_t wait = 50;
  static unsigned long lastUpdate = 0;
  static uint16_t currentLed = 0;
 
  unsigned long now = millis();
  if (now > lastUpdate+delay) {
    strip.setPixelColor(currentLed, color);
    strip.show();   
    currentLed = currentLed>strip.numPixels() ? 0 : currentLed+1;
    lastUpdate = now;
  }
}

Bringing a helpful thread back from the dead! Mike you helped me out so much, however I do have a question. When I modify your code to include more than 3 cases, why will it just freeze the state of case 3? I have modified the if (pattern > 5) pattern = 0 to include the new cases but still nothing. Thanks again!

Post your code!

Did you set up an interval for the new patterns, in the array on line 3?

PaulRB:
Post your code!

Did you set up an interval for the new patterns, in the array on line 3?

That was my mistake. Thank you. You have no idea how much your post helped!

I am wondering if anyone has an example code to have a pixel fade from one color to another and then back in the same style as Paul? I have looked at a tutorial that adafruit has for their Neopixels, however it seems to be in a different style.

in the same style as Paul?

Huh?

To fade from one colour to another, you could use map() function. Suppose you want to fade from colour (r1,g1,b1) to (r2,g2,b2) over time period t1 to t2. The formula for r at time t would be map(t,t1,t2,r1,r2). Similar for g and b.

PaulRB:
Huh?

I am new to all of this (I am sure you can tell). I guess the correct wording should have format, not style. Thanks for the help, am I on the correct path? I know I have not defined t. Not sure exactly how to define it.

void RedtoGreen() {
  uint32_t R = strip.Color(255, 0, 0);
  uint32_t G = strip.Color(0, 255, 0);
  uint32_t B = strip.Color(0, 0, 255);
  
  R = map(t, 0, 1000, 255 ,0);
  G = map(t, 0, 1000, 0, 255);
  B = map(t, 0, 1000, 0, 0);
    
    strip.show();
}

I'm sorry, your code makes no sense at all. I thought you might need a little push in the right direction, apologies for misjudging your needs. Given that you will need much more detailed guidance, perhaps you could explain in more detail what it is you want to do, so we don't waste time creating something that doesn't do what you want. You say you want to fade between two colours, but which two, how will the colours be chosen? Will just one pixel be doing this fade, or all of them? If just one, what will the others be doing?

I program large light shows at Christmas time so once I had a project idea I thought that I would be able to jump in and make it work. I misjudged the complexity of this. My project is a fiber optic hat that will cycle through looping sequences with a push button. I am using 7 Neopixels and have taken your example from above with success. My final wish would be to have the pixels fade between two colors until the button push. I would prefer to have half color 1 to color 2, and the other half opposite. If I could have the timing random between different pixels it would be ideal, however, I am sure that is much above my current level. I appreciate the help so far and I apologize for not being super clear.

Good. So you want to use Mike's code and add this new 2-colour fade pattern? You want each of the 7 pixels to fade between two colours art random intervals. What would be the slowest and fastest interval, in seconds? How are the colours chosen? Do all pixels use the same two colours?

If you want to fade between two colours you first need to know how many steps you want to use call it numberOfSteps. Then take the difference between each colour and divide it by the number of steps to get an increment. Their will be three increments one for each RGB. This will also need to be a floating point variable.

Then at each call of the state machine function add the increment value to the current colour at time intervals of your choosing until the number of steps has been made.

Grumpy_Mike:
If you want to fade between two colours you first need to know how many steps you want to use call it numberOfSteps. Then take the difference between each colour and divide it by the number of steps to get an increment. Their will be three increments one for each RGB. This will also need to be a floating point variable.

Then at each call of the state machine function add the increment value to the current colour at time intervals of your choosing until the number of steps has been made.

I am kind of understanding what needs to be done. I have found the following code and I think it does what you are saying. Correct me if I am wrong, but what I have is a definition of Color 1 and 2 as well as each of the three colors. The ColorSet is combining each of the 3 colors and defining the color? How would I get the Red, Green, and Blue to be declared? Thank you for helping, I am completely new and both you and Paul have been very patient and helpful.

void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval)
    {

        Interval = interval;
        TotalSteps = steps;
        Color1 = color1;
        Color2 = color2;
        Index = 0;
        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));

        strip.show();
    }

Well not quite.
First off when ever you go:- uint8_t you are defining a new variable so don't do that make them global variables or static ones.
Next I said make the increment value a float type, and have one for each of the colours, you haven't done that.
Next your value of index is always zero, it never changes. Make it a static variable and increment it on each entry.

The code to set up the fixed variables should be done when the index is zero and at no other time. It is probably best to use a separate setup function for this.
I don't understand what

Red(Color1)

does. Especially as the parameter passed to it is a long int, it doesn't make sense to me.

I think I might be at the point of diminishing returns. I don't give up easily but I am way over my head. I have no idea how to separate to each RGB increment. I have looked up how to use float but do I use that for each R, G, & B? I just have no idea even where to start now. It seems with my limited experience that I start to understand but only to find out that I still am clueless.