Programming NeoPixels to Show "Running LEDs"

Hey everyone, so i am pretty new to neopixels and i am currently programming running leds. so basically a certain amount of leds say 8 leds. will shoot across the strip. I have this paired up with a max program that detects when there is a spike in the low end, thus sending a value of one to arduino and calling the function to turn the leds on. The issue i am having is that if there are multiple beats within a second the led has to finish its loop, so run through all 50 leds before it can start the next cycle… Is it possible to make it so that if once instance is already running it will continue to call the function and send another strip of leds to run across? here is the code i have so far. Also my apologies if this is in the wrong section, i am new here :stuck_out_tongue:

void reactLEDStrip (){
  if(onOff == 1){
    
  for(int i = 0; i < NUM_LEDS; i++)
    {
     leds[i].setHue(random(256)); 
     FastLED.show();
     leds[i].setRGB( 0, 0, 0);
     delay(50);
    }
  } 
}

I have just realized there is a section specific to LEDs, i apologize. I also have no idea how to move my topic ...

Click on "Report to Moderator" and ask the very nice moderator (not kidding, the moderators are usually nice) to move it for you.

Get rid of the delay() in favour of a millis() based approach.

Ah, thank you so much!

SteveMann:
Click on "Report to Moderator" and ask the very nice moderator (not kidding, the moderators are usually nice) to move it for you.

Hmm, I've never used millis() but ill certainly look into it and give it a shot, thank you for the suggestion! ill keep you updated.

sterretje:
Get rid of the delay() in favour of a millis() based approach.

So ive been at it for about an hour and i cant seem to figure out how to properly use millis() for what i need it to do… heres what i currently have

void reactLEDStrip (){
 
  unsigned long currentMillis = millis();
  
  if(onOff == 1 && currentMillis - previousMillis >= interval){
    
  for(int i = 0; i < NUM_LEDS; i++)
    {
     leds[i].setHue(random(256)); 
     FastLED.show();
     leds[i].setRGB( 0, 0, 0);
    }
  } 
}

As ive said before, i have never used millis() so i am very confused on its usage despite reading up on it. Note: i had my interval set to 30 and 1000 but it did not help.

sterretje:
Get rid of the delay() in favour of a millis() based approach.

The other thing to get rid off is the for-loop.

Please post your complete code.

Thread moved as requested.

One of the reasons why I asked for full code is that I don’t know if you ever update previousMillis and how you obtain onoff.

Below is a reworked version of your function. I did not implement onoff. It uses a number of static variables so it’s self-contained. Static variables are like global variables, but are only known in the function where they are declared. I hope that the code is sufficiently documented for you to understand; if not, ask.
The function returns true once all leds are done, else false.

I’ve used print statements to print what is happening

/*
  non-blocking update of strip
  Returns:
    true if function completed one cycle, else false
*/
bool reactLEDStrip()
{
  // variable to remember that last time that the strip was updated; replace your previousMillis
  static uint32_t lastUpdateTime;
  // variable to remember the last updated led; replaces i in your for-loop
  static uint16_t ledCnt;

  // current time
  uint32_t currentTime = millis();

  // check if it's time to update the strip
  if (currentTime - lastUpdateTime >= interval)
  {
    // print some info
    Serial.print(F("Updating led "));
    Serial.print(ledCnt);
    Serial.println(F(" in strip"));

    // update the last time that the strip was updated
    lastUpdateTime = currentTime;

    // your original code here
    leds[ledCnt].setHue(random(256));
    FastLED.show();
    leds[ledCnt].setRGB( 0, 0, 0);

    // update the led count
    ledCnt++;
    // if at end of strip
    if (ledCnt == NUM_LEDS)
    {
      // inform user
      Serial.println(F("End of strip reached"));
      // start from the beginning
      ledCnt = 0;
      return true;
    }
  }
  return false;
}

You can use the function as shown below (function itself not included). This makes use of the return value so you can check in loop() if a cycle was completed.

#include <FastLED.h>

#define NUM_LEDS 20
#define DATA_PIN 6

uint32_t interval = 500;

CRGB leds[NUM_LEDS];

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

  Serial.begin(57600);
}

void loop()
{
  bool isCompleted;
  isCompleted = reactLEDStrip();
  if (isCompleted == true)
  {
    Serial.println(F("Completed"));
  }
}

The method you are using isn’t going to work well with multiple pulses, because you would need to keep track of the position of each pulse, then turn on the appropriately positioned LEDs within the strip, and also you have no idea how many pulses may be running at once.

Would be easier to feed the pulses in from the start of the LED strip, then progressively shift them towards the end of the strip, although with your code the color of the pixel also needs to randomly change as it is being moved.

Here is a sample code to demonstrate that technique:

#include <FastLED.h>

#define DATA_PIN    6
#define NUM_LEDS    50
#define BRIGHTNESS  16
CRGB leds[NUM_LEDS];

unsigned long currentMillis;
unsigned long previousMillis;
unsigned int timeDelay = 50u; //50mS delay between LED updates
int pulseLength = 8; //number of LEDs in a pulse
byte onOff = 0;

void setup() {
  // FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  LEDS.setBrightness(BRIGHTNESS);
}

void loop() {
  currentMillis = millis();

  if ((currentMillis - previousMillis) >= timeDelay) {
    previousMillis = currentMillis;

    //this randomly starts a new pulse about 1 % of the time for test purposes
    if (random(100) == 47) {
      onOff = 1;
    }

    reactLEDStrip();
  }
}

void reactLEDStrip () {
  static byte pulseIn = 0; //LED pulse to feed into the start of the LED strip

  if (onOff == 1) { //check to see if a new pulse needs to be started
    pulseIn = pulseLength; //set length of pulse to feed into LED strip
    onOff = 0;
  }

  for (int i = NUM_LEDS - 1; i > 0; i--) { //start at end of LED strip and work towards start
    if ((leds[i - 1].r || leds[i - 1].g || leds[i - 1].b) == 0x00) { //check to see if LED is turned off (all colors set to 00)
      leds[i] = leds[i - 1]; //if LED is turned off, shift it up one position
    } else {
      leds[i].setHue(random(256)); //if LED is not turned off, set it to a new random color while shifting up one position
    }
  }

  if (pulseIn == 0) {
    leds[0] = CRGB(0, 0, 0); //turn off first LED if not feeding in a new pulse
  } else {
    leds[0].setHue(random(256)); //if feeding in a new pulse, set first LED to random color
    pulseIn--; //update number of LEDs left in the current pulse
  }

  FastLED.show();
}

Here is my full code (for what i did last night).

#include <FastLED.h>

#define LED_PIN     2
#define NUM_LEDS    50
#define BRIGHTNESS  255
#define LED_TYPE    WS2811
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

#define UPDATES_PER_SECOND 100

int onOff;
unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 30;



void setup() {

  Serial.begin(9600);
  //delay( 3000 ); // power-up safety delay
  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  FastLED.setBrightness(  BRIGHTNESS );

  startMillis = millis();
}


void loop() {

  if (Serial.available()) {

    onOff = Serial.read();

  }

  reactLEDStrip();

  FastLED.delay(1000 / UPDATES_PER_SECOND);
}

//NOT WORKING -- NEED TO BYPASS CYCLE LOOP
//reacts to led
void reactLEDStrip () {

  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    if (onOff == 1) {

      for (int i = 0; i < NUM_LEDS; i++)
    {
      leds[i].setHue(random(256));
      FastLED.show();
  
      leds[i].setRGB( 0, 0, 0);
  
      startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
    }

  }
  FastLED.delay(1000 / UPDATES_PER_SECOND);

  }
  }

i will try what you suggested now and see if it works. It makes sense to me as far as im reading it. As per my onOff values, they are coming from MAX MSP which keeps track of music, whenever the low end spikes it send a value of 1 to the arduino serial which is then read and updated to a variable. Thats how my onOff gets it values

sterretje:
One of the reasons why I asked for full code is that I don’t know if you ever update previousMillis and how you obtain onoff.

Below is a reworked version of your function. I did not implement onoff. It uses a number of static variables so it’s self-contained. Static variables are like global variables, but are only known in the function where they are declared. I hope that the code is sufficiently documented for you to understand; if not, ask.
The function returns true once all leds are done, else false.

