LED Gradual Fade

Hi,

I am fairly new to arduino and am trying to do a very simple LED gradual fade up and then gradual fade down, but over a time period of 5 minutes. So it would reach full brightness at the 5 min mark then take 5 mins fading down.

The code I am using is as follows:

void setup() { pinMode(9, OUTPUT); }

boolean fadein = true; int bright = 0;

void loop() {

// adjust brightness based on current direction if(fadein) { bright += 1; } else { bright -= 1; }

// apply current light level analogWrite(9,bright);

// when get to full bright, turn around if(255 == bright) { fadein = false; } // when get to full off, turn around if(0 == bright) { fadein = true; }

delay(3000); }

I realize the delay at the moment is not 5 minutes at the moment!!

The problem I am having is that I can see the 'stepping' up and down of the LED especially at low brightness levels. Is there something I can do to decrease the increments the LED steps up and down in/ Increase PWM so there are more increments? (I do know that arduino PWM works from 0-255) I essentially just want a smooth, gradual fade in and out over a 5 min period.

I hope that someone can help me out! Thank you

Hi,
Are you using current limiting resistor on the LED?

Tom… :slight_smile:

I have tried that with the same results. At the moment I have 6 resistors in parallel

You can use Timer/Counter1 for 16-bit PWM instead of the normal 8-bit PWM. That will get you 256 times as many steps of brightness. Timer/Counter1 controls Arduino UNO Pins 9 and 10. Here is an example I just wrote and tested:

void PWM16Begin(bool EnableA, bool EnableB) {
  // Stop Timer/Counter1
  TCCR1A = 0;  // Timer/Counter1 Control Register A
  TCCR1B = 0;  // Timer/Counter1 Control Register B
  TIMSK1 = 0;   // Timer/Counter1 Interrupt Mask Register
  TIFR1 = 0;   // Timer/Counter1 Interrupt Flag Register

  // Set 'TOP' for PWM resolution.  Assumes 16 MHz clock.
  ICR1 = 0xFFFF;  // 16-bit resolution. 244 Hz PWM
  // ICR1 = 0x7FFF; // 15-bit resolution.  488 Hz PWM
  // ICR1 = 0x3FFF; // 14-bit resolution.  976 Hz PWM
  // ICR1 = 0x1FFF; // 13-bit resolution.  1953 Hz PWM
  // ICR1 = 0x0FFF; // 12-bit resolution.  3906 Hz PWM
  // ICR1 = 0x07FF; // 11-bit resolution.  7812 Hz PWM

  // Set clock prescale to 1 for maximum PWM frequency
  TCCR1B |= (1<<CS10);

  // Set to Timer/Counter1 to Waveform Generation Mode 14: Fast PWM with TOP set by ICR1
  TCCR1A |= (1<<WGM11);
  TCCR1B |= (1<<WGM13) | (1<<WGM12) ;

  if (EnableA)
    PWM16EnableA();
    
  if (EnableB)
    PWM16EnableB();
}

void PWM16EnableA() {
  // Enable Fast PWM on Pin 9: Set OC1A at BOTTOM and clear OC1A on OCR1A compare
  TCCR1A |= (1<<COM1A1);
  OCR1A = ICR1 / 2;  // Default to 50% PWM
  pinMode(9, OUTPUT);
}

void PWM16EnableB() {
  // Enable Fast PWM on Pin 10: Set OC1B at BOTTOM and clear OC1B on OCR1B compare
  TCCR1A |= (1<<COM1B1);
  OCR1B = ICR1 / 2;  // Default to 50% PWM
  pinMode(10, OUTPUT);
}

inline void PWM16A(unsigned int PWMValue) {
  OCR1A = PWMValue;
}

inline void PWM16B(unsigned int PWMValue) {
  OCR1B = PWMValue;
}

void setup() {
  PWM16Begin(true, false);  // Start 16-bit PWM on Pin 9
}

void loop() {
  const unsigned long interval = 500;
  PWM16A(0);
  delay(interval);
  PWM16A(4);
  delay(interval);
  PWM16A(16);
  delay(interval);
  PWM16A(64);
  delay(interval);
  PWM16A(256);
  delay(interval);
  PWM16A(1024);
  delay(interval);
  PWM16A(4096);
  delay(interval);
  PWM16A(16384);
  delay(interval);
  PWM16A(65535);
  delay(interval);
}

That's great thank you!

I have never used the Timer/ Counter code (sorry i am a proper newbie!) How would I slow this fade right down (ideally i am trying to have this fade on over 5 mins)- would i do this by decreasing the increment in brackets after you've written PWM16A?

and then off again (I assume for off i would repeat the code but backwards!?)

Yeah - you'll probably want to change that up to make it look smoother. Those PWM16A/B functions will set the duty cycle between 0 and 65535 (2^16-1).

8-bit pwm just isn't enough to smoothly fade leds off.

   for (unsigned long i = 1, inc=1; i < 65536UL; (inc++, i+=inc)) {
    PWM16A(i);
    delay(831); // Should take about 5 minutes
  }

Hi johnwasser,

Just to say thank you so much for your help it has really been appreciated!!

To fade down, use:

  for (long i = 65535, inc=1; i > 0; (inc++, i-=inc)) {
    PWM16A(i);
    delay(831); // Should take about 5 minutes
  }

nice bit of information. no that I could tell, but apprent bbrightness will not be linear

dave-in-nj:
nice bit of information. no that I could tell, but apprent bbrightness will not be linear

Here’s an exponential fade:

void loop() {
  const float increment = 1.01;
  
  // Fade up
  for (float pwm = 1; (long)pwm < 65536; pwm *= increment) {
    PWM16A((long)pwm);
    delay(269);  // Should take about 5 minutes total
  }
  
  // Fade down
  for (float pwm = 65535; (long)pwm > 0; pwm /= increment) {
    PWM16A((long)pwm);
    delay(269);  // Should take about 5 minutes total
  }
}

It could probably all be done in fixed point but since the goal was to take five minutes per fade I don’t think the floats are doing any harm. :slight_smile: