Is there way to add an non-blocking delay to this code?

Im trying to add a non-blocking delay to an FastLed animation sketch but when I use millis() it ruins the entire animation. I basically want a delay that only blocks the code INSIDE the function from running until the delay is complete but allows everything outside the function to run freely.

#include "FastLED.h"


#define NUM_LEDS 60
#define DATA_PIN 4

CRGB leds[NUM_LEDS];


void setup() {

  Serial.begin(115200);

  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
}

void loop() {

  theaterChase(systemColor());

}

void theaterChase(CRGB c) {
  for (int q = 0; q < 3; q++) {
    for (int i = 0; i < NUM_LEDS; i = i + 3) {
      leds[i + q] = c;            
      }
      FastLED.show();
      delay(25);
        
      for (int i = 0; i < NUM_LEDS; i = i + 3) {
      leds[i + q] = CRGB::Black;    
      }
  }
}


CRGB systemColor(){
  return CRGB(random(100, 256),0,random(100,256));
}

Post the code with the problem, if you want help fixing it.

Drop the concept of "delay", which is always blocking. What you should do instead is execute actions only when they need to be executed.

Non-blocking timing tutorials:
Blink without delay().
Beginner's guide to millis().
Several things at a time.

1 Like

Those for loops have to go. You need to let loop() do what its name implies and update the equivalent of the for loop variables using millis() for timing

A bruefe example of the principle

unsigned long periodStartTime;
unsigned long currentTime;
const unsigned long period = 1000;
byte xNow = 0;
byte xMax = 5;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  currentTime = millis();
  if (currentTime - periodStartTime >= period)
  {
    Serial.println(xNow); 
    xNow++;
    if (xNow == xMax)
    {
      xNow = 0;
    }
    periodStartTime = currentTime;
  }
  //other code to run in loop() goes here
}

This is what I tried but the issue is that it only times the leds turning off but the function above it keeps running. I want this WHOLE function to not run while it's counting down for 25ms.


#include "FastLED.h"

#define NUM_LEDS 60
#define DATA_PIN 4

CRGB leds[NUM_LEDS];

int period = 25;

unsigned long time_now = 0;

void setup() {
  Serial.begin(115200);
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
}

void loop() {

  theaterChase(systemColor());
}

void theaterChase(CRGB c) {
  for (int q = 0; q < 3; q++) {
    for (int i = 0; i < NUM_LEDS; i = i + 3) {
      leds[i + q] = c;            
      }
      FastLED.show();

      if(millis() >= time_now + period){
        time_now += period;

        for (int i = 0; i < NUM_LEDS; i = i + 3) {
        leds[i + q] = CRGB::Black;    
        }
     }
  }
}


CRGB systemColor(){
  return CRGB(random(100, 256),0,random(100,256));
}

Move the above statement to include all the code that is to be timed.

Incidentally, you are using millis() incorrectly. The statement should be

if(millis() - time_now >= period){

There is a big difference!

1 Like

Thanks, this worked for me.

void theaterChase(CRGB c)  
{
  static unsigned long last;
  static int q;
  unsigned long currentMillis = millis();

  if(currentMillis - last > 25){
    last = currentMillis;

    if(q >= 3) q = 0;

    if(q < 3)
    {
      for (uint16_t i = 0; i < NUM_LEDS; i = i + 3) 
      {
        leds[i + q] = c;  //turn every third pixel on
      }

      FastLED.show();
      // setup to turn them back off during the next iteration
      for (uint16_t i = 0; i < NUM_LEDS; i = i + 3) 
      {
        leds[i + q] = CRGB::Black;       
      }
      q++;
    }
  }  
}

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