Incremental LED sequence with Millis()

Hi everyone

Firs time poster. I've been using the forum a lot and all the community posts have been massively helpful, in reintroducing myself back into programming for fun.

I'm posting this evening, as i'm stuck looking for an example. I figure there must be one out there as there are examples for everything!

I have a sequence of 16 LEDs that need to light up one at a time until the whole line is lit. Then after a brief pause the whole line should go off and the loop starts again. I've got it working fine with delays, but i want to integrate some other sequences so millis(), would be better.

i've kind of got it working, but on the second round the sequence gets out of order. I presume to do with the timing and how the mills clocks are being counted.

i've found plenty of examples for getting LEDS blinking in alternating sequences. Like The BaldEngineer. [Great examples BTW] However nothing for incremental increases.

Can anyone point me in the direction of an example?

Thank You

Roxanne

Look at the Blink Without Delay example.

Hi,

What do you mean bt incremental increases?

Hi Roxanne, Welcome to the forum!

It would help if you could post the code you have so far. (using these guidelines: How to use this forum )

@RoxanneS:

Hi,

take a step back, rethink the problem and get a clearer bigger pic, work your way slowly until the project is done.

now I’m guessing you are using this < Larson LED > as your reference?

ok from what I can say is that he uses a very advance technique called direct bit manipulation, you could go that way or you could just used the C++ abstraction layer that Arduino provided. For the average joe, the C++ abstraction is good enough for most purposes.

lets talk on how I would approach this problem:

lets assume that this project does not require any input at the moment,

I know I have 16 Led that will turn on sequentially at a regular interval until all 16 is turn on pause for a bit turn off all the Led and the cycle repeat right…

so from there I know using an array called LEDpin would be a great idea, maybe the size of this array could be of use later on?

now second bit that I know is that I’ll be using a Timing counter,
as usual when it come to timing counter, I will always have some timeNow and timePrev, and apparently this project have two additional timing constant regularInterval and pause and a variable name interval helps too.

urm Maybe having a counter that increment wont be a so bad idea too?

so thats my top declaration

now in the void setup() function

what should I put ?

I see that I have a lot of LEDpin that needed to be declare as OUTPUT? how do I do it?
I could go and put one by one or I could used a for loop to go through the stages

just for simplicity sake why not record the current time on time prev?

i guess we are done with our void setup function…

for my void loop() function:

I do think i need to set up the timing counter first

so save current time in timeNow
the if timeNow - timePrev >= interval

what should we do now?
well how about record the timeNow in timePrec
what if we turn on the Led base on the counter value;
but if the counter is equal to number of led nothing happen ( this is the pause section )
counter increment
and if counter is more then number of led ; reset the LED array, and reset counter to 0;

done
done
and done

so you see that just the flow

code wise

const byte LEDpin[] = { 10, 30}; // <--- put your led pin sequence;
const byte numberOfLED = sizeof ( LEDpin ) / sizeof ( LEDpin[0] );

unsigned long timeNow = 0;
unsigned long timePrev = 0;
const unsigned long regularInterval = 300;
const unsigned long pause = 1000;
unsigned long interval = regularInterval;

byte counter = 0;

void setup ()
{
  for ( byte i = 0; i < numberOfLED; i++ )
  {
    pinMode (LEDpin[i] , OUTPUT);
    digitalWrite ( LEDpin[i], LOW);
  }
  timePrev = millis();
}

void loop()
{
  timeNow = millis();
  if ( timeNow - timePrev >= interval )
  {
    timePrev = timeNow;
    if ( counter < numberOfLED )
    {
      digitalWrite ( LEDpin[counter], HIGH);
    }
    counter++;
    if ( counter == numberOfLED ) interval = pause;
    else interval = regularInterval;
    if ( counter > numberOfLED )
    {
      counter = 0;
      for ( byte i = 0; i < numberOfLED; i++ )
      {
        digitalWrite ( LEDpin[i], LOW);
      }
    }
  }
}

It's just a little expensive, compared to monocolor LED's but I suggest you look up neopixels at Adafruit (although you may want to buy them on EBay). A whole string of RGB LED's is controllable with a single data line, and you would probably find them fascination enough to plan other projects around them.

jrdoner:
It's just a little expensive, compared to monocolor LED's but I suggest you look up neopixels at Adafruit (although you may want to buy them on EBay). A whole string of RGB LED's is controllable with a single data line, and you would probably find them fascination enough to plan other projects around them.

I have them! They're awesome, but they're too long to fit in the slot. It would be a lot less soldering too.

if you know of any others that are slightly shorter shout me!

After some more playing about last night this is as far as i got. There's only 6 LEDs in the sequence at the moment, for simplicity's sake, whilst i'm working it out.

It works, to a point. The lights do count on. However;

  • When I add a counter, to reset the sequence after LED6, it often stops at 4 and then resets the pattern
  • There's a stutter in the middle between 3-4 or 4-5
  • The comments out at the bottom was where i left off last night
