LCDs are alphanumeric (or graphical) displays. They are frequently used in microcontroller based applications. There are many devices in the market which come in different shapes and sizes.

Some LCDs have 40 or more character lengths with the capability to display several lines. Some other LCD displays can be programmed to display graphic images. Some modules offer color displays, while some others incorporate back lighting so that they can be viewed in dimly lit conditions. 
In terms of interfacing technique, we can group them in two categories:  Parallel LCDs and serial LCDs. 
Parallel LCDs like the popular Hitachi HD44780 series are connected to the microcontroller circuitry such that data is transferred to the LCD using more than one line and usually four data lines (4-bit mode) or eight data lines (8-bit mode) are used. This module is monochrome and comes in different shapes and sizes usually with character lengths of 8, 16, 20, 24, 32, and 40 and 1, 2 or 4 lines. Each character consists of 5×8 or 5×11 dot matrix.

A 2x16 LCD Display

Figure 1: A 2×16 LCD Display

Serial LCD is connected to a microcontroller using one data line only and data is transferred using the RS232 asynchronous data communications protocol. Serial LCDs are generally much easier to use, but they are more costly than the parallel ones. In this article we will discuss only the parallel LCDs, as they are cheaper and are used more commonly in microcontroller-based projects. 
Low-level programming of a parallel LCD is usually a complex task and requires a good understanding of the internal operation of the LCD, including an understanding of the timing diagrams. The good news, there are many LCD libraries that we can use to communicate with HITACHI HD44780 LCD controller This xlcd library works only with PIC18F series microcontrollers, but you can modify it for other series or you can write your own library based on the LCD controller datasheet, there are many other libraries as we’re gonna learn in this tutorial

This LCD display device generally has 14 pins which are marked on the PCB with some models have 16 pins if the the device has a back-light built in.

Function Pin Number Name Logic State Description
Ground 1 Vss 0V
Power supply 2 Vdd +5V
Contrast 3 Vee 0V to +5V
Control of operation 4 RS 0 D0-D7 are interpreted as commands
1 D0-D7 are interpreted as data
5 R/W 0 Write data (from microcontroller to LCD)
1 Read data (from LCD to microcontroller)
6 E 0 Access to LCD disabled
1 Normal operation
From 1 to 0 data/ commands are sent to LCD
Data/ commands 7 D0 0/1 Bit 0 LSB
8 D1 0/1 Bit 1
9 D2 0/1 Bit 2
10 D3 0/1 Bit 3
11 D4 0/1 Bit 4
12 D5 0/1 Bit 5
12 D6 0/1 Bit 6
14 D7 0/1 Bit 7 MSB

Table 1: Pin descriptions
Table 1 above shows the pin configuration and pin functions of a typical 14-pin LCD. If back-light is needed and available, The K pin should be connected to ground and pin A/Vee should be connected to positive supply via a series current limiting resistor as shown in figure 2 below.

LCD connection to Port B of PIC Microcontroller

Figure 2: LCD connection to Port B of PIC Microcontroller

The LCD controller contains three memory blocks:

  • DDRAM – Display Data RAM: This memory block is used for storing characters that should be displayed.
    Each character occupies one DDRAM address. The first line addresses are from 00 to 27, the second line addresses start from 40 to 67 in hexadecimal. To move the cursor to the beginning of second line, the DDRAM address will be 0x40. For LCDs with more than 2 lines, please check their datasheet for more information.
  • CGRAM – Character Generator RAM: This memory contains the default character map with all characters that can be displayed on the screen. The addresses of CGROM memory locations match the characters of ASCII table.


Symbol  ASCII Code in binary
0 00110000
1 00110001
2 00110010
$ 00100100
% 00100101
& 00100110
A 01000001
B 01000010
b 01100010
  • CGROM – Character Generator ROM: This memory is used  to create your own characters.

Some common HD44780 LCD controller command sets

 Instruction Byte
Clear display  0×01
Return cursor to home, and un-shift display  0×02
Move cursor right, do shift display (left)  0×05
Move cursor right, don’t shift display (this is the most common) 0×06
 Move cursor right, do shift display (left) 0×07
Display on, cursor off,  0x0C
Display on, cursor on, steady cursor  0x0E
Display on, cursor on, blinking cursor 0x0F
Shift cursor left  0×10
Shift cursor right  0×14
Shift display left  0×18
Shift display right  0x1C

