16x2 Character [Dot-Matrix] LCD Module


The Serial Monitor is a convenient way to view data from an Arduino, but what if you want to make your project portable and view sensor values without access to a computer? Liquid crystal displays (LCDs) are excellent for displaying a string of words or sensor data.

This guide will help you in getting your 16×2 character LCD up and running, as well as other character LCDs (such as 16×4, 16×1, 20×4, etc.) that use Hitachi’s LCD controller chip, the HD44780.

Since the Arduino community has already created a library to support HD44780-based LCDs, you can easily interface them.

Do you know?

LCD, or Liquid Crystal Display, is a type of display that uses liquid crystals to show characters.

When activated by an electric current, these liquid crystals become opaque, blocking the backlight that is located behind the screen. As a result, that area will be darker than the rest. By activating the liquid crystal layer in specific pixels, characters can be generated.

Hardware Overview

As the name suggests, these LCDs are ideal for displaying only characters. A 16×2 character LCD, for example, can display 32 ASCII characters across two rows.

If you look closely, you can see tiny rectangles for each character on the screen as well as the pixels that make up a character. Each of these rectangles is a grid of 5×8 pixels.


Character LCDs are available in a variety of sizes and colors, including 16×1, 16×4, 20×4, white text on a blue background, black text on a green background, and many more.

One advantage of using any of these displays in your project is that they are “swappable,” meaning that you can easily replace them with another LCD of a different size or color. Your code will need to be tweaked slightly, but the wiring will remain the same!

16×2 Character LCD Pinout

Before we get into the hookup and example code, let’s check out the pinout. A standard character LCD has 16 pins (except for an RGB LCD, which has 18 pins).


GND is the ground pin.

VCC is the LCD’s power supply and is typically connected to 5 volts.

Vo (LCD Contrast) pin controls the contrast of the LCD. Using a simple voltage divider network and a potentiometer, we can make precise contrast adjustments.

RS (Register Select) pin is used to separate the commands (such as setting the cursor to a specific location, clearing the screen, etc.) from the data. The RS pin is set to LOW when sending commands to the LCD and HIGH when sending data.

R/W (Read/Write) pin allows you to read data from or write data to the LCD. Since the LCD is only used as an output device, this pin is typically held low. This forces the LCD into WRITE mode.

E (Enable) pin is used to enable the display. When this pin is set to LOW, the LCD ignores activity on the R/W, RS, and data bus lines; when it is set to HIGH, the LCD processes the incoming data.

D0-D7 (Data Bus) pins carry the 8 bit data we send to the display. To see an uppercase ‘A’ character on the display, for example, we set these pins to 0100 0001 (as per the ASCII table).

A-K (Anode & Cathode) pins are used to control the backlight of the LCD.

Testing a Character LCD

Now comes the exciting part: testing the LCD.

To begin, connect the Arduino’s 5V and GND pins to the breadboard power rail and plug your LCD into the breadboard.

The LCD has two separate power connections: one for the LCD (pins 1 and 2) and one for the LCD backlight (pins 15 and 16). Connect LCD pins 1 and 16 to GND and 2 and 15 to 5V.

Depending on the manufacturer, some LCDs include a current-limiting resistor for the backlight. It is located on the back of the LCD, close to pin 15. If your LCD does not contain this resistor or if you are unsure whether it does, you must add one between 5V and pin 15. It should be safe to use a 220 ohm resistor, although a value this high may make the backlight slightly dim. For better results, check the datasheet for the maximum backlight current and choose an appropriate resistor value.

Let’s connect a potentiometer to the display. This is necessary to fine-tune the contrast of the display for best visibility. Connect one side of the 10K potentiometer to 5V and the other to Ground, and connect the middle of the pot (wiper) to LCD pin 3.

That’s all. Now, turn on the Arduino. You will see the backlight light up. As you turn the potentiometer knob, you will see the first row of rectangles appear. If you have made it this far, Congratulations! Your LCD is functioning properly.

Wiring a 16×2 Character LCD to an Arduino

Let’s finish wiring up the LCD to the Arduino.

We know that data is sent to the LCD via eight data pins. However, HD44780-based LCDs are designed so that we can communicate with them using only four data pins (in 4-bit mode) rather than eight (in 8-bit mode). This helps us save 4 I/O pins!

So, to interface the LCD in 4-bit mode, only six pins are required: RS, EN, D7, D6, D5, and D4.

Connect the LCD’s four data pins (D4-D7) to digital pins 5 to 2 on the Arduino, the EN pin to digital pin 11, and the RS pin to digital pin 12.