// each "event" (LED) gets their own tracking variable
unsigned long previousMillisLED7=0;
unsigned long previousMillisLED6 = 0;
unsigned long previousMillisLED5 = 0;
unsigned long previousMillisLED4 = 0;
unsigned long previousMillisLED3 = 0;
unsigned long previousMillisLED2 = 0;
unsigned long previousMillisLED1 = 0;
unsigned long previousMillisX =0;



// different intervals for each LED
int intervalLED7 = 100;
int intervalLED6 = 200;
int intervalLED5 = 300;
int intervalLED4 = 400;
int intervalLED3 = 500;
int intervalLED2 = 600;
int intervalLED1 = 700;
int intervalX = 800;
int x = 0;

// each LED gets a state varaible
boolean LED7state = false;     // the LED will turn ON in the first iteration of loop()
boolean LED6state = false;     // need to seed the light to be OFF
boolean LED5state = false;     // the LED will turn ON in the first iteration of loop()
boolean LED4state = false;     // need to seed the light to be OFF
boolean LED3state = false;     // the LED will turn ON in the first iteration of loop()
boolean LED2state = false;     // need to seed the light to be OFF
boolean LED1state = false;     // need to seed the light to be OFF

void setup() {
  Serial.begin(9600);
  
  pinMode(9, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
}
void loop() {
  // get current time stamp
  // only need one for both if-statements
  unsigned long currentMillis = millis();

  if (x ==1) {
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
    digitalWrite(4, LOW);
    x = 0;
    
  }


  // time to toggle LED on Pin 13?
  if ((unsigned long)(currentMillis - previousMillisLED6) >= intervalLED6) {
    digitalWrite(9, HIGH);
    previousMillisLED6 = currentMillis;
    if ((unsigned long)(currentMillis - previousMillisLED5) >= intervalLED5) {
      digitalWrite(8, HIGH);
      previousMillisLED5 = currentMillis;
      if ((unsigned long)(currentMillis - previousMillisLED4) >= intervalLED4) {
        digitalWrite(7, HIGH); 
       previousMillisLED4 = currentMillis;
        if ((unsigned long)(currentMillis - previousMillisLED3) >= intervalLED3) {
          digitalWrite(6, HIGH);
          previousMillisLED3 = currentMillis;
          if ((unsigned long)(currentMillis - previousMillisLED2) >= intervalLED2) {
            digitalWrite(5, HIGH);
            previousMillisLED2 = currentMillis;
            if ((unsigned long)(currentMillis - previousMillisLED1) >= intervalLED1) {
              digitalWrite(4, HIGH);
              previousMillisLED1 = currentMillis;
              
//              if ((unsigned long)(currentMillis - previousMillisX) >= intervalX){
//               previousMillisX = currentMillis;
//                x=1;
//              }
              }
            }
        }
      }
    }
  }

}

Hutkikz:
Hi Roxanne, Welcome to the forum!

It would help if you could post the code you have so far. (using these guidelines: How to use this forum )

Thanks, I've added the last place I left off last night.

Ah Ha! I it's working!

// each "event" (LED) gets their own tracking variable
unsigned long previousMillisLED7 = 0;
unsigned long previousMillisLED6 = 0;
unsigned long previousMillisLED5 = 0;
unsigned long previousMillisLED4 = 0;
unsigned long previousMillisLED3 = 0;
unsigned long previousMillisLED2 = 0;
unsigned long previousMillisLED1 = 0;
unsigned long previousMillisX = 0;



// different intervals for each LED
int intervalLED7 = 100;
int intervalLED6 = 200;
int intervalLED5 = 400;
int intervalLED4 = 600;
int intervalLED3 = 800;
int intervalLED2 = 1000;
int intervalLED1 = 1200;
int intervalX = 1600;
int x = 0;

// each LED gets a state varaible
boolean LED7state = false;     // the LED will turn ON in the first iteration of loop()
boolean LED6state = false;     // need to seed the light to be OFF
boolean LED5state = false;     // the LED will turn ON in the first iteration of loop()
boolean LED4state = false;     // need to seed the light to be OFF
boolean LED3state = false;     // the LED will turn ON in the first iteration of loop()
boolean LED2state = false;     // need to seed the light to be OFF
boolean LED1state = false;     // need to seed the light to be OFF

void setup() {
  Serial.begin(9600);

  pinMode(9, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
}
void loop() {
  // get current time stamp
  // only need one for both if-statements
  unsigned long currentMillis = millis();

// time to toggle LED on Pin 13?
  if ((unsigned long)(currentMillis - previousMillisX) >= intervalLED6) {
    digitalWrite(9, HIGH);
    previousMillisLED6 = currentMillis;
    if ((unsigned long)(currentMillis - previousMillisX) >= intervalLED5) {
      digitalWrite(8, HIGH);
      // previousMillisLED5 = currentMillis;
      if ((unsigned long)(currentMillis - previousMillisX)  >= intervalLED4) {
        digitalWrite(7, HIGH);
        if ((unsigned long)(currentMillis - previousMillisX)  >= intervalLED3) {
          digitalWrite(6, HIGH);
          if ((unsigned long)(currentMillis - previousMillisX)  >= intervalLED2) {
            digitalWrite(5, HIGH);
            if ((unsigned long)(currentMillis - previousMillisX)  >= intervalLED1) {
              digitalWrite(4, HIGH);
              if ((unsigned long)(currentMillis - previousMillisX) >= intervalX) {
                previousMillisX = currentMillis;
                digitalWrite(9, LOW);
                digitalWrite(8, LOW);
                digitalWrite(7, LOW);
                digitalWrite(6, LOW);
                digitalWrite(5, LOW);
                digitalWrite(4, LOW);
              }
            }
          }
        }
      }

    }
  }
}

At the point where you find yourself adding numeric suffixes to variable names, that's the time to start looking at arrays.unsigned long previousMillisLED7 = 0; The compiler will set it to zero unless you tell it otherwise; you're wasting effort typing.

@RoxanneS:

Your If statement is too deep;

This example works a bar of 4.
(Rollover Ready?)

//  makeabarmillis01
//  works 03JUL2016
long markTime;
long elapsedTime;
byte bar = 0;
byte pinsArray [4] = {8,9,10,11};
boolean gotMark = false;

void setup ()
{
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
}
void loop ()
{
  if(gotMark == false)
  {
    markTime = millis();
    gotMark = true;
  }
  elapsedTime = millis();
  if((elapsedTime - markTime) >= 2000) // 2 secs each
  {
    bartime();
  }
}
void bartime ()
{
  gotMark = false;
  if(bar < 4)
  {
    digitalWrite(pinsArray[bar],HIGH);
    bar ++;
  }
  else
  {
    // clear the bar
    digitalWrite(pinsArray[0],LOW);
    digitalWrite(pinsArray[1],LOW);
    digitalWrite(pinsArray[2],LOW);
    digitalWrite(pinsArray[3],LOW);
    bar = 0;  // reset bar
  }
}

Thanks Everyone, I’ll take a look at the feedback in detail on the train in the morning.

I didn’t think it was a very elegant solution :slight_smile:

I’m rediscovering a love for arrays.

time elements should be unsigned long.

CrossRoads:
time elements should be unsigned long.

Roger that.

//
//  makeabarmillis01
//  works 03JUL2016
unsigned long markTime;
unsigned long elapsedTime;
byte bar = 0;
byte pinsArray [4] = {8,9,10,11};
boolean gotMark = false;
const unsigned long dwellTime = 1000; // msec to dwell
void setup ()
{
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
}
void loop ()
{
  if(gotMark == false)
  {
    markTime = millis();
    gotMark = true;
  }
  elapsedTime = millis();
  if((elapsedTime - markTime) >= dwellTime) // 2 secs each
  {
    bartime();
  }
}
void bartime ()
{
  gotMark = false;
  if(bar < 4)
  {
    digitalWrite(pinsArray[bar],HIGH);
    bar ++;
  }
  else
  {
    // clear the bar
    digitalWrite(pinsArray[0],LOW);
    digitalWrite(pinsArray[1],LOW);
    digitalWrite(pinsArray[2],LOW);
    digitalWrite(pinsArray[3],LOW);
    bar = 0;  // reset bar
  }
}
  else
  {
    // clear the bar
    digitalWrite(pinsArray[0],LOW);
    digitalWrite(pinsArray[1],LOW);
    digitalWrite(pinsArray[2],LOW);
    digitalWrite(pinsArray[3],LOW);
    bar = 0;  // reset bar
  }

another chance to take advantage of an array :slight_smile:

else
{
   // clear the bar
   for (byte i = 0; i < 4; i++)
   {
    digitalWrite ( pinsArray[i],LOW);
  }
  bar = 0;  // reset bar
}

“another chance to take advantage of an array”

I thought about that, and borrowing “bar” instead of creating another variable, but I figured… baby steps.

Reworked the sketch this morning:

  • Got rid of the boolean flag (gotMark) by grabbing the initial markTime in setup ( )
  • Used for…next (and pinsArray) to clear the bar (I see it as a bar, they could be in a circle or scattered)
//  makeabarmillis01
//  works   03JUL2016
//  revised 04JUL2016
//  4 LEDs
unsigned long markTime;
unsigned long elapsedTime;
byte bar = 0;
byte pinsArray [4] = {8,9,10,11};
const unsigned long dwellTime = 1000; // msec to dwell
byte pinStrafe;
void setup ()
{
  for(pinStrafe=0; pinStrafe<4; pinStrafe ++)
  {
    pinMode(pinsArray[pinStrafe],OUTPUT);
  }
  markTime = millis();
}
void loop ()
{
  elapsedTime = millis();
  if((elapsedTime - markTime) >= dwellTime) // 2 secs each
  {
    markTime = millis();  // new mark
    barUpdate();
  }
}
void barUpdate ()
{
  if(bar < 4)
  {
    digitalWrite(pinsArray[bar],HIGH);
    bar ++;
  }
  else
  {
    // clear the bar, all dark
    for(pinStrafe=0; pinStrafe<4; pinStrafe ++)
    {
      digitalWrite(pinsArray[pinStrafe],LOW);
    }
    bar = 0;  // reset bar
  }
}