Blink and Fade LED using millis.

Hello everyone. I have a project I'm working on where I have to use millis to do several things as to not interrupt a few led matrix and sensors.

What I'm trying to to is 2 separate things.

  1. Blink an LED fast for 10 seconds, then Turn OFF and stop.

  2. Fade and led ON, Stay ON for 3 seconds, then fade out and stay off for 10 seconds.

What I have so Far works for both BUT:

for #1) I can't figure out how to stop the Led after 10 seconds.

and #2) I can't get the led to do anything but fade in then fade out, and repeat.

Can anyone help explain how I'd do this?

#1): Blinks Led fast

// blink for 10 seconds then turn off

const int magicRed = 47;

int led4State = LOW;
long previousMillis4 = 0;
const long interval4 = 50;

void setup() {

  pinMode(magicRed, OUTPUT);
}

void loop() {
  magicRedPanic();
}


void magicRedPanic()
{
  // blink the red LED.
  unsigned long currentMillis4 = millis();

  if (currentMillis4 - previousMillis4 > interval4) {
    previousMillis4 = currentMillis4;

    // if the LED is off turn it on and vice-versa:
    if (led4State == LOW)
    {
      led4State = HIGH;
    }
    else
    {
      led4State = LOW;
    }
    // set the LED with the ledState of the variable:
    digitalWrite(magicRed, led4State);
  }
}

#2): Fade in fade out

const byte magicWhite = 45;

#define UP 0
#define DOWN 1

// constants
const int minPWM = 0;
const int maxPWM = 255;

byte fadeDirection = UP;

int fadeValue = 0;

byte fadeIncrement = 5;

unsigned long previousFadeMillis;

int fadeInterval = 50;



void setup() {
  analogWrite(magicWhite, fadeValue);
}



void loop() {
  unsigned long currentMillis = millis();

  magicWhiteFade(currentMillis);

}




void magicWhiteFade(unsigned long thisMillis) {

  if (thisMillis - previousFadeMillis >= fadeInterval) {


    if (fadeDirection == UP) {
      fadeValue = fadeValue + fadeIncrement;
      if (fadeValue >= maxPWM) {

        fadeValue = maxPWM;
        fadeDirection = DOWN;
      }
    } else {

      fadeValue = fadeValue - fadeIncrement;
      if (fadeValue <= minPWM) {

        fadeValue = minPWM;
        fadeDirection = UP;
      }
    }
    analogWrite(magicWhite, fadeValue);
    previousFadeMillis = thisMillis;
  }

}

Since interval4 is 50ms, work out how many lots of 50ms there are in 10 seconds.
Count how many times you flash the LED.
When you’ve flashed it 10s/50ms times, move onto the fading pattern.

You will also need a state variable to say which step of the pattern you are at...
Step 1: flashing 10 seconds
Step 2: fade on
Step 3: stay on 3 seconds
Step 4: fade off
Step 5: stay off 10 seconds

After you detect the completion of each step, increment the state variable to move to the next step.

Your loop() function should probably begin with a switch case to select on state.

pcbbc:
Since interval4 is 50ms, work out how many lots of 50ms there are in 10 seconds.
Count how many times you flash the LED.
When you’ve flashed it 10s/50ms times, move onto the fading pattern.

Sorry, I could have explained their purpose A bit better I guess.
I am not intending on Combining each sketch like that. I actually would like them to be 2 completely different functions within another sketch, where I would use buttons to call either "magicRedPanic()" or another to call "magicWhiteFade" with other functions.
Each button will also have several other commands attached to them. However, I have 2 leds one I'd like to flash as I have it, for just ten seconds while that other commands are being executed.
and another one that Id like to have fade in, stay lit, then fade out while its other commands are being executed.

Thats why I had posted them separate I'd need them to work independently from each other.

Hi BubbleHockey,

you still have to add more information how it shall work.

You wrote "buttons" How shall the functionality work? A buttonpress and release initiates several actions
or must the button be hold pressed down or is it a switch in "ON"-position and as long as pressed down (switch on is beeing detected perform the actions?

If the button-press initiates the action the button-press sets a boolean variable named something like "RedFlashingActive" to true

if (Buttonpressed) {  //whatever real code is nescessary for detecting "button is pressed")
  if (!RedFlashingActive) {
      RedFlashingActive = true
  }
}

then you check for RedFlashingActive is true and call your function magicRedPanic() set up a timer exactly the same way as for flashing only difference timeperiod is 10 seconds and after ten seconds you set variable RedFlashingActive to false

You can use an equivalent logic for your function magicWhiteFade()

best regards Stefan

1)

There are two options:
1A) Use a single millis-timer and count the number of blinks as pcbbc wrote.
1B) Use two millis-timers.

Option 1B is a combination of my millis_within_millis.ino and millis_single_delay.ino.

const int ledPin = LED_BUILTIN;

unsigned long previousMillisEnable;   // a millis timer for a single shot timer
unsigned long previousMillisBlink;    // a millis timer for the blinking

bool enable = false;                  // to blink or not to blink
int ledState = LOW;


void setup()
{
  Serial.begin( 9600);
  Serial.println( "Press s to start");
  
  pinMode( ledPin, OUTPUT);
}


void loop()
{
  if( Serial.available() > 0)
  {
    char inChar = Serial.read();
    if( inChar == 's')
    {
      start1B();
    }
  }

  update1B();
}


void start1B()
{
  previousMillisEnable = millis();  // reset the millis timer for the single shot timer
  enable = true;                    // start the single shot timer and enable the blinking

  // It is not needed to set previousMillisBlink to millis().
  // But it is safer when it was used 50 days ago.
  previousMillisBlink = millis();
}

void update1B()
{
  unsigned long currentMillis = millis();

  if( enable)
  {
    if( currentMillis - previousMillisBlink >= 50)
    {
      previousMillisBlink = currentMillis;
      
      if( ledState == LOW)
        ledState = HIGH;
      else
        ledState = LOW;
      
      digitalWrite( ledPin, ledState);
    }

    if( currentMillis - previousMillisEnable >= 10000)
    {
      digitalWrite( ledPin, LOW);   // be sure that the led is off when blinking is done
      enable = false;               // stop this single shot timer and stop the blinking
    }
  }
}

I have the same questions as StefanL38 about the buttons. To avoid that, I have used the serial monitor to start it.

BubbleHockey, with a good description, half of the sketch is already written. I have made a few decisions in my sketch, but you probably won't notice them because the leds blinks fast.

When the led would blink slow, it would be nice to have full complete pulses, even for the last blink. That requires other code. In my sketch I turn off the blinking regardless where the led is at that moment in the blinking process.

2)

For number 2, there are too many things that I don't know. Do you want to be able to restart the sequence when it is busy ? Should the led do the fading with a visual normal fading, since the human eye sees brightness with a log10 curve. What is the 10 seconds at the end for, or should it start over again after that ? If so, how should it stop ?

Koepel:
1)

I have the same questions as StefanL38 about the buttons. To avoid that, I have used the serial monitor to start it.

For number 2, there are too many things that I don't know. Do you want to be able to restart the sequence when it is busy ? Should the led do the fading with a visual normal fading, since the human eye sees brightness with a log10 curve. What is the 10 seconds at the end for, or should it start over again after that ? If so, how should it stop ?

Ok, So maybe mentioning the "buttons" may have gotten off my original problem.

What I'm "atempting" to do. is have several "void functions" which blink leds in different ways. They will be used as visual indicators that different operations are under-way or alarms. And in some cases they will be called randomly as a timed event (again using millis).

so essentially as things change, I can just call "magicRedPanic();" and have it blink the LED for the pre-set amount of time then shut off and wait for the next time it is called. (same thing for the fade)

because these concepts are ultimately going to be part of larger structure using both NRF, and I2c to call void functions on 3 Arduinos, at this point I'm not so concerned about the method in which I will be calling the void function, but rather how to get the void function to "function" as intended.
ie: Start....do something...Then stop. but using millis() for which im still trying to wrap my head around, as Delays are causing all kinds of havoc with other functions, That's Why originally I just had it by itself within the loop just to test the void function.

I hope that makes more since and At its core is something that can be contained within is own void function. (or in this case 2 separate ones)

As for the fade time question I was thinking 50ms fade IN, pause ON for 3000ms, 50ms Fade OUT. then Stay off until the next time the function is called, (like the previous LED).
I figured I'd have to have these as set values that could be adjusted if I needed to shorten or lengthen the fade in/out or the time on.
(Ignore what I previously said about the "off time" its not important if we just have it off and wait for the next time I call the function)