Table 2: Some common HD44780 LCD controller command sets

Download the HD44780 LCD controller datasheet for more information.

LCD Library

MPLAB is phasing out the PIC18F Peripheral Library which is no longer included in XC8 compilers from version v1.35. In these versions, you have to download and install them separately into your compiler and they are now called Legacy Peripheral Libraries.

If you are using a latest XC8 compiler from v1.35 and you want to use MPLAB® Code Configurator (MCC) to generate drivers for your peripherals, you can use this LCD library supplied with Microchip PICDEM 2 Plus Demo Board Source Code. It can be used with PIC16F and PIC18F microcontroller series, all you need to do is to include the lcd.h and the lcd.c files, they include all the commonly used LCD functions. For more information, you can Download the HD44780 LCD controller datasheet.

Download: LCD library

  • LCD Connection: You can change the default LCD connections from PORTD to your preferred PORT by modifying the  #define LCD_PORT  in the lcd.h file and modifying the TRIS register in the lcd.c file. You can change as well the individual LCD pin connections by modifying the #define LCD_EN, #define LCD_RW and #define LCD_RS in the lcd.h file.
  • LCD_Initialize(): This routine initializes the LCD driver. This routine must be called before any other LCD routine is called.
  • LCDPutChar(): This function displays the specified ASCII character at current position on the LCD
  • LCDPutStr(): This routine writes string to LCD at current cursor position
  • LCDPutCmd(): This routine writes character to LCD command register
  • LCDGoto(): This function positions the cursor at the specified Line and column.
  • DisplayClr(): Clear the display
  • cursor_on(): Switch ON the cursor

Watch The video ADC and LCD with MPLAB Code Configurator


In this example, we are configuring our PIC18F26K20 with MPLAB® Code Configurator (MCC). The PIC will use 8MHz internal oscillator, the MCLR pin will be disabled. The LCD is connected to PORTB as shown on figure 3 below.

In this example we’ll learn how to use the LCDPutChar(), LCDPutStr(), LCDClr() and LCDGoto() functions of the LCD library

Figure 3: LCD connected to Port B of PIC18F26K20

Figure 4 below shows the project configuration overview with MPLAB Code Configurator

Figure 4: Project overview with MPLAB Code Configurator

Below is the main.c file:

 LCD Functions with PIC18 Peripheral Library

Microchip XC8 LCD library provides a large number of functions to control the HD44780 LCD controller with 4-bit and 8-bit data interface in the PIC18F Peripheral Libraries.

Watch the video tutorial


From XC8 v1.35, the Peripheral Libraries which include the LCD and other peripherals like ADC, SPI, I2C libraries are no longer included in the installation file as with previous versions. You can either write your own LCD library and use MPLAB code configurator to configure the other peripherals or the easiest is to download the Peripheral Libraries as a separate download and install them,. You can download them at microchip website under the MPLAB XC Compilers downloads tab. They are now called PIC18 Legacy Peripheral Libraries.

Download: PIC18 Legacy Peripheral Libraries

Four-bit interface-based text LCDs are the most commonly used LCDs because they save 4 microcontroller pins that can be used for other things.
You can access this library (only XC8 compiler v1.34 and older versions) by opening the help file (Help menu —> Help contents —>Search for LCD Function Descriptions or press F1 inside your project).