I’ve used print statements to print what is happening

/*

non-blocking update of strip
  Returns:
    true if function completed one cycle, else false
*/
bool reactLEDStrip()
{
  // variable to remember that last time that the strip was updated; replace your previousMillis
  static uint32_t lastUpdateTime;
  // variable to remember the last updated led; replaces i in your for-loop
  static uint16_t ledCnt;

// current time
  uint32_t currentTime = millis();

// check if it’s time to update the strip
  if (currentTime - lastUpdateTime >= interval)
  {
    // print some info
    Serial.print(F(“Updating led “));
    Serial.print(ledCnt);
    Serial.println(F(” in strip”));

// update the last time that the strip was updated
    lastUpdateTime = currentTime;

// your original code here
    leds[ledCnt].setHue(random(256));
    FastLED.show();
    leds[ledCnt].setRGB( 0, 0, 0);

// update the led count
    ledCnt++;
    // if at end of strip
    if (ledCnt == NUM_LEDS)
    {
      // inform user
      Serial.println(F(“End of strip reached”));
      // start from the beginning
      ledCnt = 0;
      return true;
    }
  }
  return false;
}




You can use the function as shown below (function itself not included). This makes use of the return value so you can check in loop() if a cycle was completed.


#include <FastLED.h>

#define NUM_LEDS 20
#define DATA_PIN 6

uint32_t interval = 500;

CRGB leds[NUM_LEDS];

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

Serial.begin(57600);
}

void loop()
{
  bool isCompleted;
  isCompleted = reactLEDStrip();
  if (isCompleted == true)
  {
    Serial.println(F(“Completed”));
  }
}

This method worked perfect! The one that sterretje suggested worked, however there was still a delay where the leds had to wait a certain period of time. i just had to make a few modifications to your code them implement it into my main program flawlessly. Thank you so much!

david_2018:
The method you are using isn’t going to work well with multiple pulses, because you would need to keep track of the position of each pulse, then turn on the appropriately positioned LEDs within the strip, and also you have no idea how many pulses may be running at once.

Would be easier to feed the pulses in from the start of the LED strip, then progressively shift them towards the end of the strip, although with your code the color of the pixel also needs to randomly change as it is being moved.

Here is a sample code to demonstrate that technique:

#include <FastLED.h>

#define DATA_PIN    6
#define NUM_LEDS    50
#define BRIGHTNESS  16
CRGB leds[NUM_LEDS];

unsigned long currentMillis;
unsigned long previousMillis;
unsigned int timeDelay = 50u; //50mS delay between LED updates
int pulseLength = 8; //number of LEDs in a pulse
byte onOff = 0;

void setup() {
  // FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  LEDS.setBrightness(BRIGHTNESS);
}

void loop() {
  currentMillis = millis();

if ((currentMillis - previousMillis) >= timeDelay) {
    previousMillis = currentMillis;

//this randomly starts a new pulse about 1 % of the time for test purposes
    if (random(100) == 47) {
      onOff = 1;
    }

reactLEDStrip();
  }
}

void reactLEDStrip () {
  static byte pulseIn = 0; //LED pulse to feed into the start of the LED strip

if (onOff == 1) { //check to see if a new pulse needs to be started
    pulseIn = pulseLength; //set length of pulse to feed into LED strip
    onOff = 0;
  }

for (int i = NUM_LEDS - 1; i > 0; i–) { //start at end of LED strip and work towards start
    if ((leds[i - 1].r || leds[i - 1].g || leds[i - 1].b) == 0x00) { //check to see if LED is turned off (all colors set to 00)
      leds[i] = leds[i - 1]; //if LED is turned off, shift it up one position
    } else {
      leds[i].setHue(random(256)); //if LED is not turned off, set it to a new random color while shifting up one position
    }
  }

if (pulseIn == 0) {
    leds[0] = CRGB(0, 0, 0); //turn off first LED if not feeding in a new pulse
  } else {
    leds[0].setHue(random(256)); //if feeding in a new pulse, set first LED to random color
    pulseIn–; //update number of LEDs left in the current pulse
  }

FastLED.show();
}