Also, I'm not sure it matters where in the "blinking" it stops, as it will mainly indicate an alarm, and I'm not going to be counting the blinks while I'm kicking the robot yelling WORK! lol. unless thats something that Is something that needs to be taken into account.

For number 2, I'm using the states that pcbbc wrote about. Let's call that option 2A.

2A) Using a Finite State Machine with millis as in my millis_and_finite_state_machine.ino, but I did not use the transitional states. I have pre-set everything properly before entering that state. I have added the 10log curve which the human eye has for brightness as in my millis_soft_pulsating_led.ino example, but I made it from 0...255 instead of 1...255.

const int ledPin = 9;                 // a PWM pin

enum
{
  STATE_OFF,                          // led off state, 'idle' state, initial state
  STATE_FADE_IN,
  STATE_ON,
  STATE_FADE_OUT,
} state;

unsigned long previousMillis;         // a single variable can be used in every state


void setup()
{
  Serial.begin( 9600);
  Serial.println( "Press g to go");
  
  pinMode( ledPin, OUTPUT);
  state = STATE_OFF;
}


void loop()
{
  if( Serial.available() > 0)
  {
    char inChar = Serial.read();
    if( inChar == 'g')
    {
      start2A();
    }
  }

  update2A();
}


void start2A()
{
  previousMillis = millis();
  state = STATE_FADE_IN;
}

void update2A()
{
  unsigned long currentMillis = millis();
  unsigned long elapsedMillis = currentMillis - previousMillis;

  switch( state)
  {
    case STATE_OFF:
      // The led should be off, do nothing.
      break;
    case STATE_FADE_IN:
      // Calculate the brightness for this moment.
      // The human eye has 10log for the brightness, so that is used.
      // This example uses 2000 ms for the ramp up.
      if( elapsedMillis >= 2000)
      {
        digitalWrite( ledPin, HIGH);
        previousMillis = currentMillis;
        state = STATE_ON;
      }
      else
      {
        float t = float( elapsedMillis) / 2000.0;  // convert 0...2000 to 0...1 for the logarithmic/exponential scale
        float u = pow( 10, t);                     // convert 0...1 to 1...10 with exponential scale with base 10
        float v = (255.5 / 9.0 * (u - 1.0));       // convert 1...10 to 0...255. Add 0.5 to 255 for rounding
        int pwm = int( v);                         // convert it to integer for the PWM value
        analogWrite( ledPin, pwm);
      }
      break;
    case STATE_ON:
      // The led should be on.
      // This example waits 5 seconds
      if( elapsedMillis >= 5000)
      {
        previousMillis = currentMillis;
        state = STATE_FADE_OUT;
      }
      break;
    case STATE_FADE_OUT:
      // Calculate the brightness for this moment.
      // The human eye has 10log for the brightness, so that is used.
      // This example uses 2000 ms for the ramp down.
      if( elapsedMillis >= 2000)
      {
        digitalWrite( ledPin, LOW);
        state = STATE_OFF;
      }
      else
      {
        float t = float( 2000 - elapsedMillis) / 2000.0; // convert 0...2000 to 1...0 for the logarithmic/exponential scale
        float u = pow( 10, t);                     // convert 0...1 to 1...10 with exponential scale with base 10
        float v = (255.5 / 9.0 * (u - 1.0));       // convert 1...10 to 0...255. Add 0.5 to 255 for rounding
        int pwm = int( v);                         // convert it to integer for the PWM value
        analogWrite( ledPin, pwm);
      }
      break;
  }
}

It is possible to make every pattern with a Finite State Machine and have a 'state' on top of that which selects the Finite State Machine.

Would all your problems be solved with a RGB led and show a different color for the different situations ?

Start....do something...Then stop

These procedures just need a state variable, it can just be a bool since there are two states, timing and idle. In the timing state, you check and update your timing variables and also write the LED. If you are doing fades, you need another state machine for that, or combine the two state tables into one, as with the code in reply #6.

By the way, I think you should care about the state in which it stops. You don't want to stop and leave the alarm LED on.

Koepel:
It is possible to make every pattern with a Finite State Machine and have a 'state' on top of that which selects the Finite State Machine.

Would all your problems be solved with a RGB led and show a different color for the different situations ?

