Fade in without delay is not working

Hi everyone, I would like to quickly ask a question:

I tried Arduino example "03-Analog-fading" and it works without doubt.
However, it is not working with millis () now.

Thanks in advance ;D

int ledPin = 5;

unsigned long previousMillis = 0; 
const long interval = 300;   

void setup() {}

void loop() {
  unsigned long currentMillis = millis();
  
  // fade in 
  for (int fadeValue = 0 ; fadeValue <= 50; fadeValue += 5) {
    if (currentMillis - previousMillis >= interval) {
      analogWrite(ledPin, fadeValue);
      previousMillis = currentMillis;
    }
  }

  // fade out 
  for (int fadeValue = 50 ; fadeValue >= 0; fadeValue -= 2) {
    if (currentMillis - previousMillis >= interval) {
      analogWrite(ledPin, fadeValue);
      previousMillis = currentMillis;
    }
  }
}

Try this:

  // fade in 
  for (int fadeValue = 0 ; fadeValue <= 50; fadeValue += 5) {
    while (currentMillis - previousMillis < interval); // an empty loop, equivalent to using delay()
    analogWrite(ledPin, fadeValue);
    previousMillis = currentMillis;
  }

Do you see the difference, and why your previous attempt did not work?

But both my suggested change and your attempt are pointless. You might as well use delay(). Both are still "blocking code" and won't allow the Arduino to perform other tasks while the fading is going on.

1 Like

Thanks for reaching out :blush:

In terms of "blocking code", do you have any sugestions on fade in & out with non-blocking code? Since I do need my Arduino to perform others tasks (e.g. use the remote control to run the stepper motor at the same time. )

Also, I just tried the code you suggested. But the outcome seems to be the same. The led still didn't light up. Maybe I misunderstood something. I would really appreciate it if you could explain a little bit more. Thank you so much.

int ledPin = 5;

unsigned long previousMillis = 0; 
const long interval = 300;   

void setup() {}

void loop() {
  unsigned long currentMillis = millis();
  
  // fade in 
  for (int fadeValue = 0 ; fadeValue <= 50; fadeValue += 5) {
    while (currentMillis - previousMillis < interval);
    analogWrite(ledPin, fadeValue);
    previousMillis = currentMillis;
  }

//  // fade out 
//  for (int fadeValue = 50 ; fadeValue >= 0; fadeValue -= 2) {
//    while (currentMillis - previousMillis < interval);
//    analogWrite(ledPin, fadeValue);
//    previousMillis = currentMillis; 
//  }
  
} //loop

Sorry, my bad.

Change it like this:

  // fade in 
  for (int fadeValue = 0 ; fadeValue <= 50; fadeValue += 5) {
    while (millis() - previousMillis < interval);
    analogWrite(ledPin, fadeValue);
    previousMillis = millis();
  }

Because previousMillis was only updated at the beginning of loop() the while-loop became an infinite loop!

1 Like

Got it! Thanks.
And it works now! Really appreciate it. Have a nice day. :smiley: :smiley: :heart:

Your code is using a for-loop to control fadeValue. To make the fading happen slowly and smoothly, so the fading effect can be seen by the eye, the for-loop must run slowly, by using either millis() or delay(). This makes the for-loop into blocking code. It's ok to have for-loops and while-loops in non-blocking code provided those loops run very quickly. But you need the for-loop to run slowly, which makes it blocking code. Therefore you cannot use a for-loop to control the value of fadeValue.

1 Like

But it is not fixed yet, your code will not be able to perform other tasks while the led is fading. My point is that simply using millis() instead of delay() does not fix that problem.

See my previous post.

1 Like

For 'non blocking code' try this.

const byte ledPin = 5;

unsigned long previousMillis = 0;
const unsigned long interval = 300;

boolean fadeInOut = true;
int
fadeMin = 0, // >= 0
fadeMax = 50, // <= 255
fadeValue = fadeMin,
fadeInStep = 5,
fadeOutStep = 2
;

void setup ()
{
  pinMode ( ledPin, OUTPUT );
  digitalWrite ( ledPin, LOW );
  Serial.begin ( 115200 );
}

void loop ()
{
  unsigned long currentMillis = millis ();
  
  if ( ( currentMillis - previousMillis ) >= interval )
  {
    Serial.println ( fadeValue );
    if ( fadeInOut )
    {
      fadeValue += fadeInStep;
      if ( fadeValue > fadeMax )
      {
        fadeValue = fadeMax;
        fadeInOut = false;
      }
    }
    else
    {
      fadeValue -= fadeOutStep;
      if ( fadeValue < fadeMin )
      {
        fadeValue = fadeMin;
        fadeInOut = true;
      }
    }
    previousMillis = currentMillis;
    analogWrite ( ledPin, fadeValue );
  }
  
  // do other brilliant things
}
1 Like

Thanks for reaching out flashko.
This is super help. Hope you have a wonderful day! :smiling_face_with_three_hearts:

Sure thing. Thank you so much PaulRB.
I just tried flashko's non-blocking code and it seems to work well !

Sorry, I meant to say you cannot use a for-loop to control the value of fadeValue.

No prob. Thanks for reminding

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