Toggeling backlight on 16x2 LCD

I have a small issue I can’t seem to resolve which I’m sure you guys can help me with.

I’ve hooked up a “YwRobot Arduino LCM1602 IIC V1” screen to my Uno, and also a pushbutton. The display shows one message when i hold the button down, and another message when the button is not pushed (Instagram video here). The thing is - I’d like to be able to turn off the backlight. Or even better - I’d like to fit another pushbutton that turns the backlight on, and then a delay, say 30 seconds or something, and then off again.

Now, I’ve tried a couple of things, but haven’t managed to get it to work. I think my main problem is that lcd.backlight don’t seem to work in my code. After a bit of research in the library I’m using it seems that I have to use setBacklightPin or something, but I can’t seem to figure out how.

Can anyone help me out with this? Do I have to include other libraries to take care of this?
Here is my code: (Please note: all the commenting are in my native language. Oh, and also - tips on the rest of the code is more than welcome. This is my first “real” project, that’ll actually be used for something real once done)

/*  LCD-display Garasjeprosjekt
    Harald Halvorsen 23/1/14  */

// --------------------------------
// IMPORTERE NØDVENDIGE BIBLIOTEKER
// --------------------------------
    #include <Wire.h>                // Hører til Arduino IDE
    #include <LiquidCrystal_I2C.h>   // Bibliotek til LCD
    
// -------------------
// DEFINERE KONSTANTER
// -------------------
  // sette LCD-adresser til 0x27 for et 20 chars 4 line display
  // Sette pins på I2C chip:
  // ---  addr, en,rw,rs,d4,d5,d6,d7,bl,blpol  ---
    LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // LCD I2C adresse
    
  // Sette input-pin for trykknapp
  const int knapp = 2;
  const int led = 13;
  
// ------------------
// DEFINERE VARIABLER
// ------------------

// æ ø å Æ Ø Å
    byte newChar0[8] = {0b10101,0b01010,0b10101,0b01010,0b10101,0b01010,0b10101,0b01010}; // sjakkmønster
    byte Lae[8] ={B00000,B00000,B11010,B00101,B01111,B10100,B11111,B00000}; // æ 
    byte Loe[8] ={B00000,B00001,B01110,B10101,B10101,B01110,B10000,B00000}; // ø 
    byte Laa[8] ={B00100,B00000,B01110,B00001,B01111,B10001,B01111,B00000}; // å 
    byte Sae[8] ={B01111,B10100,B10100,B11110,B10100,B10100,B10111,B00000}; // Æ 
    byte Soe[8] ={B00001,B01110,B10011,B10101,B11001,B01110,B10000,B00000}; // Ø 
    byte Saa[8] ={B00100,B00000,B01110,B10001,B11111,B10001,B10001,B00000}; // Å
    byte Mlm[8] ={B00000,B00000,B00000,B00000,B00000,B00000,B00000,B00000}; // Mellomrom  
    // æ, ø, å, Æ, Ø, Å er plassert i RAMadresse 0, 1, 2, 3, 4, 5

// ------------
// SETUP-RUTINE
// ------------

void setup()
{
    lcd.begin(16,2);   // stille inn displayet for 16x2 tegn, og slå på bakbelysningen
    
    // Sette knapp som input
    pinMode(knapp, INPUT);
    pinMode(led, OUTPUT);
    digitalWrite(knapp, HIGH);
    
  // upload 8 selvdefinerende bokstaver
      lcd.createChar(0, newChar0); // Sjakk
      lcd.createChar(1, Lae); // æ 
      lcd.createChar(2, Loe); // ø 
      lcd.createChar(3, Laa); // å 
      lcd.createChar(4, Sae); // Æ 
      lcd.createChar(5, Soe); // Ø 
      lcd.createChar(6, Saa); // Å 
      lcd.createChar(7, Mlm); // Mellomrom 
       
      lcd.clear(); // Nødvendig etter Upload
}


// -------------
// LOOP-FUNKSJON
// -------------

void loop()
{
 int knappstatus = 0;              // Sette startstatus på knapp
 knappstatus = digitalRead(knapp); // Lese knapp
  if (knappstatus == LOW) {        // IF/ELSE-funksjon for melding
    digitalWrite(led, HIGH);
    lcd.setCursor(0,0); 
    lcd.print("Garasjen");
    lcd.setCursor(0,1);
    lcd.print("er ");
    lcd.write(3);
    lcd.print("pen   ");
  } else {
    digitalWrite(led, LOW);
    lcd.setCursor(0,0); 
    lcd.print("Garasjen");
    lcd.setCursor(0,1);
    lcd.print("er lukket");
  }

} // - -  THE END  - -

