Using millis() instead of delay()

Hello everyone - noob question

I have a small led strip program using the delay function where leds chase in one direction in red and then change to green in the other direction, in order to get two leds of, diferent colours, running in different directions at the same time I think I'd need to use the miilis() function and not delay().

I was hoping someone could help me change the delay() function in the code below to millis() and then I'll spend some time trying to work out the rest, I've been reading a few webpages on this but cant quite get my head around the syntax.

[code]
//Leds chase backwards and forwards along strip
//

#include <FastLED.h>
#define NUM_LEDS 60
#define DATA_PIN 5

CRGB leds[NUM_LEDS];

unsigned long delayPeriod = 20;


void setup() { 
       FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
   }

void loop()  
    {
    // chase bforward red 
    
   
        for(int dot = 0; dot < NUM_LEDS; dot++) { 
            //fadeToBlackBy( leds, NUM_LEDS, 20);
            leds[dot] = CRGB::Red;
            FastLED.show();
            leds[dot] = CRGB::Black;
            delay(delayPeriod);                     
        }

    // chase backward green
        for(int dot=NUM_LEDS ; dot >=0 ; dot--){ 
            leds[dot] = CRGB::Green;
            FastLED.show();
            //fadeToBlackBy( leds, NUM_LEDS, 100);
            leds[dot] = CRGB::Black;
            delay(delayPeriod);

      
        }}

[/code]

To use mllis() for timing instead of delay() you need to restructure your program to keep loop() running freely

An example

unsigned long currentTime;
unsigned long startTime;
unsigned long period = 1000;
byte count = 0;

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

void loop()
{
  currentTime = millis();
  if (currentTime - startTime >= period)
  {
    Serial.println(count);
    startTime = currentTime;
    count++;
    if (count >= 10)
    {
      count = 0;
    }
  }
}

Of course, instead of printing you could do almost anything. If you want more than one pattern then when you have finished the current one change to another one by having the action controlled by a variable

Take a look at Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE

It is admiral and arguably necessary that you eventually learn to use millis() (properly!) in place of delay();, but in this case

No problem or challenge that you would face making chasers go both ways at once will be alleviated with mills();

Consider (untested, compiles)

  for (int dot = 0; dot < NUM_LEDS; dot++) {
 
    leds[dot] = CRGB::Red;
    leds[NUM_LEDS - dot - 1] = CRGB::Green;

    FastLED.show();
    
    leds[dot] = CRGB::Black;
    leds[NUM_LEDS - dot - 1] = CRGB::Black;
    
    delay(delayPeriod);
  }

which just illuminates two LEDs each time, shows them, and extinguishes them. A (the) trick you'll see if you look closely is the index used to refer to the second color

NUM_LEDS - dot - 1

which will just run through the LEDs in reverse from dot as dot goes from 0 to (NUM_PIXELS - 1).

Plug in a few values and see. Or run this loop in your code and see.

But do get back to millis() and, perhaps, state machines one day. This would be a good candidate.

a7

You have to turn everything inside-out. You use static (or global) variables so they retain their value across calls to loop(). You reduce the loops to separate increment and test operations so only one step of the loop happens each time loop is called. Then you use millis() to schedule the steps of the loop. Both loops were roughly the same so a state variable is used to keep track of which of the two loops is the current loop.

void loop()
{
  unsigned long currentMillis = millis();
  static unsigned long previousMillis = 0;
  static boolean RedMode = true;
  static int dot = 0;

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

    // Time to do one step of the loop
    if (RedMode)
    {
      // chase forward red
      leds[dot] = CRGB::Red;
      FastLED.show();
      leds[dot] = CRGB::Black;
    }
    else // GreenMode
    {
      // chase backward green
      leds[(NUM_LEDS - 1) - dot] = CRGB::Green;
      FastLED.show();
      leds[(NUM_LEDS - 1) - dot] = CRGB::Black;
    }

    // End of the looped stuff, increment the loop
    dot++;

    // Check to see if the loop is over
    if (dot >= NUM_LEDS)
    {
      dot = 0; // Re-start the loop
      RedMode = !RedMode; // Togle the mode
    }
  }
}

Nice code as usual @johnwasser, but it does not

“ get two leds of, diferent colours, running in different directions at the same time”

the OP’s stated objective.

An easy modification, no doubt. And probably using some kind of trick along the lines of what @alto777 was getting at in #2.

a7

Thanks for the replies I really appreciate it.

alto777:
Nice code as usual @johnwasser, but it does not “get two leds of, diferent colours, running in different directions at the same time”, the OP’s stated objective.

Sorry, I missed that. To do that they don't need millis():

void loop()
{
  for (int dot = 0; dot < NUM_LEDS; dot++)
  {
    // chase forward red
    leds[dot] = CRGB::Red;
    // chase backward green
    leds[(NUM_LEDS - 1) - dot] = CRGB::Green;
    
    FastLED.show();


    // Turn both of those off the next time .show() is called
    leds[dot] = CRGB::Black;
    leds[(NUM_LEDS - 1) - dot] = CRGB::Black;


    delay(delayPeriod);
  }
}

That code looks good. And oddly familiar. :wink:

a7

You need to re-organize your code as tasks, see my tutorial on Multi-tasking in Arduino
and then replace delay() with something based on millis() see my detailed tutorial on How to write Timers and Delays in Arduino

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