Function Description Code Example
BusyXLCD Is the LCD controller busy? while( BusyXLCD() );   // Wait here while LCD Controller is busy
OpenXLCD Configure the I/O lines used for controlling the LCD and initialize the LCD. OpenXLCD( FOUR_BIT & LINES_5X7 );   //Configure LCD in 4-bit Data Interface mode and 5×7 characters, multiple line display.
putcXLCD Write a byte to the LCD controller This example will display the character “L” on the LCD: unsigned char x = ‘L’;
putsXLCD Write a string from data memory to the LCD. The writing stops when a NULL character is detected. putsXLCD(“Hello World”);  // Display Hello World.
putrsXLCD Write a string from program memory to the LCD. The writing stops when a NULL character is detected. char mytxt[ ] = “Hello World”; putrsXLCD(mytxt);  // Display
Hello World.
ReadAddrXLCD Read the address byte from the LCD controller. char addr;
while ( BusyXLCD() );
addr = ReadAddrXLCD();  //Read address.
ReadDataXLCD Read a byte from the LCD controller. char data;
while ( BusyXLCD() );
data = ReadAddrXLCD();   //Read data from controller.
SetCGRamAddr Set the character generator address. char cgaddr = 0x1F;
while( BusyXLCD() );
SetCGRamAddr( cgaddr );
SetDDRamAddr Set the display data address. char ddaddr = 0x40;
while( BusyXLCD() );
SetDDRamAddr( ddaddr );  //Move cursor to beginning of
second line (16×2 LCD)
WriteCmdXLCD *Write a command to the LCD controller.
It is important that the LCD is not busy before sending a command. The while( BusyXLCD() ) should be used.
while( BusyXLCD() );
WriteCmdXLCD(DON);    //Turns display on

*Note: The following commands can be specified in the WriteCmdXLCD command argument:

  • DOFF:  Turns display off  example: WriteCmdXLCD(DOFF);
  • DON:   Turns display on
  • CURSOR_OFF:  Enables display, hide cursor
  • BLINK_ON:  Enables cursor blinking
  • BLINK_OFF:  Disables cursor blinking
  • SHIFT_CUR_LEFT: Shifts cursor left
  • SHIFT_CUR_RIGHT: Shifts cursor right
  • SHIFT_DISP_LEFT : Shifts display to the left
  • SHIFT_DISP_RIGHT: Shifts display to the right

The command argument can also use the set of commands in table 2 above:

The LCD library requires that the following delay functions be defined by the user before using the LCD functions:

DelayFor18TCY             Delay for 18 cycles
DelayPORXLCD            Delay for 15 ms and
DelayXLCD                     Delay for 5 ms

Assuming a microcontroller clock frequency of 4 MHz, the instruction cycle time is 1 μs. With a clock frequency of 8 MHz, the instruction cycle time is 0.5 μs. The 18-cycle delay is obtained using no operation (NOP) statements, where each NOP operation takes one cycle to execute. The end of a function with no “return” statement takes two cycles. When a “return” statement is used, a BRA statement branches to the end of the function where a RETURN 0 is executed to return from the function, thus adding two more cycles.
For more on delay functions, check the article:

Connecting Light Emitting Diodes (LED) to a PIC Microcontroller.

Examples of LCD Delays with 8 MHz and 4 MHz clock.

or very simply, this statement can also create that required delay:

 LCD Connection

LCD connection to a PIC microcontroller

Figure 5: LCD connection to a PIC microcontroller

The physical connection between the LCD and microcontroller I/O ports is defined in file “xlcd.h” and the default settings use PORTB pins in 4-bit mode where the low 4 bits of the port (RB0-RB3) are connected to the upper data lines (D4–D7) of the LCD. This file should be changed if the LCD is to be connected differently or to another PORT. After modifying the LCD pin connection in the xlcd.h file, the user must recompile the XLCD routines and then include the updated files in the project. This can be accomplished by adding the XLCD source files into the project.
The LCD pin R/W can be connected to ground if there is no need to read from the LCD as in most cases. This can spare another pin on the microcontroller.
Figure 5 above shows the LCD in 4-bit mode connected to PIC18F2620.

 Watch the Video Tutorial: LCD connection to PORTC  using XC8 PIC18 Peripheral Library LCD Functions

 Example using XC8 PIC18 Peripheral Library LCD Functions

Display the words ” Hello World” on first line of LCD and “LCD Display” on second line as shown in the circuit diagram on figure 5 above.
The MCLR is not enabled and the circuit uses internal oscillator at 8MHz so an external crystal device and a resistor to MCLR pin are not required.

You can download the full project files (MPLAB XC8 source code and Proteus Schematic design) below here.  All the files are zipped, you will need to unzip them (Download a free version of the Winzip utility to unzip files).  

Download LCD Example with MPLAB Code Configurator:

Download: LCD MPLAB Project with MPLAB Code Configurator

Download: LCD PIC18F26K20 Proteus Project

Download LCD Example with PIC18F Peripheral Libraries:

Download: LCD Header 

Download: LCD HEX

Download: LCD Main C
Download: LCD Interface Proteus