I think it is simpler than that. The jumper on the backpack is either ENABLES or DISABLES software control .
My personal feeling is that it ENABLES software control because the backlight blinks when the controller
finishes loading a program. My parallel LCD backlight is on all the time (unless I use a transistor). But removing
the jumper turns off the backlight I can tell you there is a backlight command in the I2C Hello World example.

Maybe someone else can say for sure.
If you can control it with software there is no need to read the following:
Either way you can remove the jumper and connect a two-wire cable to the where the jumper was
connected and connect one end to the collector of an NPN transistor and the other wire to the emitter
of the transistor. Before you do that you need to ohm it out (with the power off) to find to find out which
pin is connected to pin -15 of the parallel lcd. Once you know that , you can connect the emitter of the
transistor to that pin and the other pin of the 2-pin male connector would go to the collector of the
transister. You then need to add a 1 k resistor between the base of the transistor and the arduino
digital output to want to use to control the backlight. If that doesn’t work you can use a small 5V dc relay
(from RadioShack or wherever and connect the 2-pin connector to the common and Normally Open
contacts of the relay and use a transitor to turn on the relay with the collector connected to one end
of the coil and the emitter to ground. The other end of the coil to +5V and a 1 k resistor between the
base of the transistor and your arduino digital output. That will definately do what you want.
Hopefully someone else has a simpler solution but whatever you do , don’t do anything with that
connector without running by someone so you don’t damage your lcd. That jumper connects +5V to
the backlight so one pin goes to the backlight (pin-15) and the other to +5V , possibly with an 82 ohm resistor
in series. You should add a 1N4001 diode across the collector & emitter of the transistor with the band (cathode)
connected to the collector and other end (anode) to the emitter to protect the transistor from back-EMF.

Thanks for the quick reply!

However - I don’t think it’s a hardware problem. I did a bit more reading, and in one of the example codes on the page I found the library, there is this block of code in one of the examples:

// ------- Quick 3 blinks of backlight  -------------
  for(int i = 0; i< 3; i++)
  {
    lcd.backlight();
    delay(250);
    lcd.noBacklight();
    delay(250);
  }
  lcd.backlight(); // finish with backlight on

I added that in my setup, and the comment in the code is quite right - the screen indeed flashes three times before loop. So - that tells me that what I’m after can actually be done in the code, no? So how do I go about it? Any tips?

You just confirmed it is s/w controlled so all you need is to read a switch (button) and use an if statement to check the switch and put a backlight OFF (or ON) statement to execute when if (switch==ON) is true. right ?

You don't need to mess with setBacklightPin() that is old deprecated API code and should no longer be used. Also, don't use setBacklight(dimvalue) as that takes a dim value parameter and the hardware you have does not support dimming.

If you fill in the full constuctor with the backlight information as you have done, lcd.begin() will turn on the backlight. And then simply use lcd.noBacklight() to turn it off and then lcd.backlight() to turn i back on.

For the external button stuff, you will have to connect a button to the AVR Then use digitalRead() to detect it being pushed, then based on what you want to do you can simply call lcd.backlight() or lcd.noBacklight() to turn the backlight on/off as desired.

--- bill

Yeah, I tried that. Works perfectly. Thanks Don.

Yeah, I tried that. Works perfectly. Thanks Don.

What did you try? What are you thanking me for?

Don

I never tried to control the backlight on my I2C lcd because I never had a reason to. I have on my 4-bit but not the I2C. I knew there was a backlight statement had never really tested it (by removing it) but I do remember seeing the backlight blink off right after loading a program. After reading your comment I thought I should test it just to find out if is s/w controlled (as I thought) and it worked. So I know it's a minor thing but it is one more thing I learned so for that little tidbit I thank you. Progress never ends . it just continues one baby step at a time...

Maybe it's those funny cigarettes. Have you been to Colorado lately?

Don

No. Just curiosity. I just wondered if it worked. I can think of a couple uses for it.

By the way, that won't turn off the display entirely. Just the backlight as it says. But the characters should still be displayed. To turn everything off, you also need to call noDisplay()

It's very easy to save the time any button is pressed and then compare that against the current time in loop() to shut off the display if nothing was pressed for x seconds. :)

Thanks for the help, folks! It's now working the way I wanted :)

Now, one other thing - I am planning to fit this LCD inside a nice looking enclosure - not sure what kind yet - and I don't want to use the same button as I have on the breadboard now (one of these. The coolest thing would be to have just a touch sensitive small 1x1cm pad, or something - to turn on the backlight. Now, I've been checking eBay, and the closest I can find is something like this - but how would one go about to "integrate" the "button" in an enclosure? I mean - I don't want this to be visible in any way, if you know what I mean. Any tips on this? Or any other cool looking, discrete pushbutton?

No need to get a fancy sensor. Any strip of copper or metal will do: http://playground.arduino.cc//Main/CapacitiveSensor?from=Main.CapSense http://www.youtube.com/watch?v=BHQPqQ_5ulc

If the plastic allows the electric field to pass through and the right RC constant is chosen you may even be able to make it work through the enclosure.

Thanks for the tip, but I don’t think I’m capable of DIYing a nice looking button, hehe. This is going up in plain public view, so the WAF (Wife Acceptance Factor) has to be at least 90.

What I’d really like is a small button similar to this, but the problem with this one is that it’s got the connectors and stuff on the same side as the touch-area, and that’a no good when I want to place it in a hole on the front of my box alongside the display, for instance. Something looking like this beside my display would be sexy!

Anyway - I notices a little thing now. When I’ve hit the button for the backlight, and the display lights up, the other button - the one that changes the message in the display doesn’t seem to work. It’s like the backlight freezes the display, in a way, if you know what I mean. Is there a workaround for this? Maybe it’s my n00bie code that’s not 100%? Here’s the code:

/*
Garasjeprosjekt
Harald Halvorsen . Januar, 2014
*/

//  --------------------------------
//  IMPORTERE NØDVENDIGE BIBLIOTEKER
//  --------------------------------
    #include <Wire.h>                // Hører til Arduino IDE
    #include <LiquidCrystal_I2C.h>   // Bibliotek til LCD

//  -------------------
//  DEFINERE KONSTANTER
//  -------------------
    LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // LCD I2C adresse

    const int garasjeKnapp = 2;   // Bryter i garasjen
    const int led = 13;           // Intern LED for signaltest
    
    const int blKnapp = 12;  // Knapp for backlight
    int blState = 0;         // Startstatus på backlight av/på
  
//  ------------------
//  DEFINERE VARIABLER
//  ------------------
    // Kode for å få æ, ø, å, Æ, Ø, Å i display
    byte Lae[8] = {B00000,B00000,B11010,B00101,B01111,B10100,B11111,B00000}; // æ 
    byte Loe[8] = {B00000,B00001,B01110,B10101,B10101,B01110,B10000,B00000}; // ø 
    byte Laa[8] = {B00100,B00000,B01110,B00001,B01111,B10001,B01111,B00000}; // å 
    byte Sae[8] = {B01111,B10100,B10100,B11110,B10100,B10100,B10111,B00000}; // Æ 
    byte Soe[8] = {B00001,B01110,B10011,B10101,B11001,B01110,B10000,B00000}; // Ø 
    byte Saa[8] = {B00100,B00000,B01110,B10001,B11111,B10001,B10001,B00000}; // Å
    // æ, ø, å, Æ, Ø, Å er plassert i RAMadresse 0, 1, 2, 3, 4, 5

//  ------------
//  SETUP-RUTINE
//  ------------

void setup() {
  
    lcd.begin(16,2);   // stille inn displayet for 16x2 tegn, og slå på bakbelysningen
    
    pinMode(garasjeKnapp, INPUT);      // Bryter til garasjen
    digitalWrite(garasjeKnapp, HIGH);  // Startstatus på garasjebryter
    pinMode(led, OUTPUT);              // Intern LED for signaltest
    pinMode(blKnapp, INPUT);           // Bryter til backlight

    // Laste opp seks selvdefinerende bokstaver
    lcd.createChar(0, Lae); // æ 
    lcd.createChar(1, Loe); // ø 
    lcd.createChar(2, Laa); // å 
    lcd.createChar(3, Sae); // Æ 
    lcd.createChar(4, Soe); // Ø 
    lcd.createChar(5, Saa); // Å 
    lcd.clear();            // Nødvendig etter Upload
    
}

//  -------------
//  LOOP-FUNKSJON
//  -------------

    void loop() {
            
      int garasjeKnappStatus = 0;                      // Sette startstatus på knapp
      garasjeKnappStatus = digitalRead(garasjeKnapp);  // Lese knapp

      // Funksjon for tekst på display
      if (garasjeKnappStatus == HIGH) {  
        lcd.setCursor(0,0);              
        lcd.print("Garasjen");        
        lcd.setCursor(0,1);             
        lcd.print("er ");                  
        lcd.write(2);                
        lcd.print("pen   ");         
      } else {                           
        lcd.setCursor(0,0);       
        lcd.print("Garasjen");         
        lcd.setCursor(0,1);          
        lcd.print("er lukket");            
      }
      
      // Funksjon for å slå på backlight
      blState = digitalRead(blKnapp);   
      if (blState == HIGH) {           
        lcd.backlight();               
        delay(5000);                   
      } else {                         
        lcd.noBacklight();     
      }

}

What I meant is that you may be able to place the metal surface inside the case and that it will work through the plastic of the case. You will have to try it, but it's not always necessary to actually touch these sensors. They can work when you get near them and also through certain materials.

The problem is probably your five second delay after switch on the backlight

Serenifly: The problem is probably your five second delay after switch on the backlight

Is there another way to leave the backlight on for X amount of time after button is pushed?

See the BlinkWithoutDelay example: http://arduino.cc/en/Tutorial/BlinkWithoutDelay

Save the millis() value when the backlight was switched on to an unsigned long. Then subtract it from the current millis() value and check if the result is greater than 5000. Also set a boolean when the button was pressed to tell you the backlight status and only do the comparison when the backlight was switched on.

Something like this (not tested!):

void loop()
{
     static unsigned long backlightTime;
     static boolean backlightOn;

     if(digitalRead(blKnapp) == HIGH)
     {
          delay(20);     //primitive debounce button. You forgot that too
          backlightOn = true;
          backlightTime = millis();
     }

     if(backlightOn == true && millis() - backlightTime > 5000)
     {
          lcd.noBacklight();
          backlightOn = false;
     }
}

In this code pressing the button again will lengthen the time the light is on because the time is always overwritten

Thanks a lot! I've never seen that way of doing things before :) Solved my problem!

Now I am ready to move this project from my breadboard and over to permanent installation. I just have two more questions:

1. I like to draw up my projects in Fritzing. I do this for various reasons - one is to get training in writing and reading circuit designs, another is just to save them for later reference. But I can't seem to find a LCD in there with the backpack. Any site I can download that, or what do I do? 2. On this project I am using two resistors. Both are 10K and one of them is a pulldown from the button changing the message in the display. The other one is a pulldown on the backlight button - connected between the button and the wire that goes to the arduino digital pin. Now - I can't remember why I chose 10K -I think maybe they've just been sticking around from my tutorials or something - I remember using a 10K when I did the "click button to light LED"-tutorial. I know how to calculate which resistor to use when I'm lighting, say, an LED, but how do I know what kind of resistor I need when hooking up buttons like this? I am very new to electronics, so I think I could use some guidance in this matter...

There's basically only two types of resistors used for biasing an input or switch, they PASSIVE: to establish a passive state of HIGH or LOW while waiting for something to happen. ACTIVE: to over-ride a PASSIVE state to change the logic from HIGH to LOW or vice versa.

A general guideline to use when choosing values for these two types is: Resistor(PASSIVE)= 10 X Resistor(ACTIVE) ie: Let R(ACTIVE) = 1 k ohm then R(PASSIVE) = 10 k ohm Hence , the resistance of the ACTIVE state resistor is 1/10th that of the PASSIVE , resulting in 10 times the current of the PASSIVE resistor , to guarantee that the state will change. When talking about TTL logic (5V logic) circuits, 10k is a typical PASSIVE resistor value to hold an input HIGH or LOW, while drawing very little current, and 1 k is a typical ACTIVE resistor value to change that state . If you have a button with one side of it connected to an input with a 10 k pullup/pulldown resistor and the other side connected to +5V or GND with a 1 k resistor, when you press the button, the input will see the logic change state. The 1 k resistor draws less current than a direct short to ground which may be a consideration in battery powered circuits. Basically any combination of resistors R & 10R will achieve the same result but it's probably not a good idea to go less than 100 ohms for an ACTIVE type resistor, so for example 470 & 4.7 k , 330 & 3.3k , but there is no need for anything less than 10 k for a PASSIVE type resistor, the exception of course being the I2C pullups which should be 4.7k.,. and the ONEWIRE pullups , also 4.7 k ohm.

Hi, and thanks for all the advice and guidance!

I am closing in on the project, preparing to move it from the breadboard to my garage and hallway.

However - I’ve got some quiestions about the “correctness” of my wiring and/or code. As my display/backback-unit isn’t in Fritzing (not that I can see, at least) I have not included it in this sketch, but here’s the wiring for my buttons:

The top button is where my garage door sensor will be. The bottom is the backlight toggle.

Now - other than this, I have an Arduino Pro Micro (sparkfun lookalike) and the 1602 I2C-display hooked up. And everything is working fine. The thing I am wondering is: how come I’ve ended up wiring the two buttons differently? Of course - this is impossible for you guys to answer, since I am the one who’s done it, hehe, but all my wiring and code have come about from simple beginner tutorials and tips/advice from this forum. So - what I was hoping for, was that someone in here, who’s got a tad more knowledge and skill, could take a look at this wiring, and the code below, and check if there’s a better way to hook this up, and/or code it. More efficiently, or something. I really don’t know how I came about the different two button setups, and I don’t quite understand it either. I’ve tried to hook the button connected to pin 10 exactly the same as the other one, and altering the code to get it to work, but I can’t seem to get it working.

Anyone have a couple of minutes to take a look and try to explain it to me?

Oh, and here’s the full code:

//  --------------------------------
//  IMPORTERE NØDVENDIGE BIBLIOTEKER
//  --------------------------------
    #include <Wire.h>                // Hører til Arduino IDE
    #include <LiquidCrystal_I2C.h>   // Bibliotek til LCD

//  -------------------
//  DEFINERE KONSTANTER
//  -------------------
    LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // LCD I2C adresse

    const int garasjeKnapp = 14;   // Bryter i garasjen
    const int blKnapp = 10;  // Knapp for backlight

//  ------------------
//  DEFINERE VARIABLER
//  ------------------
    // Kode for å få æ, ø, å, Æ, Ø, Å i display
    byte Lae[8] = {B00000,B00000,B11010,B00101,B01111,B10100,B11111,B00000}; // æ 
    byte Loe[8] = {B00000,B00001,B01110,B10101,B10101,B01110,B10000,B00000}; // ø 
    byte Laa[8] = {B00100,B00000,B01110,B00001,B01111,B10001,B01111,B00000}; // å 
    byte Sae[8] = {B01111,B10100,B10100,B11110,B10100,B10100,B10111,B00000}; // Æ 
    byte Soe[8] = {B00001,B01110,B10011,B10101,B11001,B01110,B10000,B00000}; // Ø 
    byte Saa[8] = {B00100,B00000,B01110,B10001,B11111,B10001,B10001,B00000}; // Å
    // æ, ø, å, Æ, Ø, Å er plassert i RAMadresse 0, 1, 2, 3, 4, 5

//  ------------
//  SETUP-RUTINE
//  ------------

void setup() {

    lcd.begin(16,2);   // stille inn displayet for 16x2 tegn, og slå på bakbelysningen
    
    pinMode(garasjeKnapp, INPUT);      // Bryter til garasjen
    digitalWrite(garasjeKnapp, HIGH);  // Startstatus på garasjebryter
    pinMode(blKnapp, INPUT);              // Bryter til backlight
    
    // Laste opp seks selvdefinerende bokstaver
    lcd.createChar(0, Lae); // æ 
    lcd.createChar(1, Loe); // ø 
    lcd.createChar(2, Laa); // å 
    lcd.createChar(3, Sae); // Æ 
    lcd.createChar(4, Soe); // Ø 
    lcd.createChar(5, Saa); // Å 
    lcd.clear();            // Nødvendig etter Upload

}

//  -------------
//  LOOP-FUNKSJON
//  -------------

void loop() {
      
    int garasjeKnappStatus = 0;                      
    garasjeKnappStatus = digitalRead(garasjeKnapp);  
    
    //  Display text
    if (garasjeKnappStatus == HIGH) {
        lcd.setCursor(0,0);              
        lcd.print("Garasjen");        
        lcd.setCursor(0,1);             
        lcd.print("er ");                  
        lcd.write(2);                
        lcd.print("pen   ");         
      } else {                
        lcd.setCursor(0,0);       
        lcd.print("Garasjen");         
        lcd.setCursor(0,1);          
        lcd.print("er lukket");            
    }
    
    //  Backlight toggeling   
    static unsigned long backlightTime;
    static boolean backlightOn;
    
    if (digitalRead(blKnapp) == HIGH) {
    delay(20);     // Debounce
    backlightOn = true;
    backlightTime = millis();
    lcd.backlight();
    }
    
    if (backlightOn == true && millis() - backlightTime > 10000) {
    lcd.noBacklight();
    backlightOn = false;
    }

} // SLUTT