Millis instead of delay on array of ledstrip

Hello..I have understood the requirement of using Millis() instead of Delay(), as the latter is blocking and can cause interruptions when timing. I have gone through the forum for a likely solution to my scenario, where I am using an array of few leds from my ledstrip to chase forward and backward in the array. the delay() was used as follows:

int ledblink[7]={13,38,65,90,117,142,169}; //specific leds on the strip
void loop() {
  
    
      for( int i=6; i>=0;i--){
      leds[ledblink[i]]= colour;//colour is a separate function I am using to derive random colours
      FastLED.show();
      leds[ledblink[i]]= CRGB::Black;
      delay(50);
      }
 

  for( int i=0; i<7;i++){
     leds[ledblink[i]]= colour;
  FastLED.show();
  leds[ledblink[i]]= CRGB::Black;
   delay(50);
     }
  

Now, to use Millis() instead, I found this old post by @Danois90 :

You cannot use a "for" loop. You should use a global instance of "x", something like this:

int x = 0;

void loop() {
  currentMillis = millis();
  if (currentMillis - startMillis >= period) {
    startMillis = currentMillis;
    leds[x].setRGB(255,69,0);
    FastLED.show();
    leds[x] = CRGB::Black;
    if (++x >= NUM_LEDS) x = 0;
  }
  //Other stuff here..
}

But this works for the entire ledstrip. I am unable to incorporate the above idea for an array of particular leds,as in my case. Thanks in advance.

I think the one LED is "on/off" so fast, it looks like all LEDs are on. You could make a timer that lights an LED, then waits 50ms to extinguish the same LED, before moving to the next LED.

By the way... it is best to post a full, compilable, sketch for testing.

1 Like

Whay you did is not a delay at all.

// blablabla code

  now= millis();
  while(millis() < now + period ) ;

// blablabla code

Keep most of your code, but think of making your i global, and that every 50ms you change it. When it gets to the top you start changing it downwards, and when it is at the bottom you change it upwards.

To do this you need to remember where you are (ii) and which way you are going (increment).

Maybe you want something like this completely untested snippet of an incomplete program:

int ii = 0;
int increment = 1;

void loop() {
  uint32_t now = millis();
  static uint32_t last = 0;
  const uint32_t interval = 50;
  if (now - last >= interval) {
    last = now;
    leds[ledblink[ii]] = colour; //colour is a separate function I am using to derive random colours
    FastLED.show();
    leds[ledblink[ii]] = CRGB::Black;
    // move the index:
    ii = ii + increment;
    if (ii > 6) { // top
      ii = 6;
      increment = -1;
    } else if (ii < 0) { // bottom
      ii = 0 ;
      increment = 1;
    }
  }
}

maikarg.... that blocks and might as well be delay()

Thanx Dave for your reply. My question still remains, how can (ii) be assigned to my array of particular leds, viz
int ledblink[7]={13,38,65,90,117,142,169) , because as per your reply, int(ii) = 0 also, being the first led of the strip.
Very many thanks..

I thought you said you already had it working with:

My untested snippet should work much the same, but be able to use millis() instead of delay() and for(){} because it can remember where it is and which way it was going between executions of loop().

Or if you are asking about ii and i, I used 'ii' instead of 'i' because it is easier to search and replace with.

Or maybe I do not understand your question.

Your post is a bit confusing, I'm not sure if you are editing the original post after suggestions are made which makes progress impossible to track.

Please post changes as a reply to this thread so we can see.

You should post the whole sketch as some is in doubt when you don't.

I add some comments and suggestions in them

int x = 0;
// what about startMillis and period?
// where is the led library include?
// ditto  NUM_LEDS and the leds[] array?
// ditto void setup()

void loop() {
  currentMillis = millis();
  if (currentMillis - startMillis >= period) {
    startMillis = currentMillis;
    leds[x].setRGB(255,69,0);
    FastLED.show();
    leds[x] = CRGB::Black;

// this  is what makes your led chase do the whole strip
    if (++x >= NUM_LEDS) x = 0;
// if you want to back and forth a segment of the strip...
// Then you need variables for 
// the low end, 
// the high end and 
// increment direction may be 1 or -1 to go up or down
// and more if() structure to handle the back and forth like

// x += increment;
// if ( increment > 0 )
// {
//    if ( x == high end )
//    {
//      x = high end - 1;
//      increment = -1;
//    }
// }
// else 
//    if ( x == low end )
//    {
//      x = low end + 1;
//      increment = 1;
//    }
// }
//    when you want code to do something, ya gotta write those parts
  }
  //Other stuff here..
}
1 Like

Hi.. It's my bad.. Let me explain.. I have a matrix of many leds displaying time. These particular array of leds I have listed earlier are a single vertical line bang in the centre of the matrix and I want them to chase up and down on a timer I decide, maybe 1000 milliseconds per led. So they move down lighting 1 led/sec, and at the bottom all go black, then light up similarly.
Now the thing is, your int(ii)=0 points to 1st led of the whole matrix, whereas I want it to point to 1st led of my array, viz top most led of the centre vertical line.. Thnx

Danois90's suggestion looks perfectly fine, but your code uses an extra layer of indirection--you work with:

 leds[ledblink[i]]

instead of

 leds[i]   

You need that indirection to work on just a sample of leds().

It does not.

My

uses the same indirection as

Where, supposing i or ii = 0, the ledblink[0] refers to the first element of:

... or 13. Which is then used as an index into leds as led[13].

Ok thanx.. Will test and revert.. Have a good day..

@harry5568 - Rather than mixing timing (without delay) and LED counting and LED coloring in one function (loop()), I like to make timers that call specific functions. For example:

unsigned long timeout, interval = 500; // timers
bool ledState; // ON or OFF
int ledNumber; // LED counter

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

void loop() {
  if (millis() - timeout > interval) { // wait for interval
    timeout = millis(); // restart the "lap" timer
    ledState = !ledState; // change state variable OFF to ON or ON to OFF
    if (ledState) // if state is 1
      ledON(); // time to turn LED ON
    else // if state is 0
      ledOFF(); // time to turn LED OFF
  }
}

void ledON() { // turn LED(s) ON
  Serial.print("LED ");
  Serial.print(ledNumber);
  Serial.print(" ON");
  getNextLED();
}

void ledOFF() { // turn LED(s) OFF
  Serial.println(" OFF");
}

void getNextLED() {
  if (ledNumber > 6) // monitor counter
    ledNumber = 0; // reset counter
  ledNumber++; // increment counter
}

Hi i tested.. As per your code, each array led lights up, lights off, then moves down. That is not what i want..what i want is - starting state all off, Each led should lightup, stay lighted as it moves down one step.. When it reaches full extent down/or up, again all off and repeat up/down.
Thnx

Not quite clear... How long is a full cycle? And what happens in each timestep?

If there are N leds, does it spend the first N steps lighting them up sequentially, then on the N+1th step turn them all off? Then repeat?

With something like that you can do it with math, keeping track of a state variable for where you are in the N+1-step process. For most of them you turn on the n-th LED, and for the last step you turn them all off and reset.

Hacking at @xfpd's code:

unsigned long timeout, interval = 500; // timers
bool ledState; // ON or OFF
int ledNumber; // LED counter
const int NUM_LEDS = 7;

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

void loop() {
  if (millis() - timeout > interval) { // wait for interval
    timeout = millis(); // restart the "lap" timer
    if (ledNumber <= NUM_LEDS)
      ledON(); // time to turn LED ON
    else // a step too far
      ledsAllOFF(); // time to turn LEDs OFF
  }
}

void ledON() { // turn LED(s) ON
  Serial.print("LED ");
  Serial.print(ledNumber);
  Serial.println(" ON");
  getNextStep();
}

void ledsAllOFF() { // turn LED(s) OFF
  for (int ii =1 ; ii <= NUM_LEDS; ++ii) {
    Serial.print("LED ");
    Serial.print(ii);
    Serial.println(" OFF");
  }
  getNextStep();
}

void getNextStep() {
  if (ledNumber > NUM_LEDS) // monitor counter
    ledNumber = 0; // reset counter
  ledNumber++; // increment counter
}

All 170 LEDs, one by one, or just the LEDs in this array, one by one?

Looking at that array, I think those indices might be relations to columns of an ragged-ish rectangular array or something:

> diff(c(13,38,65,90,117,142,169))
[1] 25 27 25 27 25 27
> 

If so, the math of how they are arranged would be important.

It looks a little snake-like.

My dear bros.. Like the occam's razor(please google)., let's keep it simple.
Plse refer to my first post with delay().. I want same exact with millis()..
Best Regards..

What is the shape of the LEDs?

See post 14 and change the Serial.print() to your LED pattern.

1 Like

OK. Your first post was shoddy, and my first post replaced its delay() with millis().

Perhaps try "How To Get The Best Out Of This Forum" and consider smart questions#explicit.

Since OP is not adding useful content, let's invent something... I now see the "snake" if these values are the nth LED being lit/extinguished. in seven (or more) rows (or columns).