BlinkWithoutDelay style timing and NeoPixels [solved!]

I have a project I'm nearly done with. It's a strip of NeoPixels controlled with a Nano and manipulated with a button. I don't have hardly any experience coding, so most of the code I used was picked up from other projects. Most other projects didn't use a button though, so I'm trying to convert them to use the BlinkWithoutDelay style timing. That way, a button will be responsive. It works with the rainbow and rainbow cycle functions, but I can't figure out how to get a color to fade in from black and then fade out again smoothly.

This is what I have. It only fades in then starts over. Can someone help me fade it out as well?

void fadeIn(uint32_t c, uint8_t brightness, uint8_t wait) {
  
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > wait) {
  
    //set the color of all pixels
    allColor(c);
    
    // save the last time you changed a NeoPixel 
    previousMillis = currentMillis; 
    
    uint16_t i;
    int b = (neoPixel_j * brightness) / brightness;
    strip.setBrightness(b);
    strip.show(); 
    neoPixel_j = (neoPixel_j + 1) % brightness;
  }
}

I'd also like to be able to do the theater chase with BlinkWithoutDelay style timing. Can someone help me convert this code?

void theaterChase(uint32_t c, uint8_t wait) {
  
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();
     
      delay(wait);
     
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }

Thanks very much to any and all who help. I'm very new at this but it's been a lot of fun so far.

I can't make sense of your first code snippet in the absence of the rest of the code that uses it.

The second piece looks like it needs to be converted into a state machine - which is a grand way of saying that you need some variables to record the state or position in the sequence it has got to so that each iteration of the code (when the time interval expires) will move it on to the next state.

The demo several things at a time may help to illustrate the concept.

...R

Thanks for the reply! Heres the rest of the code. It's kind of long so I removed the unnecessary stuff

    #include <Adafruit_NeoPixel.h>
    #define PIN 6    
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(30, PIN, NEO_GRB + NEO_KHZ800);
    const int buttonPin = 2;    // momentary push button on pin 0
    const int numPixelsInStrip = 30;
        
    // Variables will change:
    int ledState = HIGH; // the current state of the output pin
    int buttonState; // the current reading from the input pin
    int lastButtonState = LOW; // the previous reading from the input pin
    long lastDebounceTime = 0; // the last time the output pin was toggled
    long debounceDelay = 50; // the debounce time; increase if the output flickers
    long previousMillis; // will store last time pixel was updated
    int neoPixelToChange = 0; //track which neoPixel to change
    int neoPixel_j = 0; //stores values for program cycles
    int nPatterns = 1;  //number of patterns to rotate through
    int lightPattern = 1; //rotates between patterns with a button press
    int defaultBrightness = 64;
    
    //cylon variables
    int fadeDirection = -1;//change sigen to fade up or down
    boolean cylonDirection = true; //keeps track of the direction the pixels should swipe
    boolean cylonPause = false; //keeps track of the pause inbetween swipes
    long delayMillis = 0; // will store the last time the cylon swipe was paused

//----------------------------------------------------------------------------------------------
// the setup routine runs once when you press reset:
    void setup() {
    strip.begin();
    strip.show();                // initialize all pixels to 'off'  
    strip.setBrightness(defaultBrightness); // initialize brightness  
    pinMode(buttonPin, INPUT);   // initialize the BUTTON pin as an input
    
}

//=============================================================================================
// the loop routine runs over and over again forever;  
  void loop() {
  
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;
      
      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {        
        //change the program
        lightPattern = (lightPattern + 1) % (nPatterns + 1); //include numOfPrograms + 1, since there is an off state
      }
    }
  }

  // save the reading.  Next time through the loop
  lastButtonState = reading;
 //----------------------------------------------------------------------------------------------------- 
  switch(lightPattern) {
    case 1:
      allColor(strip.Color(255,255,150)); //off white
      break;
  }
}
//=============================================================================================
// Fill all the dots with one color
void allColor(uint32_t c) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
  }
} 
 
//----------------------------------------------------------------------------------------------
//fades in, then shuts off
void softBlink(uint32_t c, uint8_t brightness, uint8_t wait) {
  
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > wait) {
  
    //set the color of all pixels
    allColor(c);
    
    // save the last time you changed a NeoPixel 
    previousMillis = currentMillis; 
    
    uint16_t i;
    int b = (neoPixel_j * brightness) / brightness;
    strip.setBrightness(b);
    strip.show(); 
    neoPixel_j = (neoPixel_j + 1) % brightness;
  }
}

I've been playing with this seemingly forever and I can't seem to get it. I've found other scripts online that fade in and out, but I can't get them to respond to a button press, and I'm not sure why.

