Interfacing LCD Display With PIC Microcontroller – XC8
Français
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.
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.
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.
Example:
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.
Buy an LCD from our Online Store
[porto_products view=”grid” columns=”2″ ids=”5348, 4924″]
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
Example:
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:
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
#include "mcc_generated_files/mcc.h" #include "lcd.h" /* Main application */ // This function creates seconds delay. // The argument specifies the delay time in seconds void Delay_Seconds(unsigned char z) { unsigned char x,y; for (y = 0; y < z; y++) { for (x = 0; x < 100; x++)__delay_ms(10); } } void main(void) { // Initialize the device SYSTEM_Initialize(); // initialize the LCD LCD_Initialize(); // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global and Peripheral Interrupts // Use the following macros to: // Enable high priority global interrupts //INTERRUPT_GlobalInterruptHighEnable(); // Enable low priority global interrupts. //INTERRUPT_GlobalInterruptLowEnable(); // Disable high priority global interrupts //INTERRUPT_GlobalInterruptHighDisable(); // Disable low priority global interrupts. //INTERRUPT_GlobalInterruptLowDisable(); // Enable the Global Interrupts //INTERRUPT_GlobalInterruptEnable(); // Enable the Peripheral Interrupts //INTERRUPT_PeripheralInterruptEnable(); // Disable the Global Interrupts //INTERRUPT_GlobalInterruptDisable(); // Disable the Peripheral Interrupts //INTERRUPT_PeripheralInterruptDisable(); LCDPutStr(" Hello World!"); //Display String "Hello World" LCDGoto(8,1); //Go to column 8 of second line LCDPutChar('1'); //Display character '1' Delay_Seconds(1); // 1 second delay LCDGoto(8,1); //Go to column 8 of second line LCDPutChar('2'); //Display character '2' Delay_Seconds(1); // 1 second delay LCDGoto(8,1); //Go to column 8 of second line LCDPutChar('3'); //Display character '3' Delay_Seconds(1); // 1 second delay DisplayClr(); // Clear the display LCDPutStr(" LCD Display"); //Display String "LCD Display" LCDGoto(0,1); //Go to second line LCDPutStr("StudentCompanion"); //Display String "StudentCompanion" while (1) { // Add your application code } } /** End of 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
Important:
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’; putcXLCD(x); |
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:
Example:
1 |
WriteCmdXLCD(0×01 ); // Clear the screen |
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.
1 2 3 4 5 6 7 8 |
void DelayFor18TCY( void ) //18 cycles delay { Nop( ); Nop( ); Nop( ); Nop( ); Nop( ); Nop( ); Nop( ); Nop( ); Nop( ); Nop( ); Nop( ); Nop( ); Nop( ); Nop( ); return; } |
or very simply, this statement can also create that required delay:
1 2 3 4 |
DelayFor18TCY( void ) //18 cycles delay with 8MHz clock { Delay10TCYx(20); } |
1 2 3 4 5 6 |
void DelayPORXLCD(void) // 15ms delay { Delay1KTCYx(30); // 15ms delay with 8MHz Clock //or Delay1KTCYx(15); // 15ms delay with 4MHz Clock } |
1 2 3 4 5 6 |
void DelayXLCD(void) // 5ms delay { Delay1KTCYx(10); // 5ms delay with 8MHz Clock //or Delay1KTCYx(5); // 5ms delay with 4MHz Clock } |
LCD Connection
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.
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
/* * File: main.c * www.studentcompanion.co.za * Interfacing LCD Display with PIC microcontroller * Created on August 26, 2019, 2:49 AM * Compiler XC8 v1.34 * MPLAB X IDE v5.25 */ #include "Configuration.c" #include <stdio.h> #include <stdlib.h> #include <delays.h> void init_XLCD(void); //Initialize LCD display void DelayFor18TCY( void ); //18 cycles delay void DelayPORXLCD (void); // Delay of 15ms void DelayXLCD (void); // Delay of 5ms void main(void) { OSCCON = 0x76; // Configure to use 8MHz internal oscillator init_XLCD(); //Call the Initialize LCD display function putrsXLCD("LCD Display"); //Display "LCD display" SetDDRamAddr(0x40); //shift cursor to beginning of second line putrsXLCD("StudentCompanion"); //Display "StudentCompanion" while(1) { } } void init_XLCD(void) //Initialize LCD display { OpenXLCD(FOUR_BIT&LINES_5X7); //configure LCD in 4-bit Data Interface mode //and 5x7 characters, multiple line display while(BusyXLCD()); //Check if the LCD controller is not busy //before writing some commands? WriteCmdXLCD(0x06); // move cursor right, don?t shift display WriteCmdXLCD(0x0C); //turn display on without cursor } void DelayFor18TCY( void ) //18 cycles delay { Delay10TCYx(20); } void DelayPORXLCD (void) // Delay of 15ms { Delay1KTCYx(30); } void DelayXLCD (void) // Delay of 5ms { Delay1KTCYx(10); } |
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: PIC18F26K20
Download: LCD MPLAB Project with MPLAB Code Configurator
Download: LCD PIC18F26K20 Proteus Project
Download LCD Example with PIC18F Peripheral Libraries: PIC18F2620
Download MPLAB X Project: LCD-Plib
Download Proteus Schematic Project: LCD Interface Proteus