This article is a continuation of the series of tutorials on the PIC16F877A Microcontroller. The aim of this series is to provide easy and practical examples that anyone can understand. In the previous LCD tutorial, we have used that LCD in 8-bit mode. But here we will see LCD 4-bit interfacing with PIC16F877A Microcontroller.
LCD 4 bit interfacing with PIC16F877A
Introduction
8-bit mode – Using 8 data lines in LCD (totally 8 data lines are there)
4-bit mode – Using only 4 data lines in the LCD module
8-bit mode is already working and that looks awesome. Then why we are going to 4-bit mode? This is the question that comes to mind whenever I said 4-bit mode. Yeah, that 8-bit mode is nice. But but but… Just assume. I’m doing one project which requires more number of hardware. But PIC16F877A has only 33 GPIOs. So in that time I can use this 4-bit mode and reduce the pin required for the LCD module. Am I right? Great. That’s why 4-bit mode also important. Already we know the LED’s operation. If we want to enable 4-bit mode we have to do small modifications in the normal method. Let’s see that.
In initializing time we have to give 0x28 command. That’s all.
LCD Initializing
void lcd_init() { cmd(0x02); cmd(0x28); cmd(0x0e); cmd(0x06); cmd(0x80); }
Sending command
Here everything is the same except the way of data writing. Here we have only 4 bits. So we need to send nibble by nibble. So first we need to send first nibble then followed by the second. See that code. I’m writing into Port B’s last 4 bits. Because the last 4 bits are connected to LCD.
void cmd(unsigned char a) { rs=0; PORTB&=0x0F; PORTB|=(a&0xf0); en=1; lcd_delay(); en=0; lcd_delay(); PORTB&=0x0f; PORTB|=(a<<4&0xf0); en=1; lcd_delay(); en=0; lcd_delay(); }
Sending Data
Same as sending the command.
void dat(unsigned char b) { rs=1; PORTB&=0x0F; PORTB|=(b&0xf0); en=1; lcd_delay(); en=0; lcd_delay(); PORTB&=0x0f; PORTB|=(b<<4&0xf0); en=1; lcd_delay(); en=0; lcd_delay(); }
Circuit Diagram
Code
#include <pic.h> __CONFIG( FOSC_HS & WDTE_OFF & PWRTE_OFF & CP_OFF & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF); #define rs RD2 #define en RD3 void lcd_init(); void cmd(unsigned char a); void dat(unsigned char b); void show(unsigned char *s); void lcd_delay(); void main() { unsigned int i; TRISB=TRISD2=TRISD3=0; lcd_init(); cmd(0x90); show("www.EmbeTronicX.com"); while(1) { for(i=0;i<15000;i++); cmd(0x18); for(i=0;i<15000;i++); } } void lcd_init() { cmd(0x02); cmd(0x28); cmd(0x0e); cmd(0x06); cmd(0x80); } void cmd(unsigned char a) { rs=0; PORTB&=0x0F; PORTB|=(a&0xf0); en=1; lcd_delay(); en=0; lcd_delay(); PORTB&=0x0f; PORTB|=(a<<4&0xf0); en=1; lcd_delay(); en=0; lcd_delay(); } void dat(unsigned char b) { rs=1; PORTB&=0x0F; PORTB|=(b&0xf0); en=1; lcd_delay(); en=0; lcd_delay(); PORTB&=0x0f; PORTB|=(b<<4&0xf0); en=1; lcd_delay(); en=0; lcd_delay(); } void show(unsigned char *s) { while(*s) { dat(*s++); } } void lcd_delay() { unsigned int lcd_delay; for(lcd_delay=0;lcd_delay<=1000;lcd_delay++); }
Output
[ Please find the output image Here ]
Hope you learned something from this. You can download the whole project here.
In our next tutorial, we will see how to interface the DC motor with PIC16F877A.
You can also read the below tutorials.

Embedded Software | Firmware | Linux Devic Deriver | RTOS
Hi, I’m SLR. I am a tech blogger and an Embedded Engineer. I am always eager to learn and explore tech-related concepts. And also, I wanted to share my knowledge with everyone in a more straightforward way with easy practical examples. I strongly believe that learning by doing is more powerful than just learning by reading. I love to do experiments. If you want to help or support me on my journey, consider sharing my articles, or Buy me a Coffee! Thank you for reading my blog! Happy learning!