#include <Adafruit_NeoPixel.h>

#define PIN 6
#define PIXEL 60

Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}


void loop() {
  int R = 0;
  int G = 0;
  int B = 0;
  //Fade in
  for(R && G && B; R<126 && G<126 && B<126; R++ && G++ && B++) {
    for(int i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, strip.Color(R, G, B));
      strip.show();
      delay(0);
    }
    delay(1);
  }
  //Fade Out
  for(R && G && B; R>-1 && G>-1 && B>-1; R-- && G-- && B--) {
    for(int j=0; j<strip.numPixels(); j++) {
      strip.setPixelColor(j, strip.Color(R, G, B));
      strip.show();
      delay(0);
    }
    delay(1);
  }
}

I've been playing with this code, trying to implement the blink without delay style of timing, but I can't get it to work. It just cycles through the fade without responding to the button at all.

Is there any way to make the first sketch (which responds nicely to a button) also fade out? or how to make the second sketch respond to a button?

  for(R && G && B; R<126 && G<126 && B<126; R++ && G++ && B++) {

The WTF light just exploded. Just exactly what is that initialization statement trying to do? What is that increment statement trying to do? Neither one is correct for a compound for loop. Commas go between sections, not &&.

I've been playing with this code, trying to implement the blink without delay style of timing, but I can't get it to work. It just cycles through the fade without responding to the button at all.

     strip.show();
      delay(0);
    }
    delay(1);

In addition to what @PaulS said it is a peculiar feature of Blink Without Delay that the function delay() is not used.

This demo several things at a time may help to explain the concept.

...R

PaulS:

  for(R && G && B; R<126 && G<126 && B<126; R++ && G++ && B++) {

The WTF light just exploded. Just exactly what is that initialization statement trying to do? What is that increment statement trying to do? Neither one is correct for a compound for loop. Commas go between sections, not &&.

Hi Paul, thanks for the reply. I'm only starting to scratch the surface of C/C++ so when I piece together code, sometimes it gets wonky. That bit was from Neo pixel fade in/out? - adafruit industries. I think it had to do with the increment of the light increase (larger number = smoother fade?) but I'm not sure. Anyway, I've put together another program that I think should work better. Please see below.

Robin2:

I've been playing with this code, trying to implement the blink without delay style of timing, but I can't get it to work. It just cycles through the fade without responding to the button at all.

     strip.show();

delay(0);
    }
    delay(1);




In addition to what @PaulS said it is a peculiar feature of Blink Without Delay that the function delay() is not used.

This demo [several things at a time](http://forum.arduino.cc/index.php?topic=223286.0) may help to explain the concept.

...R

Thanks again, Robin. I had a look at that example, and it makes sense, but I'm not sure I fully understand. Like I said, I'm very new that this, so bare with me. I think I'm finally starting to begin to understand the blink w/o delay concept though. I put together a new sketch with what I've learned. Focusing on the fade program near the bottom, the program has to cycle through the "if(currentMillis - previousMillis > wait) {" loop without getting caught in any loops inside it (ie. we can't use the "for" command). That way, it checks the button with every cycle (or every increment of light increase). Is that correct? The program below still isn't responding to a button press. Can anyone see what is amiss this time?

 #include <Adafruit_NeoPixel.h>
    #define PIN 6    
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(30, PIN, NEO_GRB + NEO_KHZ800);
    const int buttonPin = 2;    // momentary push button on pin 0
    const int numPixelsInStrip = 30;
        
    // Variables will change:
    int ledState = HIGH; // the current state of the output pin
    int buttonState; // the current reading from the input pin
    int lastButtonState = LOW; // the previous reading from the input pin
    long lastDebounceTime = 0; // the last time the output pin was toggled
    long debounceDelay = 50; // the debounce time; increase if the output flickers
    long previousMillis; // will store last time pixel was updated
    int neoPixel_j = 0;
    int nPatterns = 1;  //number of patterns to rotate through
    int lightPattern = 1; //rotates between patterns with a button press
    int defaultBrightness = 127;

//----------------------------------------------------------------------------------------------
// the setup routine runs once when you press reset:
    void setup() {
    strip.begin();
    strip.show();                // initialize all pixels to 'off'  
    strip.setBrightness(defaultBrightness); // initialize brightness  
    pinMode(buttonPin, INPUT);   // initialize the BUTTON pin as an input
    
}

//====================================================================
// the loop routine runs over and over again forever;  
  void loop() {
  
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;
      
      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {        
        //change the program
        lightPattern = (lightPattern + 1) % (nPatterns + 1); //include numOfPrograms + 1, since there is an off state
      }
    }
  }

  // save the reading.  Next time through the loop
  lastButtonState = reading;
 //----------------------------------------------------------------------------------------------------- 
  switch(lightPattern) {
    case 1:
      fade(strip.Color(0,0,0),10);
      break;

  }
}

void fade(uint32_t c, uint8_t wait) {

for(uint16_t i=0; i<127; i++) {  
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > wait) {
        previousMillis = currentMillis; 
        allColor(strip.Color(neoPixel_j,neoPixel_j,neoPixel_j));
        strip.show();
        neoPixel_j = (neoPixel_j  + 1);
  }
}
neoPixel_j = 0;
for(uint16_t i=0; i<127; i++) {  
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > wait) {
        previousMillis = currentMillis; 
        allColor(strip.Color(defaultBrightness,defaultBrightness,defaultBrightness));
        strip.show();
        defaultBrightness = (defaultBrightness -  1);
  }
}
defaultBrightness = 127;
}

void allColor(uint32_t c) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
  }
}
for(uint16_t i=0; i<127; i++) {  
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > wait) {
        previousMillis = currentMillis; 
        allColor(strip.Color(neoPixel_j,neoPixel_j,neoPixel_j));
        strip.show();
        neoPixel_j = (neoPixel_j  + 1);
  }
}

How long will it take to run through this for loop? It depends on previousMillis and wait, doesn't it? Some iterations will take no time. Others will take longer. But, overall, how long will each color be shown?

I think you'll be very hard-pressed to find an example of blink without delay that uses a for loop (or that uses it for timing stuff). The blink without delay philosophy is NOT a direct replacement for delay(). It is a mind set that causes one to approach writing code completely differently.

PaulS:
It is a mind set that causes one to approach writing code completely differently.

+1

Instead of doing all of the fade in a single FOR loop each step of that process should take place in subsequent iterations of loop() and there should be a variable somewhere (I would use a global variable) to keep track of what stage of the fade things are at.

As a learning exercise you might try modifying one of the LED flash functions in several things at a time to make it fade the LED.

And apologies for posting the link twice - the grey cells are not what they used to be.

...R

PaulS:
How long will it take to run through this for loop? It depends on previousMillis and wait, doesn't it? Some iterations will take no time. Others will take longer. But, overall, how long will each color be shown?

I think you'll be very hard-pressed to find an example of blink without delay that uses a for loop (or that uses it for timing stuff). The blink without delay philosophy is NOT a direct replacement for delay(). It is a mind set that causes one to approach writing code completely differently.

I thought it would only depend on the wait time, so 10ms in my case, but I suppose I'm mistaken. I'm realizing that this may be a bit over my head. And I think you're probably exactly right with that last statement. It's fascinating, I just need more time to learn the basics I think.

Robin2:

PaulS:
It is a mind set that causes one to approach writing code completely differently.

+1

Instead of doing all of the fade in a single FOR loop each step of that process should take place in subsequent iterations of loop() and there should be a variable somewhere (I would use a global variable) to keep track of what stage of the fade things are at.

As a learning exercise you might try modifying one of the LED flash functions in several things at a time to make it fade the LED.

And apologies for posting the link twice - the grey cells are not what they used to be.

...R

Hmmm I think I understand what you are saying. So increment the brightness each time through the loop so that you can return to the top of the program as fast as possible. I think that's pretty much what happens in softBlink in this code:

    #include <Adafruit_NeoPixel.h>
    #define PIN 6    
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(30, PIN, NEO_GRB + NEO_KHZ800);
    const int buttonPin = 2;    // momentary push button on pin 0
    const int numPixelsInStrip = 30;
        
    // Variables will change:
    int ledState = HIGH; // the current state of the output pin
    int buttonState; // the current reading from the input pin
    int lastButtonState = LOW; // the previous reading from the input pin
    long lastDebounceTime = 0; // the last time the output pin was toggled
    long debounceDelay = 50; // the debounce time; increase if the output flickers
    long previousMillis; // will store last time pixel was updated
    int neoPixelToChange = 0; //track which neoPixel to change
    int neoPixel_j = 0; //stores values for program cycles
    int nPatterns = 1;  //number of patterns to rotate through
    int lightPattern = 1; //rotates between patterns with a button press
    int defaultBrightness = 64;
    
    //cylon variables
    int fadeDirection = -1;//change sigen to fade up or down
    boolean cylonDirection = true; //keeps track of the direction the pixels should swipe
    boolean cylonPause = false; //keeps track of the pause inbetween swipes
    long delayMillis = 0; // will store the last time the cylon swipe was paused