The wiring is shown below.


Difference between 4-bit and 8-bit mode

There is a major difference between the 8-bit and 4-bit modes aside from the number of data pins required to interface the LCD.

8-bit mode is significantly faster than 4-bit mode. This is because in 8-bit mode, data is written in a single operation, whereas in 4-bit mode, a byte is split into two nibbles and two write operations are performed.

Therefore, 4-bit mode is commonly used to save I/O pins. 8-bit mode, on the other hand, is best suited when speed is a priority in the application and at least 10 I/O pins are available.

Arduino Example Code

The example sketch below prints “Hello World” to the LCD. First, try out the sketch, and then we’ll go over it in detail.

    // include the library code:
#include <LiquidCrystal.h>
// Creates an LCD object. Parameters: (rs, enable, d4, d5, d6, d7)
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() 
{
	// set up the LCD's number of columns and rows:
	lcd.begin(16, 2);
	// Clears the LCD screen
	lcd.clear();
}
void loop() 
{
	// Print a message to the LCD.
	lcd.print("  Hello world!");
	// set the cursor to column 0, line 1
	// (note: line 1 is the second row, since counting begins with 0):
	lcd.setCursor(0, 1);
	// Print a message to the LCD.
	lcd.print("  LCD Tutorial");
}
  

If everything is correct, a “Hello world!” should appear on the display.

Code Explanation:

The sketch begins by including the LiquidCrystal library. This library comes with the Arduino IDE and allows you to control Hitachi HD44780 driver-based LCD displays.


    // include the library code:
    #include <LiquidCrystal.h>
    
  

Next, an object of the LiquidCrystal class is created by passing as parameters the pin numbers to which the LCD’s RS, EN, and four data pins are connected.

    
    // Creates an LCD object. Parameters: (rs, enable, d4, d5, d6, d7)
    LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
    
  

In the setup, two functions are called. The first function is begin(). It is used to initialize the interface to the LCD screen and to specify the dimensions (columns and rows) of the display. If you’re using a 16×2 character LCD, you should pass 16 and 2; if you’re using a 20×4 LCD, you should pass 20 and 4.

The second function is clear(). This function clears the LCD screen and positions the cursor in the upper-left corner.

    
    lcd.begin(16, 2);
    lcd.clear();
    
  

In the loop, the print() function is used to print “Hello world!” to the LCD. Please remember to use quotation marks " " around the text. There is no need for quotation marks when printing numbers or variables.

    
    // Print a message to the LCD.
    lcd.print(" Hello world!");
    
  

The function setCursor() is then called to move the cursor to the second row. The cursor position specifies where you want the new text to appear on the LCD. It is assumed that the upper left corner is col=0 and row=0.

    
    lcd.setCursor(0, 1);
    lcd.print(" LCD Tutorial");
    
  

Other useful functions of the LiquidCrystal Library

There are many useful functions you can use with LiquidCrystal Object. Some of them are listed below:

  • lcd.home() function positions the cursor in the upper-left of the LCD without clearing the display.
  • lcd.blink() function displays a blinking block of 5×8 pixels at the position to which the next character will be written.
  • lcd.noBlink() function turns off the blinking LCD cursor.
  • lcd.cursor() function displays an underscore (line) at the position to which the next character will be written.
  • lcd.noCursor() function hides the LCD cursor.
  • lcd.scrollDisplayRight() function scrolls the contents of the display one space to the right. If you want the text to scroll continuously, you have to use this function inside a for loop.
  • lcd.scrollDisplayLeft() function scrolls the contents of the display one space to the left. Similar to the above function, use this inside a for loop for continuous scrolling.
  • lcd.noDisplay() function turns off the LCD display, without losing the text currently shown on it.
  • lcd.display() function turns on the LCD display, after it’s been turned off with noDisplay(). This will restore the text (and cursor) that was on the display.

Custom Character Generation for 16×2 Character LCD

If you find the default font uninteresting, you can create your own custom characters (glyphs) and symbols. They come in handy when you need to display a character that isn’t in the standard ASCII character set.

As previously discussed in this tutorial, a character is made up of a 5×8 pixel matrix; therefore, you must define your custom character within this matrix. You can define a character by using the createChar() function.

To use createChar(), you must first create an 8-byte array. Each byte in the array corresponds to a row in a 5×8 matrix. In a byte, the digits 0 and 1 indicate which pixels in a row should be ON and which should be OFF.

All of these user-defined characters are stored in the LCD’s CGRAM.

CGROM and CGRAM

All Hitachi HD44780 driver-based LCDs have two types of memory: CGROM and CGRAM (Character Generator ROM and RAM).

