How to control a HD44780 LCD display from a PIC16F microcontroller

In this tutorial we’ll learn how to control a LCD display from a PIC microcontroller. LCD displays are one of the most used devices to display information. It allows an electronic system to show text and is easily programmable using a microcontroller. We’ll use a PIC16F88 from Microchip. This tutorial can be used to control any LCD display based on a HD44780 controller. Let’s create a little library to control a LCD display!

The HD44780 controller allows us to use either a 4-bit or a 8-bit mode to interface the LCD display to a microcontroller. We’ll first see the 8-bit mode, which uses more pins but is easier to understand for a first time.

Bill of Material

In addition to the usual components needed to run the PIC (see this tutorial if you forgot!), we’ll need a 16*2 characters LCD display (I used this one from Adafruit, which comes with the headers soldered, very convenient if you don’t want to lose time soldering!). We’ll also need a 10Ω resistor to protect the backlight LED, and a potentiometer to adjust the contrast. In the final version I used a second potentiometer to control the brightness instead of the 10Ω resistor. Two 10kΩ potentiometers will be perfect.

Build the circuit

LCD display

Let’s read the datasheet of our LCD display to understand how it works and how to connect it to our PIC. First, page 10, we see the list of the pins with their names.

List of the pins of the LCD display
List of the pins of the LCD display

If your display has a backlight LED, pin 15 will be LED+ and pin 16 will be LED-. As we won’t read data from the LCD display, we’ll connect R/W (pin 5) to GND, to keep it in write mode. Pins 4 to 14 will be controlled by the PIC.

The pin 3 is used to set the contrast, we will connect it to a potentiometer to adjust it so we can see the text on the screen correctly.

Here is the beginning of the schematic for the LCD side:

Schematic of the LCD display
Schematic of the LCD display


On the PIC side, we find the usual components needed to run the microcontroller, plus connections to the LCD display:

Connections on the PIC
Connections on the PIC

Final circuit

The full circuit is shown bellow:

Full circuit to control a LCD display from a PIC16F88
Full circuit to control a LCD display from a PIC16F88


How to control the display?

First, we need to understand how to control the display. According to the datasheet, it used two modes: a command mode and a data mode. The command mode is used to change settings in the display or move the cursor, and the data mode is used to display characters on the LCD. The full list of instructions is given page 11, but we’ll only need some of them.

Command mode is active when RS = 0, data mode is active when RS = 1. Here is a list of the instructions we’ll use:

Clear & return function
Clear & return function
Display control function
Display control function
Function set
Function set

The final instruction we’ll use will set the DDRAM address, which basically means it will move the cursor on the screen. As we see in the datasheet, for a 2-line display mode, the first line addresses will range from 0x00 to 0x27, and the second one from 0x40 to 0x67. But our screen only has 16 characters per line, which means that in reality, the only characters we’ll be able to use will be at addresses 0x00 to 0x0F for the first line and 0x40 to 0x4F for the second one.

Set the cursor position

To finish with, we’ll use the data write mode to display a character on the position pointed to by the cursor:

Display a character
Display a character

LCD library

Header file

Let’s write a small library to control our LCD. We’ll create a LCD.h and a LCD.c files to implement the functions. In the header file, we start by defining the pins used:

Then, we define the commands we’ve seen previously:

Lastly, we declare the prototype of the functions we’ll write in the .c file:

Details of the functions

The first function we write is the initialization function. It will set up the pins directions and initialize the LCD display to use the parameters defines previously in the commands.

The function used to send a command to the LCD display is the following. To send a command, we have to write its value on the data bus (LCD_D), while holding LCD_RS low (command mode) and keeping LCD_EN high for a bit (5ms is more than enough, as the execution time given by the datasheet is always inferior to 1.5ms). We then tie LCD_EN to ground to make sure no other command is executed by accident.

The clear function simply calls the command function to clear the screen and move the cursor to the origin:

The last command function will move the cursor to a given line and column. We first make sure the line and column are not too big for the screen. Then, as a line starts every 0x40 addresses, we can multiply the given line by 0x40 and add this value to a variable we call AC. This variable is initialized to 0x80 because it is the “set DDRAM address” instruction that we saw earlier. We then add the value of the column to it, and we can apply the command to the display.

To finish with, let’s write the functions that will display data on the screen. The first one will only display a single character at the current position of the cursor. It is very similar to the command function, except LCD_RS is set to 1 here (data mode).

Finally, we can write the function used to display a whole string on the LCD. It will simply call the previous function to display each character individually, until we read the character '\0'  (end of line).

Full code

Here is the full code for the LCD.h file:

And here is the full code for LCD.c:

Main file to test the library

To finish with, we write a main function that will test our library. After configuring the PIC, we just initialize the LCD and in the while(1) loop, we write “Hello” on the first line and “World!” on the second one. We then clear the display. We add a delay of 1 second between each step to see the result on the screen.


After compiling and programming the PIC, here is the result on the LCD display. We see that our text is shown correctly, congratulations! If you don’t see anything on the screen, try turning the potentiometers to change the brightness and contract.

Result on the LCD display
Result on the LCD display

If you have any question, please post a comment below.

Be the first to comment

%d bloggers like this: