recent
Hot News

Use a DFRobots LCD shield with an Arduino / Genuino board and the LiquidCrystal library

Home

 


In this tutorial, we are going to learn together how to use a DFRobots "LCD Keypad" shield with an Arduino / Genuino board and the LiquidCrystal library supplied with the Arduino software. As a bonus, we will see how to vary the power of the LCD backlight.


Hello everyone !

In this tutorial, we will learn how to use a great classic in the Arduino world: the DFRobots LCD shield, also available for ten euros on eBay, DealExtreme, Amazon, etc.

PS The card used for this article is a Chinese copy at $ 12. It is, however, exactly the same card as the original from DFRobots from a functional point of view.

The shield

The shield

This shield is designed and manufactured by DFRobots. It is redistributed / cloned by many vendors on various sites such as eBay or DealExtreme. There are two versions: 1.0, presented in this article and 1.1, identical to 1.0 with some aesthetic changes.

The card is very basic which limits its price. This consists of an alphanumeric LCD screen of 2 x 16 characters, a contrast adjustment potentiometer and a series of 6 buttons (up, down, right, left, selection, reset). No more no less.

This shield is ideal for anyone who wants to add an LCD screen and control buttons (for a menu for example) to their project at a lower cost and above all without wiring.

The screen is white characters on a blue background. This is HD44780 compatible and is used with the LiquidCrystal library supplied as standard with the Arduino software. No additional installation is therefore necessary.

 The visual rendering of the screen is really very nice. White on blue is my favorite LCD color (besides being the most readable) 😉

The connection

It may seem a little weird to talk about connectors for an Arduino shield that just plugs into an Arduino board. However, like any Arduino shield, the LCD shield uses a number of pins to function.

Let's start with the LCD screen part first. The LCD screen is wired as follows:


Screen pin

Arduino pin

D4 (data)

D4

D5 (data)

D5

D6 (data)

D6

D7 (data)

D7

RS (control signal data / orders)

D8

EN (signal start transmission)

D9

Back lighting

D10 (PWM)


As you can see in the table above, the LCD display uses pins D4 to D10 (included). It is therefore important to be careful that no other shield uses these pins.

For example, the use of pins D4 and D10 poses known problems of compatibility with various shields such as the official Ethernet shield which uses pin D4 for the SD card reader and pin D10 for the Ethernet module. The same kind of problem arises with the SD shields from Sparkfun and Adafruit which use the D4 pin for communication with the SD card. So pay close attention to the pins that your shields use to avoid conflicts.

N.B. Pin D10 is used for PWM management of the backlight. By default, the backlight is active. So you don't have to do anything to activate it.

The buttons are managed via pin A0. It may sound a little weird, but the buttons are wired through a network of resistors which allows the status of the buttons to be "read" in the form of an analog voltage. This trick helps to reduce the number of pins needed for the buttons. Be careful though if your application or one of your shields uses pin A0.

PS The multiturn potentiometer at the top left of the shield allows you to adjust the contrast of the LCD screen. If the LCD screen seems too dark or on the contrary too bright, you need to adjust this potentiometer with a small screwdriver.

N.B. The shield also has a remote ICSP port for DIY enthusiasts who would like to connect their AVR programmer to their Arduino, or connect an SPI module via a flexible cable. I will deliberately ignore the use of this connector, which is reserved for experienced users.

Buttons

Let us dwell on the push buttons for a time.

Close-up on the buttons of the shield

As mentioned in the previous chapter, their wiring is a bit special. In reality, each push button is wired to a network of resistors which form a relatively complex voltage divider bridge.

To find out which button has been pressed, all you have to do is call the analogRead () function on pin A0 and compare the value read against a range of typical values.

For example, with my shield, I get the following values:


Button

Value read with analogRead(A0)

none

1023

UP 

135

DOWN 

312

LEFT 

485

RIGHT

727

SELECT 

2

In order to accommodate the possible variations from one card to another, here is the table of values to use:

Value read with analogRead(A0)

Button

0 <= valeur < 50

RIGHT 

50 <= valeur < 250

UP 

250 <= valeur < 450

DOWN 

450 <= valeur < 650

LEFT 

650 <= valeur < 850

SELECT 

>= 850

None

 The advantage of this method of wiring the buttons is that it only takes one analog pin to read all the push buttons. However, this solution has a big disadvantage since it is impossible to know if two buttons are pressed simultaneously.

N.B. The RST (reset) button cannot be used by the user. This button is directly wired to the RESET pin of the Arduino board and allows you to restart the Arduino board when needed.

The demonstration assembly

This demo assembly is so simple, that I won't even have to describe it. 😉

LCD Keypad + Arduino UNO board assembly


To carry out this assembly, we will need:
  • An Arduino UNO board (and its USB cable),
  • An LCD shield from DFRobots or similar.
Take the shield, plug it over the Arduino board. And There you go !

The basic code with the screen only



Hello World !

Let's start with the use of the LCD screen alone. We are going to display the classic “Hello World!” Message.

1 /* Dependencies */
2 #include <LiquidCrystal.h>

First of all, it is necessary to include the LiquidCrystal library that comes basic with the Arduino software in our code. This will allow us to communicate with the LCD screen by means of easy-to-use functions.

1 /** LiquidCrystal object for communication with the LCD screen */
2 LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

We will then declare an instance of the LiquidCrystal library with the pin numbers seen in the previous chapters.

PS You will notice that the management of pin D10 for the backlight is not carried out by the LiquidCrystal library. It is up to the user to take care of it.


/** Function setup() */
void setup() {
 lcd.begin(16, 2);
 lcd.print("Hello World !");
}

/** Function loop() */
void loop() {
  // Nothing to do
}

Then come the classic setup () and loop () functions.

The setup () function configures the LCD screen in 2 x 16 character mode and displays the text "Hello World!". The loop () function does nothing.

The complete code with comments:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * Basic code for using the Arduino LCD shield from DFRobots (LCD only).
 */

/* Dependencies */
#include <LiquidCrystal.h>


/** LiquidCrystal object for communication with the LCD screen */
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


/** Function setup() */
void setup() {
 lcd.begin(16, 2);
 lcd.print("Hello World !");
}

/** Function loop() */
void loop() {
  // Nothing to do
}

N.B We will see later in one (or more) article (s) how to use the various functions provided by the LiquidCrystal library. The articles in question will be linked at the bottom of the page as soon as they are available.

Basic code with read buttons

Code examples for buttons

Now that the LCD screen is functional, we will move on to reading the buttons.

1
2
3
4
5
/* Dependencies */
#include <LiquidCrystal.h>

/** LiquidCrystal object for communication with the LCD screen */
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
The beginning of the code is identical to that of the previous chapter.

1
2
3
4
5
6
7
8
9
/** List of usable buttons */
enum {
  BUTTON_NONE,  
  BUTTON_UP,    
  BUTTON_DOWN,  
  BUTTON_LEFT,  
  BUTTON_RIGHT, 
  BUTTON_SELECT 
};

first modification, we declare an enumeration of constants for our various buttons.

PS We could manually declare BUTTON_NONE = 0, BUTTON_UP = 1, etc. It would be long and boring to do. The C syntax gives us the possibility of doing this automatically with the enumerations, so take advantage of it

1
2
3
4
5
/** Function setup() */
void setup() {
  lcd.begin(16, 2);
  lcd.print("Button:");
}

Second modification, the setup () function will display "Button:" on the first line of the screen instead of "Hello World!".

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/** Return the pressed button (if there is one) */
byte getPressedButton() {

  /* Reads the state of the buttons */
  int value = analogRead(A0);

  /* Calculating the state of the buttons */
  if (value < 50)
    return BUTTON_RIGHT;
  else if (value < 250)
    return BUTTON_UP;
  else if (value < 450)
    return BUTTON_DOWN;
  else if (value < 650)
    return BUTTON_LEFT;
  else if (value < 850)
    return BUTTON_SELECT;
  else
    return BUTTON_NONE;
}

Serious things begin.

The getPressedButton () function - whose code is shown above - allows you to read the state of the shield buttons. This function uses analogRead (A0) to read the voltage on pin A0 and uses a series of if else to test the read value.

N.B. The if else are ordered from the smallest to the largest high value.


1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/** Function loop() */
void loop() {

  /* Displays the button pressed */
  lcd.setCursor(0, 1);
  switch (getPressedButton()) {
  case BUTTON_NONE:
    lcd.print(F("      "));
    break;

  case BUTTON_UP:
    lcd.print(F("UP    "));
    break;

  case BUTTON_DOWN:
    lcd.print(F("DOWN  "));
    break;

  case BUTTON_LEFT:
    lcd.print(F("LEFT  "));
    break;

  case BUTTON_RIGHT:
    lcd.print(F("RIGHT "));
    break;

  case BUTTON_SELECT:
    lcd.print(F("SELECT"));
    break;
  }

  /* Time for display */
  delay(100);
}

For this example, I modified the loop () function to include a switch case (equivalent to a series of if else) which displays a small text when a button is pressed.

N.B. I have added empty spaces at the end of certain texts to prevent the text from a previous display from causing a problem later.

The complete one with comments:

/**
 * Code de base pour l'utilisation de la shield Arduino LCD de DFRobots (LCD + boutons).
 */