CGROM is non-volatile memory that retains data even when the power is removed, whereas CGRAM is volatile memory that loses data when the power is removed.

The CGROM stores the font that appears on a character LCD. When you instruct a character LCD to display the letter ‘A’, it needs to know which dots to turn on so that we see an ‘A’. This data is stored in the CGROM.

CGRAM is an additional memory for storing user-defined characters. This RAM is limited to 64 bytes. Therefore, for a 5×8 pixel LCD, only 8 user-defined characters can be stored in CGRAM, whereas for a 5×10 pixel LCD, only 4 can be stored.

Custom Character Generator

Creating custom characters has never been easier! We’ve developed a small application called Custom Character Generator. Can you see the blue grid below? You can click on any pixel to set or clear that pixel. And as you click, the code for the character is generated next to the grid. This code can be used directly in your Arduino sketch.

There’s no limit to what you can create. The only limitation is that the LiquidCrystal library only supports eight custom characters. But don’t be sad, look at the bright side; at least we have eight characters.

Arduino Example Code: Custom Character

The sketch below demonstrates how to display custom characters on the LCD.

    // include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
// make some custom characters:
byte Heart[8] = {
0b00000,
0b01010,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000,
0b00000
};
byte Bell[8] = {
0b00100,
0b01110,
0b01110,
0b01110,
0b11111,
0b00000,
0b00100,
0b00000
};

byte Alien[8] = {
0b11111,
0b10101,
0b11111,
0b11111,
0b01110,
0b01010,
0b11011,
0b00000
};
byte Check[8] = {
0b00000,
0b00001,
0b00011,
0b10110,
0b11100,
0b01000,
0b00000,
0b00000
};
byte Speaker[8] = {
0b00001,
0b00011,
0b01111,
0b01111,
0b01111,
0b00011,
0b00001,
0b00000
};

byte Sound[8] = {
0b00001,
0b00011,
0b00101,
0b01001,
0b01001,
0b01011,
0b11011,
0b11000
};

byte Skull[8] = {
0b00000,
0b01110,
0b10101,
0b11011,
0b01110,
0b01110,
0b00000,
0b00000
};
byte Lock[8] = {
0b01110,
0b10001,
0b10001,
0b11111,
0b11011,
0b11011,
0b11111,
0b00000
};
void setup() 
{
	// initialize LCD and set up the number of columns and rows: 
	lcd.begin(16, 2);
	// create a new character
	lcd.createChar(0, Heart);
	// create a new character
	lcd.createChar(1, Bell);
	// create a new character
	lcd.createChar(2, Alien);
	// create a new character
	lcd.createChar(3, Check);
	// create a new character
	lcd.createChar(4, Speaker);
	// create a new character
	lcd.createChar(5, Sound);
	// create a new character
	lcd.createChar(6, Skull);
	// create a new character
	lcd.createChar(7, Lock);
	// Clears the LCD screen
	lcd.clear();
	// Print a message to the lcd.
	lcd.print("Custom Character");
}
// Print All the custom characters
void loop() 
{ 
	lcd.setCursor(0, 1);
	lcd.write(byte(0));
	lcd.setCursor(2, 1);
	lcd.write(byte(1));
	lcd.setCursor(4, 1);
	lcd.write(byte(2));
	lcd.setCursor(6, 1);
	lcd.write(byte(3));
	lcd.setCursor(8, 1);
	lcd.write(byte(4));
	lcd.setCursor(10, 1);
	lcd.write(byte(5));
	lcd.setCursor(12, 1);
	lcd.write(byte(6));
	lcd.setCursor(14, 1);
	lcd.write(byte(7));
}
    
  

The output appears as shown.

Code Explanation: Custom Character

After including the library and creating the LCD object, custom character arrays are defined. The array consists of 8 bytes, with each byte representing a row in a 5×8 matrix.

This sketch contains eight custom-characters. Take, for example, the Heart[8] array. You can see that the bits (0s and 1s) are forming the shape of a heart. 0 turns the pixel off, and 1 turns it on.

    byte Heart[8] = {
0b00000,
0b01010,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000,
0b00000
};
    
  

In the setup, we use the createChar() function to create a custom character. This function accepts two parameters: a number between 0 and 7 to reserve one of the eight supported custom characters, and the name of the array.

    
// create a new character
lcd.createChar(0, Heart);
    
  

In the loop, to display the custom character, we simply call the write() function and pass it the number of the character we reserved earlier.

    
// byte(0) represents Heart character.
lcd.write(byte(0));
    
  


Post a Comment