[SOLVED] Fading LCD backlight via PWM pin

Hi all,

I would like to have a little function that dims up the LCD backlight before diplaying info and then dims it down when no new information is needs to be displayed.

This is the code I have:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int backlightPin = 6;
int brightness = 0;
int fadeAmount = 5;

void setup() {
  lcd.begin(20,4);
  pinMode(backlightPin, OUTPUT);
}

void loop() {
  lcd.home();
  lcd.clear();
  lcd.print("Awaking...");
  
  while (brightness <= 255) {
   
    analogWrite(backlightPin, brightness);
    brightness += fadeAmount;
    delay(20);
  }
  
  lcd.clear();
  lcd.home();
  lcd.write("Awake.");
  delay(1000);
  
  lcd.clear();
  lcd.home();
  lcd.write("Going to sleep...");
  
  while (brightness >= 0) {
     
    analogWrite(backlightPin, brightness);
    brightness -= fadeAmount;
    delay(20);
  }
   
  lcd.clear();
  lcd.home();
  lcd.write("Asleep.");
  delay(1000);
   
   
}

I don't see anything wrong with this code, however:

  1. the backlight is less bright than if hooked up to the +5V rail
  2. the screen blinks at the end of the fade to dark and before fading back to full light; and again when fully lit and before dimming to dark.

Here is a little video to illustrate the blinking situation

I suspect this has to do with the Atmega's internals but I'm not skilled enough to know more than that. Any advice on how to fix this? Or a better way to accomplish this dimming effect without the glitches and with full backlighting?

Does this make any difference?

brightness += fadeAmount;
analogWrite(backlightPin, brightness);

Maybe your not getting the full 5v through the PWN pin

Also try debugging the brightness value to make sure it's going to 255 and back to 0 then back to 255.

Good idea though.

You're looping a little bit too much.

In the first while loop even if brightness is 255 you add 5. Since it's an int you get 260.

In the second while loop even if brightness is 0 you subtract 5. Since it's an int you get -5.

I changed my loop to this:

void fadeLCD(byte mode, int duration) {
  if (mode == 1) {
    for (brightness = 0; brightness <= 255; brightness++) {
      analogWrite(backlightPin, brightness);
      if (brightness != 255) {
        delay(duration/256);
      }
    }
  }
  if (mode == 0) {
    for (brightness = 255; brightness >= 0; brightness--) {
      analogWrite(backlightPin, brightness);
      if (brightness != 0) {
        delay(duration/256);
      }
    }
  }
}

However, I would like to use "up" and "down" for the value of mode, out of clarity. But if I do this:

void fadeLCD(byte mode, int duration) {

and call the function with

fadeLCD('up',fadeLen);

it doesn't work.
How can I do? Is it possible at all?

Also, I checked the voltage on the PWM and the +5V rail: they are identical (when the PWN reaches max value). Why would the backlight not be as bright as if I hooked it up straight to the +5V rail?

Do you notice the flicker pwm makes? I havent had the chance to try it but i think if you change the prescaler to a faster pwm there will be no flicker and who kbows maybe look brighter,
this line will make it faster, at the end 0x3 is normal, higher number is faster i believe up to like 6

 TCCR2B = TCCR2B & B01111000 | 0x04;// SET PRESCALER

and that's for pin 3 & 11 i believe

The use of 'up' could be a define.

define up 1
define down 0

That way your don't have to compare ascii values.

define up 1
define down 0

Should be like:

#define up 1
#define down 0

Oh yeah, the # :blush:

Just had a thought, have you tried swapping it up?

Putting 5v into the backlight and then using the PWN pin as a drain to control the brightness.

I think that can be done, could be wrong too.

Putting 5v into the backlight and then using the PWN pin as a drain to control the brightness.

Putting +5v from the PWM pin of the arduino to anode of an LED and ground to ground of the arduino will make it work.

Or the anode to 5v and pwm to cathode, which just means 0 pwm is brightest and 255 is off

winner10920:
Or the anode to 5v and pwm to cathode, which just means 0 pwm is brightest and 255 is off

This backlight is still dimmer than off the +5V rail

You can in such a case use a transistor with its base connected to the pwm pin with a 220min resistor, just like you drive a high power motor or relay,take care of the base current needed to turn the transistor on as chip can supply a max of 40ma.

Could you give more details please? I have a PN2222 transistor as part of my Arduino starters kit but I have never used it and I have no idea how to wire it up...

Well you have the very right transistor , utilise it just like you would run a relay ,I have written other things already, in the above post. :*

Could you give more details please? I have a PN2222 transistor as part of my Arduino starters kit but I have never used it and I have no idea how to wire it up...

Follow this:

But only use one LED. Or use multiple. Who am I to tell you what to do?

Also note that R2-R5 will depend on how much current your LED wants. Use this page

http://led.linear1.org/1led.wiz

to figure that out (you'll need the specifics for your LED. If you don't have them, 2v forward voltage and 20 mA current is typical).

Thanks, it worked. Minus the resistor for the LED because it's built in the LCD screen already.

Very cool idea sir, this topic should be flagged for hot topic.

Thanks!

Just saw this and thought it may be of use too.

ok i might be late to reply , but for future reference ,

only changing the loops having conditions (<= 255 or >=0 ) should not contain the equal to sign..

and also the original code in the first code should contain "brighness = 0" at the start of every loop.. works like a charm without complexities..

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11,5,4,3,2);

int backlightPin = 10;
int brightness = 0;
int fadeAmount = 5;

void setup() {
  lcd.begin(16,2);
  pinMode(backlightPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  lcd.home();
  lcd.clear();
  lcd.print("Awaking...");
   brightness = 0;
  while (brightness < 255) {
   
    analogWrite(backlightPin, brightness);
    brightness += fadeAmount;
    delay(20);
   
    
  }
  Serial.print("End of while loop");
  lcd.clear();
  lcd.home();
  lcd.write("Awake.");
  delay(1000);
  
  lcd.clear();
  lcd.home();
  lcd.write("Going to sleep...");
  
  while (brightness > 0) {
     
    analogWrite(backlightPin, brightness);
    brightness -= fadeAmount;
    delay(20);
  }
   
  lcd.clear();
  lcd.home();
  lcd.write("Asleep.");
  delay(1000);
   
   
}

Even better than a define is

typedef enum { DOWN, UP } direction_t;

void fadeBacklight( direction_t dir, int amount)
{
  // Stuff goes here.
}