Non-blocking theater style chase animation for NeoPixels

554 views Asked by At

I am trying to adapt this version of the Adafruit NeoPixel theater chase example to be non-blocking by not using the delay() function and instead of using the millis() function to create a counter, however, I am having no luck as the NeoPixels just light up constantly. Am I missing something? I decided to place the if statement at the point where the nested for loop turns off every 3rd pixel in the strand thinking this would be the spot to put it since in the old code the delay() was called previous to this step.

Here is this version I made which doesn't work:

//Theatre-style crawling lights.
void theaterChase(uint32_t c, const long wait) {
  unsigned long currentMillis = millis();
  for (int j = 0; j < 10; j++) { //do 10 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, c);  //turn every third pixel on
      }
      strip.show();
      if (currentMillis - previousMillis >= wait) {
        previousMillis = currentMillis;
        for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
          strip.setPixelColor(i + q, 0);      //turn every third pixel off
        }
      }
    }
  }
}

and here is the old version:

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}
1

There are 1 answers

0
Dave X On

The for loops wrapped around the delay are what does the blocking.

You have to disassemble the nested for loops that are wrapped around delay() into their constituent parts.

  1. You can turn the for(j...){} loop into the if( currentMillis -last > wait){} conditional and rely on the outer loop() to call this function frequently.
  2. You make q save state with a static and do the iteration arithmetic yourself

Untested code:

//Theatre-style crawling lights.
void theaterChase(uint32_t c, const long wait) {
  static unsigned long last;
  static int q;
  unsigned long currentMillis = millis();
  if( currentMillis -last > wait){
    last = currentMillis;
    if(q >= 3) q = 0;
    if(q < 3){
      for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, c);  //turn every third pixel on
      }
      strip.show();
      // setup to turn them back off during the next iteration
      for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
          strip.setPixelColor(i + q, 0);      //turn every third pixel off
      }
      q++;
    }// if(q ...
  } // if( currentMillis... 
}