FastLED, Visual Looping issue

one element by loop() loop turn

i think i found my answer here
Chasing LEDs millis

So what your saying is to have your code with minimal blocking using millis to limit its availablility to the main loop?

void loop() {
	Constantly refresh/show updates,

        Use millis as switch to limit blocking code run time.  (for loops in here)

        Use millis as second switch to limit blocking code run time (for loops in here)

Why "limiting" blocking code with millis or anything else?
Why not get rid of the blocking code altogether ?

1 Like

What do you want that for loop to do ?
If there is nothing in the body of a for loop to block its execution then it is OK to use it

1 Like

Ok so i have an
arrayofleds = 1,2,3,4,5..,12

is should say

int i =0;
every x milliseconds (if i > ((/sizeof arrayofleds)-1) 
{
i+1;
};
every x milliseconds UpdateLEDS[i]
      for(int j = 1; j <= LightWidthFix; j++) { ///Fill LEDS between two points
       leds[i + j].setRGB(red, green, blue);
      }

That for loop should be finding the leds between I (First LED) and J (Last LED) and Updating the colour values. but because the LED's are in a circle they overlap the array size at the begining and end of the cycle meaning basic math wont give me usable numbers (It exceeds the array size negative and possitive)

where is than part of this if?

1 Like

It is a TWO DIFFERENT PROBLEMS.

Let's choose the some basic index - the led, which will be a starting point of your color sequence.

So all your code can be divided to two part:

  1. Incrementing basic index every NNN mS of time - it can be easily done by each turn of loop() without a for cycle

  2. Calculation of the led numbers, based on basic index - with taking into account the transition through the beginning and end of the cycle and updating its colors.
    This task does not depend on the cycle at all and can be framed as a separate procedure

1 Like

This for loop doesn't contain delays of another blocking elements, so it have not considered as "blocking" itself and not violate a "non-blocking" paradygm

1 Like

Consider something like this

const byte ledPins[] = { 3, 5, 6, 9 };
const byte NUM_LEDS = sizeof(ledPins) / sizeof(ledPins[0]);

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

void loop()
{
    nextCurrentLed();
}

void nextCurrentLed()
{
    static byte count = 0;
    const int period = 2000;
    const unsigned long currentTime = millis();
    static unsigned long startTime = currentTime;
    if (currentTime - startTime >= period)
    {
        Serial.print("current LED number = ");
        Serial.println(count);

        startTime = currentTime;
        nextAndPrevious(count);
        count++;
        count = count % NUM_LEDS;
    }
}

void nextAndPrevious(byte count)
{
    Serial.print("previous LED number = ");
    Serial.println((byte)(count - 1) % NUM_LEDS);
    Serial.print("next LED number = ");
    Serial.println((count + 1) % (NUM_LEDS));
    Serial.println();
}

1 Like

I got it working as desired. Thanks for helping me understand Millis more and modulo seems very usefull.

Wokwi LED Ring - Ajustable

If you see anything in this that you hate or think i should do differently or thanks simply redundant don't hesitate to bring it up.

#include "FastLED.h"

#define NUM_LEDS  12    // Enter the total number of LEDs on the strip
#define PIN       5     // LED signal Pin

int LightWidth = 3;     //Set the number of active LED's
int delayDuration = 100;


CRGB leds[NUM_LEDS];

void setup() {
  Serial.begin(9600);
  FastLED.addLeds<WS2812B, PIN, GRB>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);    // limit power of LED strip to 5V, 500mA
  FastLED.clear();                                    // Init LEDs to "off"
}

void loop() {
  //////(int red, int green, int blue, int LightWidth, int delayDuration)
  Beacon(204, 136, 0, LightWidth, delayDuration);
}

void Beacon(int red, int green, int blue, int LightWidth, int delayDuration){
  int LightWidthFix = LightWidth - 1;

  for(int i = 0; i <= ((NUM_LEDS -LightWidth) + LightWidthFix); i++) {
    FastLED.clear();
    FastLED.show();
    
    leds[i].setRGB(red/10, green/10, blue/10); ///Create Primary Leading LED
      
    int j;                                      ///Create second Trailing LED
    if (i < LightWidthFix ) {
    j = (i + NUM_LEDS) - LightWidthFix;
    leds[j].setRGB(red/10, green/10, blue/10);   
    }
    else{
    j = i -LightWidthFix;      
    leds[j].setRGB(red/10, green/10, blue/10); 
    }    

    if ((i>0)&&(i<LightWidthFix)){                ///Fill from Low fix
      Serial.println("FILL LOW");
      for (int l = i; l >= 0; l--) {
        leds[l].setRGB(red, green, blue);
       }
    }
    
    if ((j<NUM_LEDS)&&(j>(NUM_LEDS-LightWidth))){ ///Fill To High fix
      Serial.println("FILL HIGH");
      for (int l = j; l < NUM_LEDS; l++) {
        leds[l].setRGB(red, green, blue);
       }
    }
    
    if ((i>=LightWidthFix)&&(j<=(NUM_LEDS-LightWidth))){  ///Fill To Main Cycle
      Serial.println("FILL MAIN");
      for (int t = 0; t <= LightWidthFix; t++){
      leds[j+t].setRGB(red, green, blue);
      }
    }

    

    FastLED.show();
    delay(delayDuration);
  }

}

Sorry, did you forget to insert a new code?
I see this everything is the same as before - blocking for loop and delay.
And this code has no millis at all.

1 Like

I see a led sequence of four leds :nerd_face:
The first led in the sequence might be dim, I don't care, it is the first led. The second led will be the bright led.
There is no need to clear all the leds every time. The fourth led in the sequence turns the led off.
So I put four leds in a sequence and let them rotate around:

// Forum: https://forum.arduino.cc/t/fastled-visual-looping-issue/1134527
// This Wokwi project: https://wokwi.com/projects/366722641131463681
//
// A led sequence of four leds:
//   The first is dim
//   The second is bright
//   The third is dim
//   The fourth is off (the default is off)

#include <FastLED.h>

#define NUM_LEDS  12    // Number of NeoPixel leds
#define PIN       5     // Data pin for ledstrip

int index = 0;          // index of led at the front

CRGB leds[NUM_LEDS];
CRGB sequence[4] = {CRGB::DarkViolet, CRGB::Violet, CRGB::DarkViolet, CRGB::Black};

void setup() 
{
  FastLED.addLeds<WS2812B, PIN, GRB>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.clear();       // turn all leds off
}

void loop() 
{
  EVERY_N_MILLISECONDS(150)
  {
    // put the sequence somewhere on the leds
    for(int i=0; i<4; i++)
      leds[ToIndex(index-i)] = sequence[i];

    // Update the ledstrip
    FastLED.show();

    // advance index for next time
    index++;
    if(index >= NUM_LEDS)
      index = 0;
  }
}

// Bring a number into the range of the array.
// A negative number can not be too large.
// but it will work for this code.
int ToIndex(int i)
{
  if(i < 0)
    i += NUM_LEDS;
  return(i % NUM_LEDS);
}

Try it in Wokwi simulation:

  EVERY_N_MILLISECONDS(150)
  {
    // put the sequence somewhere on the leds
    for(int i=0; i<(sizeof sequence); i++)
      leds[ToIndex(index-i)] = sequence[i];

Firstly, YOINK ima borrow this code.

Secondly it's more modular if you do this. Then you only need to change the definitions to update the number of leds in sequence.

EDIT: I lied. Millis is crap. I hate everything. :poop:

Fixed it.

int LEDSequence [5] = {CRGB::LightCoral , CRGB::Goldenrod ,CRGB::Goldenrod , CRGB::LightCoral, CRGB::Black};
CRGB sequence[5] = {CRGB::LightCoral , CRGB::Goldenrod ,CRGB::Goldenrod , CRGB::LightCoral, CRGB::Black};

void loop() 
{
  EVERY_N_MILLISECONDS(150)
  {
    // put the sequence somewhere on the leds
    for(int i=0; i<(sizeof(LEDSequence)); i++)
      leds[ToIndex(index-i)] = sequence[i];

    // Update the ledstrip
    FastLED.show();

That does not fix it. I'm sorry to say, but that code is not good :woozy_face:

The normal way is to divide the whole array by the size of an element.
These show both ways to get the element size. They are both okay.

void setup() 
{
  Serial.begin(115200);
  Serial.println(sizeof(sequence)/sizeof(sequence[0]));
  Serial.println(sizeof(sequence)/sizeof(CRGB));

See how did you know that CRGB is something to get the size of?
Like i can simply count through CRGB leds[NUM_LEDS]; so why do i need to /sizeof (CRGB);?

Any single variable type, structure or class has a size and can be an object of sizeof(). Any variable of these types also can be "sized" by this function - so you even don't need to know, what is CRGB - type or instance

1 Like

The FastLED array is not initialized for certain values.
So it makes sense to do this:

#define NUM_LEDS  12    // Number of NeoPixel leds
CRGB leds[NUM_LEDS];

By doing that, the 'NUM_LEDS' can be used in the sketch.

Suppose that the "sequence" array can be any size, then the code would be this:

CRGB sequence[] = {CRGB::DarkViolet, CRGB::Violet, CRGB::DarkViolet, CRGB::Black};

In the code, the number of elements of the array has to be calculated. It is an array of CRGB things, so the element size is such a CRGB thing.

    int n = sizeof(sequence)/sizeof(CRGB);
    for(int i=0; i<n; i++)
      leds[ToIndex(index-i)] = sequence[i];

That works, and I have my sketch at Wokwi updated for that: FastLED, a led sequence of four leds - Wokwi ESP32, STM32, Arduino Simulator

However, it you like to have 'NUM_SEQUENCE_LEDS' and use that for the array:

#define NUM_SEQUENCE_LEDS  4 
CRGB sequence[NUM_SEQUENCE_LEDS] = { ...

That is okay as well. It is less flexible code, but it is good and it works.

1 Like

i cant believe it took me this long to see the value of millis in led control. It means i can do things like fading an LED over time without other code blocking the execution of the fade causing visual jitter and general unpleasantness.

For example. It allows me to have an animation run every 100 millis but fade an led within that animation every 5 millis.

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