/* Dependencies */
#include <LiquidCrystal.h>


/** LiquidCrystal object for communication with the LCD screen */
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


/** List of usable buttons*/
enum {
  BUTTON_NONE, 
  BUTTON_UP,    
  BUTTON_DOWN,  
  BUTTON_LEFT,  
  BUTTON_RIGHT,
  BUTTON_SELECT 
};


/** Function setup() */
void setup() {
  lcd.begin(16, 2);
  lcd.print("Bouton:");
}

/** Function loop() */
void loop() {

  /* Displays the button pressed */
lcd.setCursor(0, 1); switch (getPressedButton()) { case BUTTON_NONE: lcd.print(F(" ")); break; case BUTTON_UP: lcd.print(F("UP ")); break; case BUTTON_DOWN: lcd.print(F("DOWN ")); break; case BUTTON_LEFT: lcd.print(F("LEFT ")); break; case BUTTON_RIGHT: lcd.print(F("RIGHT ")); break; case BUTTON_SELECT: lcd.print(F("SELECT")); break; } /* Time for display */ delay(100); } /** Return the pressed button (if there is one) */ byte getPressedButton() { /* Reads the state of the buttons * / int value = analogRead(A0); /* Calculation of the state of the buttons * / if (value < 50)
    return BUTTON_RIGHT;
  else if (value < 250)
    return BUTTON_UP;
  else if (value < 450)
    return BUTTON_DOWN;
  else if (value < 650)
    return BUTTON_LEFT;
  else if (value < 850)
    return BUTTON_SELECT;
  else
    return BUTTON_NONE;
}

Bonus: Adjust the backlight brightness

For some applications, the backlight is not necessary, or at least not all the time.

With the LCD shield, it is possible, via pin D10, to control the backlight. You can turn it off, turn it on or reduce its brightness. To do this, just use the analogWrite () function on pin D10. A value of 0 turns the backlight off, a value of 255 turns it on, and anything in between these two extremes will reduce the brightness proportionally.

1
2
3
4
5
6
7
8
/* Dependencies */
#include <LiquidCrystal.h>

/** Pin for backlight control */
const byte BACKLIGHT_PWM_PIN = 10;

/** LiquidCrystal object for communication with the LCD screen */
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

To use this functionality, all you have to do is declare a constant with the pin number D10.


1
2
3
4
5
6
7
8
/** Function setup() */
void setup() {
 analogWrite(BACKLIGHT_PWM_PIN, 0); // No backlight
 //analogWrite(BACKLIGHT_PWM_PIN, 255); // 100% backlight
 
 lcd.begin(16, 2);
 lcd.print("Hello World !");
}

Then in the setup () function, you should call the analogWrite () function with the desired value.

N.B. If you wish to turn off the backlight completely, without using it subsequently, place the call to analogWrite () BEFORE the call to lcd.begin ().

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
/** Function loop() */
void loop() {
  for (int i = 0; i <= 255; ++i) {
    analogWrite(BACKLIGHT_PWM_PIN, i);
    delay(10);
  }
  for (int i = 255; i >= 0; --i) {
    analogWrite(BACKLIGHT_PWM_PIN, i);
    delay(10);
  }
}

For the example, I have included in the loop () function two loops which gradually turn on and then turn off the backlight.

In a "real" application, the modification of the backlight could be conditioned by a delay without pressing a button, by a menu, or the like. It's up to you to be creative;)

N.B. Once the analogWrite () call has been made, the value is kept in memory. So there is no need to periodically call analogWrite () with the same value.

The complete one with comments:

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
 * Basic code for using the Arduino LCD shield from DFRobots (LCD with PWM).
 */

/* Dependencies */
#include <LiquidCrystal.h>


/** Pin for backlight control */
const byte BACKLIGHT_PWM_PIN = 10;

/** LiquidCrystal object for communication with the LCD screen*/
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


/** Function setup() */
void setup() {
 analogWrite(BACKLIGHT_PWM_PIN, 0); // Pas de rétroéclairage
 //analogWrite(BACKLIGHT_PWM_PIN, 255); // Rétro-éclairage 100%
 
 lcd.begin(16, 2);
 lcd.print("Hello World !");
}

/** Function loop() */
void loop() {
  for (int i = 0; i <= 255; ++i) {
    analogWrite(BACKLIGHT_PWM_PIN, i);
    delay(10);
  }
  for (int i = 255; i >= 0; --i) {
    analogWrite(BACKLIGHT_PWM_PIN, i);
    delay(10);
  }
}

This tutorial is now complete.

If you liked this tutorial, feel free to comment on it on the forum, share it on social networks and support the site if you like it.



google-playkhamsatmostaqltradent