//----------------------------------------------------------------------------------------------
// the setup routine runs once when you press reset:
    void setup() {
    strip.begin();
    strip.show();                // initialize all pixels to 'off'  
    strip.setBrightness(defaultBrightness); // initialize brightness  
    pinMode(buttonPin, INPUT);   // initialize the BUTTON pin as an input
    
}

//=============================================================================================
// the loop routine runs over and over again forever;  
  void loop() {
  
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;
      
      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {        
        //change the program
        lightPattern = (lightPattern + 1) % (nPatterns + 1); //include numOfPrograms + 1, since there is an off state
      }
    }
  }

  // save the reading.  Next time through the loop
  lastButtonState = reading;
 //----------------------------------------------------------------------------------------------------- 
  switch(lightPattern) {
    case 1:
      softBlink(strip.Color(255,255,150), 35, 10); //off white
      break;
  }
}
//=============================================================================================
// Fill all the dots with one color
void allColor(uint32_t c) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
  }
} 
 
//----------------------------------------------------------------------------------------------
//fades in, then shuts off
void softBlink(uint32_t c, uint8_t brightness, uint8_t wait) {
  
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > wait) {
  
    //set the color of all pixels
    allColor(c);
    
    // save the last time you changed a NeoPixel 
    previousMillis = currentMillis; 
    
    uint16_t i;
    int b = (neoPixel_j * brightness) / brightness;
    strip.setBrightness(b);
    strip.show(); 
    neoPixel_j = (neoPixel_j + 1) % brightness;
  }
}

Isn't that right? I guess I just don't understand it well enough to be able to fade it back down. How do I increment the brightness to a certain level without a "for" statement? should I increment a variable in this part of the code?

 switch(lightPattern) {
    case 1:
      softBlink(strip.Color(255,255,150), 35, 10); //off white
      break;

Sorry, I know I have a lot of questions. I'll try some more stuff tonight when I have my set up in front of me. I just feel like I'm so close and it's very frustrating. Thanks for all of your help Paul and Robin

you can simplify your code here

  switch(lightPattern) 
  {
  case 1:
    softBlink(strip.Color(255,255,150), 35, 10); //off white
    break;
  }

as you only have one case:

if (lightPattern == 1) softBlink(strip.Color(255,255,150), 35, 10); //off white

what is your variable i doing here?

void softBlink(uint32_t c, uint8_t brightness, uint8_t wait) 
{
  if(millis() - previousMillis > wait) 
  {
    allColor(c);
    uint16_t i;//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    int b = (neoPixel_j * brightness) / brightness;
    strip.setBrightness(b);
    strip.show(); 
    neoPixel_j = (neoPixel_j + 1) % brightness;
    previousMillis = currentMillis; 
  }
}

difficult to understand what you want to do in that function...

are you trying to change the brightness? nowhere in loop() are you incrementing/decrementing the argument brightness that you are passing to the function...

also, what do you expect this to do?

    int b = (neoPixel_j * brightness) / brightness;}

(anything * brightness) / brightness == anything

BulldogLowell:
you can simplify your code here

  switch(lightPattern) 

{
 case 1:
   softBlink(strip.Color(255,255,150), 35, 10); //off white
   break;
 }




as you only have one case:



if (lightPattern == 1) softBlink(strip.Color(255,255,150), 35, 10); //off white




what is your variable i doing here?



void softBlink(uint32_t c, uint8_t brightness, uint8_t wait)
{
 if(millis() - previousMillis > wait)
 {
   allColor(c);
   uint16_t i;//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   int b = (neoPixel_j * brightness) / brightness;
   strip.setBrightness(b);
   strip.show();
   neoPixel_j = (neoPixel_j + 1) % brightness;
   previousMillis = currentMillis;
 }
}




difficult to understand what you want to do in that function...

are you trying to change the brightness? nowhere in loop() are you incrementing/decrementing the argument brightness that you are passing to the function...

also, what do you expect this to do?



int b = (neoPixel_j * brightness) / brightness;}




(anything * brightness) / brightness == anything

Thanks for your response. I actually have about 14 patterns I want to scroll through, I just removed the unnecessary stuff to keep the code short here. As for that softBlink function, I honestly have no idea what the i is for or why we're multiplying and then dividing by the same number. Didn't make sense to me either, but I figured it was some sort of code nuance that I didn't know about.

All the same I started over yesterday and figured it out. It uses blink w/o delay style timing and a bunch of nested if statements. Might be crude, but I'm quite proud of it. I'll post it when I have access to it tonight.

Thank you, everyone, for your help though this most troubling time. I very much appreciate it.