Custom Characters on LCD using PIC – MPLAB XC8
Contents
I hope that you already go through our tutorial, Interfacing LCD with PIC Microcontroller – MPLAB XC8. HD44780 compatible controllers used in these LCDs allows us to define 8 custom characters in addition to the standard pre-programmed characters. In this tutorial we will learn, how to create custom characters on LCD using PIC Microcontroller and MPLAB XC8 compiler.
DDRAM, CGROM and CGRAM
CGROM – Character Generator ROM
This is the memory which holds 5×8 or 5×10 dot patterns of predefined characters in the LCD. It can generate 208 5×8 dot character patterns and 32 5×10 dot character patterns.
DDRAM – Display Data RAM
This is the memory which holds the character data which is currently displayed on the LCD screen. Its capacity is 80×8 bits, ie 80 characters.
CGRAM – Character Generator RAM
This memory works similar to CGROM but as this is a RAM we can modify its data any time. So we can store our custom character patterns in this memory through program. We can store up to eight 5×8 character dot patterns or four 5×10 character dot patterns in this memory.
Character Generation
Characters are displayed on the LCD using 5×8 or 5×10 dot matrix. Most of the commonly available displays uses 5×8 dot matrix. We can simply create a custom character by defining each pixel in the dot matrix. Here is an example of creating Ω symbol on 5×8 dot matrix.

MPLAB XC8 Code
Note that the following program uses our MPLAB XC8 LCD Library and you should include the header file “lcd.h” to your project directory.
#define _XTAL_FREQ 8000000
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
#include <xc.h>
#include <stdio.h>
#include "lcd.h";
// BEGIN CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
//END CONFIG
const unsigned short MyChar5x8[] = {
0x00, 0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00, // Code for char num #0
0x0E, 0x1B, 0x11, 0x11, 0x11, 0x11, 0x1F, 0x00, // Code for char num #1
0x0E, 0x1B, 0x11, 0x11, 0x11, 0x1F, 0x1F, 0x00, // Code for char num #2
0x0E, 0x1B, 0x11, 0x11, 0x1F, 0x1F, 0x1F, 0x00, // Code for char num #3
0x0E, 0x1B, 0x11, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, // Code for char num #4
0x0E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, // Code for char num #5
0x00, 0x04, 0x02, 0x1F, 0x02, 0x04, 0x00, 0x00, // Code for char num #6
0x00, 0x00, 0x0E, 0x11, 0x11, 0x0A, 0x1B, 0x00 // Code for char num #7
};
void InitCustomChars()
{
char i;
Lcd_Cmd(0x04); // Set CGRAM Address
Lcd_Cmd(0x00); // .. set CGRAM Address
for (i = 0; i <= 63 ; i++)
Lcd_Write_Char(MyChar5x8[i]);
Lcd_Cmd(0); // Return to Home
Lcd_Cmd(2); // .. return to Home
}
int main()
{
TRISD = 0x00; // PORTD as Output
Lcd_Init();
InitCustomChars(); // Write custom characters to LCD memory
while(1)
{
Lcd_Clear();
Lcd_Set_Cursor(1,1);
Lcd_Write_Char(0); // Display Custom Character 0
Lcd_Write_Char(1); // Display Custom Character 1
Lcd_Write_Char(2); // Display Custom Character 2
Lcd_Write_Char(3); // Display Custom Character 3
Lcd_Write_Char(4); // Display Custom Character 4
Lcd_Write_Char(5); // Display Custom Character 5
Lcd_Write_Char(6); // Display Custom Character 6
Lcd_Write_Char(7); // Display Custom Character 7
__delay_ms(1000);
}
return 0;
}
Hope you can understand the working of the program from above comments. Please comment below if you have any doubts.
Circuit Diagram

Output

Download Here

Hi Ligo, I really enjoy your projects and how you explain the workings of it !!!
I’m new to C programming and is still busy getting the grips of it. I used to program in assembly but knew
some or other time I will have to learn this language.Thank you once again for making the learning so easy.
Thanks
Jonathan
Hi, very good guide, may I ask for pure sine wave system guide please.
Thank you, you saved my life!
Hello,
Who told to use 49 ? 63 is the correct value.
Dear Ligo, i tried to display 8 custom characters using a 20 x 4 lcd but the 7th and 8th custom character didn’t appear the way they were supposed to , so i took another look at this tutorial and used ” i <= 63 " in the for loop like you used and it worked perfectly. Please could explain how the " i <=63 " affects the display.THANK YOU. PS i used " i <= 49" in the first code.
Please read the article : https://electrosome.com/lcd-pic-mplab-xc8/ and the datasheet of HD44780 controller used in the LCD.
Dear Ligo
Could you please explain more about function Lcd_cmd();.I don’t understand how to set adress CGRAM.
Why we set Lcd_cmd(0x04) and Lcd_cmd(0x00);.
Thank you