I have had state machines suggested to me before but I'm still trying to wrap my head around no delays.
I'll have some reading to do.
Honestly Im a but confused by the loop in both sketches you suggested and how to implement them. I'm calling one Function and then updating it with another? the first one just defining previousMillis and state = STATE_FADE_IN;? Could you not do that in start of the single function?
I get the serial portion and then calling the function after I input "g" in the monitor, but then the series of {} after I'm not sure. sorry I'm still learning

As for the RGB, no. these will all be different Leds in different places. several in some cases.

aarg:
By the way, I think you should care about the state in which it stops. You don't want to stop and leave the alarm LED on.

Sorry, I meant I did not care about the number, I was under the impression that writing it False would have it End with it off either way.

I'm just trying to work out. the easiest way to calling each, as Im up to about 40 animations each one calling a dozen different actions. And Previous to this issue have just had things working primarily with delays, which I now know was counterproductive. And am I bit lost with this, But thank you for everyones suggestions and help! it is helping me get a handle on this.

When using millis(), you have to do one thing to start it and then do an other thing in the Arduino loop(). There is no other way.

When the code with millis() is not in the loop() itself, but in a function, then that function is often called a "update" function.
When the Arduino loop() runs hundreds or thousands times per second, then that "update" function is called very often and everything runs smooth and fast.

I have used a "start" function for both sketches to make clear how it is started.

  1. Blink an LED fast for 10 seconds, then Turn OFF and stop.
blink10enable = true; //do this to start the sequence.
...
void blink10() {
  static unsigned long lastMillis;
  static unsigned long blinkMillis;

  if (blink10enable) { // reset state and LED if done
    if (millis() - lastMillis >= 10000) {
      blink10enable = false;
      digitalWrite(13, LOW);
    }
    else if (millis() - blinkMillis >= 500) { // or blink
      blinkMillis = millis();
      digitalWrite(13, not digitalRead(13));
    }
  }
  else { // otherwise keep a start time
    lastMillis = millis();
  }
}

In this case, there is a single state variable, blink10enable which can only be true or false. You can be fancier and define states TIMING and IDLE, which don't make anything faster, just easier to read.

Your idea with the functions doesn’t help you if the functions are still delaying. While the functions are executing you main code, or other functions, can not be checking, or doing anything else.

You need to get your head away from the linear model of programming (which works perfectly adequately for a single task)... do this, wait for something, do something else, wait...

And start thinking more along the lines of how you do more than one long running chore at a time yourself. Say for example cooking a meal where you need to perform several different recipes which form the entire meal, but simultaneously.

There you mentally keep track of how far you have got (your “state”) in each recipe, but constantly switch between each recipe doing a little bit of each as and when needed. If nothing needs doing on one recipe you move on to the next recipe, and check that until eventually you find something that does need attention.

That’s all the Arduino program that works as a state machine is doing. Constantly running through loop() looking at the state of each task and deciding if it’s time to do something or not. So you can divide those separate tasks out into functions if it helps organise your program, but it isn’t going to help you do more than one thing at a time unless you first grasp the state concept.

So your code becomes a series of..
Does task x require attention? No...move on...
Does task y require attention? Yes...do a single small step of task y...if complete advance state of y...
Does task z require attention? No...move on...
Repeat from start checking task x, y, z...

Do this fast enough and it gives the impression the Arduino is doing everything at once.

Yes, notice that blink10() above never stops if you call it. It just performs whatever quick task is needed at the moment, and immediately returns to loop(). Everything in loop() has to behave that way.

aarg:
Yes, notice that blink10() above never stops if you call it. It just performs whatever quick task is needed at the moment, and immediately returns to loop(). Everything in loop() has to behave that way.

Yes, I understand the concept, I guess that is what I was getting at. my problem became exiting the function after a set time. whereas Before I was calling the function, preformed its action, returned to the loop but the action, never stopped or as per above just kept repeating. And for the fade, I could not get it to stay lit in the middle of the fade, and then again, the same problem exiting.

I tried a few times with a state "machine" knowing very little, I knew you could use break to get out. but I was more like a State abacus, not so much a Machine, cuz I broke it.

All the suggestions above Work perfectly THANK YOU! And for helping me understand this a bit better! I'll do a bit of playing around and try to get them to work in the larger sketch!