Interfacing LCD with PIC Microcontroller – Hi Tech C

Interfacing LCD with PIC Microcontroller – Hi Tech C

Contents

16×2 Character LCD is a very basic LCD module which is commonly used in electronics projects and products. It contains 2 rows that can display 16 characters. Each character is displayed using 5×8 or 5×10 dot matrix. It can be easily interfaced with a microcontroller. In this tutorial we will see how to write data to an LCD with PIC Microcontroller using Hi-Tech C Compiler. Hi-Tech C has no built in LCD libraries so we require the hardware knowledge of LCD to control it. Commonly used LCD Displays uses HD44780 compliant controllers.

16x2 LCD Pin Diagram
16×2 LCD Pin Diagram

This is the pin diagram of a 16×2 Character LCD display. As in all devices it also has two inputs to give power Vcc and GND. Voltage at VEE determines the Contrast of the display. A 10K potentiometer whose fixed ends are connected to Vcc, GND and variable end is connected to VEE can be used to adjust contrast. A microcontroller needs to send two informations to operate this LCD module, Data and Commands. Data represents the ASCII value (8 bits) of the character to be displayed and Command determines the other operations of LCD such as position to be displayed. Data and Commands are send through the same data lines, which are multiplexed using the RS (Register Select) input of LCD. When it is HIGH, LCD takes it as data to be displayed and when it is LOW, LCD takes it as a command. Data Strobe is given using E (Enable) input of the LCD. When the E (Enable) is HIGH, LCD takes it as valid data or command. The input signal R/W (Read or Write) determines whether data is written to or read from the LCD. In normal cases we need only writing hence it is tied to GROUND in circuits shown below.

The interface between this LCD and Microcontroller can be 8 bit or 4 bit and the difference between them is in how the data or commands are send to LCD. In the 8 bit mode, 8 bit data and commands are send through the data lines DB0 – DB7 and data strobe is given through E input of the LCD. But 4 bit mode uses only 4 data lines. In this 8 bit data and commands are splitted into 2 parts (4 bits each) and are sent sequentially through data lines DB4 – DB7 with its own data strobe through E input. The idea of 4 bit communication is introduced to save pins of a microcontroller. You may think that 4 bit mode will be slower than 8 bit. But the speed difference is only minimal. As LCDs are slow speed devices, the tiny speed difference between these modes is not significant. Just remember that microcontroller is operating at high speed in the range of MHz and we are viewing LCD with our eyes. Due to Persistence of Vision of our eyes we will not even feel the speed difference.

Hope that you got rough idea about how this LCD Module works. Actually you need to read the datasheet of HD44780 LCD driver used in this LCD Module to write a Hi-Tech C program for PIC. But we solved this problem by creating a header file lcd.h which includes all the commonly used functions. Just include it and enjoy.


Functions in lcd.h

Lcd8_Init() & Lcd4_Init() : These functions will initialize the LCD Module connected to the following defined pins in 8 bit and 4 bit mode respectively.

8 Bit Mode :

#define RS RB6
#define EN RB7
#define D0 RC0
#define D1 RC1
#define D2 RC2
#define D3 RC3
#define D4 RC4
#define D5 RC5
#define D6 RC6
#define D7 RC7

4 Bit Mode :

#define RS RB2
#define EN RB3
#define D4 RB4
#define D5 RB5
#define D6 RB6
#define D7 RB7

These connections must be defined for the working of LCD library.

Lcd8_Clear() & Lcd4_Clear() : Calling these functions will clear the LCD Display when interfaced in 8 Bit and 4 Bit mode respectively.

Lcd8_Set_Cursor() & Lcd4_Set_Cursor() : These functions set the row and column of the cursor on the LCD Screen. By using this we can change the position of the character being displayed by the following functions.

Lcd8_Write_Char() & Lcd4_Write_Char() : These functions will write a character to the LCD Screen when interfaced through 8 Bit and 4 Bit mode respectively.

Lcd8_Write_String() & Lcd4_Write_String() : These functions are used to write strings to the LCD Screen.

Lcd8_Shift_Left() & Lcd4_Shift_Left() : These functions are used to shift the content on the LCD Display left without changing the data in the display RAM.

Lcd8_Shift_Right() & Lcd4_Shift_Right() : Similar to above functions, these are used to shift the content on the LCD Display right without changing the data in the display RAM.

8 Bit Mode

Circuit Diagram

Interfacing LCD with PIC Microcontroller - 8 Bit Mode
Interfacing LCD with PIC Microcontroller – 8 Bit Mode

Hi-Tech C Code

#include<htc.h>
#include<pic.h>

#define RS RB6
#define EN RB7
#define D0 RC0
#define D1 RC1
#define D2 RC2
#define D3 RC3
#define D4 RC4
#define D5 RC5
#define D6 RC6
#define D7 RC7

#define _XTAL_FREQ 8000000

#include "lcd.h"

void main()
{
  int i;
  TRISB = 0x00;
  TRISC = 0x00;
  Lcd8_Init();
  while(1)
  {
    Lcd8_Set_Cursor(1,1);
    Lcd8_Write_String("electroSome LCD Hello World");
    for(i=0;i<15;i++)
    {
      __delay_ms(1000);
      Lcd8_Shift_Left();
    }
    for(i=0;i<15;i++)
    {
      __delay_ms(1000);
      Lcd8_Shift_Right();
    }
    Lcd8_Clear();
    Lcd8_Set_Cursor(2,1);
    Lcd8_Write_Char('e');
    Lcd8_Write_Char('S');
    __delay_ms(2000);
  }
}

4 Bit Mode

Circuit Diagram

Interfacing LCD with PIC Microcontroller - 4 Bit Mode
Interfacing LCD with PIC Microcontroller – 4 Bit Mode

Hi-Tech C Code

#include<htc.h>
#include<pic.h>

#define RS RB2
#define EN RB3
#define D4 RB4
#define D5 RB5
#define D6 RB6
#define D7 RB7
#define _XTAL_FREQ 8000000
#include "lcd.h"

void main()
{
  int i;
  TRISB = 0x00;
  Lcd4_Init();
  while(1)
  {
    Lcd4_Set_Cursor(1,1);
    Lcd4_Write_String("electroSome LCD Hello World");
    for(i=0;i<15;i++)
    {
      __delay_ms(1000);
      Lcd4_Shift_Left();
    }
    for(i=0;i<15;i++)
    {
      __delay_ms(1000);
      Lcd4_Shift_Right();
    }
    Lcd4_Clear();
    Lcd4_Set_Cursor(2,1);
    Lcd4_Write_Char('e');
    Lcd4_Write_Char('S');
    __delay_ms(2000);
  }
}

Note : Don’t forget to add lcd.h to Header files before building.

Adding a Header File
Adding a Header File

You can download the header file lcd.h, Hi-Tech C and Proteus files here…

Interfacing LCD with PIC Microcontroller – Hi Tech C

Share this post

  • First of all, thank you for this tutorial.

    I tried it with PIC18F25K22 and I see only black rectangles.

    Does anybody have an idea?

    Thanks
    John

  • hi.
    i got the following error. could you please give me a solution.
    thanks.

  • I want to use C for coding and run multiple tasks at the same time. Here I hit the wall. In the code above, you use a function __delay_ms(xx) which stuck the controller for xx mS. Something I realty don’t want. I want to set a time delay and pursue other tasks. Later when the processor is free I will check if the delay expired. If it is, move ahead, set a new delay, set a pointer where I am with this particular task and get out to the next check. Please give me some suggestions or links how to move from mono- to “multi-task” with PIC

  • hello sir,i have used your code of lcd but the header file lcd.h gives error, can you please suggest me the solution

  • build fine, placed in proteus fine lighting up i can see E pin and data pins getting power but not seeing any letter ???? and no idea how to debug

  • Hello If I want to add an LCD display like this one to my PIC18f4455.
    The steps are the same or they differ from your PIC?I want to do this
    for a project at my univeristy. This is the schematic of my pic

  • Hello If I want to add an LCD display like this one to my PIC18f4455. The steps are the same or they differ from your PIC?I want to do this for a project at my univeristy.

  • Hi Ligo,
    Could you please briefly explain the function of the header file as well?
    Like each subroutine and its action in one or two line.
    -Thanks

  • HELLO MY LCD IS NOT DISPLAYING PRACTICALLY. DONT KNOW WHY. PLEASE NEED HELP AS CONCERNING CONNECTION

  • sir,
    How to put a degree symbol in lcd using PIC16F877a. I am using MPlab IDE.

  • Great Article. Unfortunately, I found this article too late – I already found the answer on another service. I just filled out a form with an online software. It looked much better typed than hand-written. I used http://goo.gl/OeiYxJand it’s very easy to use.

  • hello, thanks for the information. The above code works well on my board. Will it be possible for you to share hi-tech compiler c code for lcd.h ?? thanks

  • create a program that makes the LEDs light up in the order D5, D5, D7, D1, D4, D2, D4, and then repeats this sequence continuously.

    Each LED should be ON for a period of approximately 0.5 second before turning OFF for the next 0.5 second so that they are clearly visible. Then the next LED in the sequence takes over.

  • Please use our forums ( https://electrosome.com/forums ) for technical support not directly related to above tutorial.
    Note : forums are for technical support only. We can’t freely develop projects/programs for all those who contacts us. We will provide free technical support only. If you need us to develop your project / code. Please hire one of our engineers. It will help us to survive.

  • my project is anti-theft vehicle security.we want attaching keypad to enter the password.if it is not correct(3 trials),the message is send to owner through gsm, simultaneosly the door will be locked until the owner to open the car by using original key.what we do?,plz help me,,,and provide a code for it.we use pic18f4580 with mplabide

  • sir i need to know the c code of programming pic16f690 with lcd and adc module

  • Hi for everyone,

    I’d like to remark, I just a beginner in programming. I suppose, I found the problem for many person’s non-working project. Here on the website the source code seems OK, but the downloadable part isn’t. Why? See my attached picture. On left hand side you can see the website and next to them on right hand side is the downloaded source code. As you can see, the downloaded source code referring the port D4-D7 as data lines against of B4-B7. The schematic is OK, matching to the website source code.

    Next serious issue is the clock frequency. Here on the website is the right value, 8MHz (#define _XTAL_FREQ 8000000) and the downloaded has wrong, 20MHz (#define _XTAL_FREQ 20000000).

    I think is the best solution at the moment is build the project as schematic shows and copy the source code from here from the website, if you don’t want to type manually.

    I’ll be back soon after modifying the downloaded source code. I’ll try first the 4 bit mode.

  • I want to build a wireless temprature monitor using pic and xbee…….please guide me!

  • Hi,

    I am trying to interface a 16X2 LCD with PIC24FJ128GB202, and I am using the above code. i added the appropriate libraries in the program but unfortunately I am unable to define on which registers the pin corresponds i.e. all the #define RS RB2
    #define EN RB3
    #define D4 RB4
    #define D5 RB5
    #define D6 RB6
    #define D7 RB7

    are giving an error as : newmain.c:16:3: error: ‘D4’ undeclared (first use in this function)

    newmain.c:16:3: note: each undeclared identifier is reported only once for each function it appears in

    newmain.c:21:3: error: ‘D5’ undeclared (first use in this function)

    newmain.c:26:3: error: ‘D6’ undeclared (first use in this function)

    newmain.c:31:3: error: ‘D7’ undeclared (first use in this function)

    I am very confused, any help will appreciated.

  • Hi. I’m using MPLAB X with XC8 and when I try to build the project I get the following warning “check.c:63: warning: (359) illegal conversion between pointer types pointer to const unsigned char -> pointer to unsigned char” on all Lcd8_Write_String(“”) lines. Other than that, great code. Thanks.

  • Yes.
    But not working. to configure I used below conigure code
    __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_ON & BOREN_ON & CP_OFF & CPD_OFF & LVP_OFF & DEBUG_OFF);

  • Yes.
    But not working. to configure I used below conigure code __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_ON & BOREN_ON & CP_OFF & CPD_OFF & LVP_OFF & DEBUG_OFF);

    Best regards

    Kawser

  • I download this project.But Hardware does not work.I check again and again but do not find the fault.
    Thanks for your reply.

    Best regards
    Kawser

  • ur 8 Bit Interfacing code work fine on Proteus ,
    but 4 Bit Interfacing code not work on Proteus why ?

  • When I build the code I have this problem…”can’t open include file “lcd.h” : No such file or derectory..I had add the header..plz tell me hw can I fix this

  • Hello plz i would like to use LCD to iplay ‘helo world” but by using C in Mplab and C30 commpiler

  • Hello, thanks for this info.

    I am having a problem simulating this with Proteus i keep getting this error:

    “picc.exe
    –pass1 –errformat=”Error at file %%f line %%l column %%c: (%%n) %%s”
    –warnformat=”Warning at file %%f line %%l column %%c: (%%n) %%s”
    –msgformat=”Message at file %%f line %%l column %%c: (%%n) %%s”
    -D_XTAL_FREQ=1000000 -G –chip=16F877A -O”main.p1″ “../main.c”
    HI-TECH C Compiler for PIC10/12/16 MCUs (Lite Mode) V9.82
    Copyright (C) 2011 Microchip Technology Inc.
    (1273) Omniscient Code Generation not available in Lite mode (warning)
    Warning at file ../main.c line 22 column 26: (111) redefining preprocessor macro “_XTAL_FREQ” ((null): 0)
    Warning at file ../main.c line 31 column 1: (361) function declared implicit int
    Warning at file ../main.c line 34 column 1: (361) function declared implicit int
    Warning at file ../main.c line 35 column 1: (361) function declared implicit int
    Warning at file ../main.c line 39 column 1: (361) function declared implicit int
    Warning at file ../main.c line 44 column 1: (361) function declared implicit int
    Warning at file ../main.c line 46 column 1: (361) function declared implicit int
    Warning at file ../main.c line 48 column 1: (361) function declared implicit int
    picc.exe
    –output=mcof –errformat=”Error at file %%f line %%l column %%c: (%%n)
    %%s” –warnformat=”Warning at file %%f line %%l column %%c: (%%n) %%s”
    –msgformat=”Message at file %%f line %%l column %%c: (%%n) %%s” -G
    –chip=16F877A -O”Debug.cof” “main.p1” “lcd.p1″
    HI-TECH C Compiler for PIC10/12/16 MCUs (Lite Mode) V9.82
    Copyright (C) 2011 Microchip Technology Inc.
    (1273) Omniscient Code Generation not available in Lite mode (warning)
    Error at file line 0 column : (500) undefined symbols:

    _Lcd8_Write_Char(Debug.obj) _Lcd8_Write_String(Debug.obj)
    _Lcd8_Init(Debug.obj) _Lcd8_Clear(Debug.obj) _Lcd8_Shift_Left(Debug.obj)
    _Lcd8_Set_Cursor(Debug.obj) _Lcd8_Shift_Right(Debug.obj)
    make: *** [Debug.cof] Error 1

    Error code 2”

    I used same code for the 8bit mode and i use same circuit with it . please tell me what to do.

    Many Thanks
    Nwafor Austine

  • Hello, thanks for this info.

    I am having a problem simulating this with Proteus i keep getting this error:

    “picc.exe –pass1 –errformat=”Error at file %%f line %%l column %%c: (%%n) %%s” –warnformat=”Warning at file %%f line %%l column %%c: (%%n) %%s” –msgformat=”Message at file %%f line %%l column %%c: (%%n) %%s” -D_XTAL_FREQ=1000000 -G –chip=16F877A -O”main.p1″ “../main.c”
    HI-TECH C Compiler for PIC10/12/16 MCUs (Lite Mode) V9.82
    Copyright (C) 2011 Microchip Technology Inc.
    (1273) Omniscient Code Generation not available in Lite mode (warning)
    Warning at file ../main.c line 22 column 26: (111) redefining preprocessor macro “_XTAL_FREQ” ((null): 0)
    Warning at file ../main.c line 31 column 1: (361) function declared implicit int
    Warning at file ../main.c line 34 column 1: (361) function declared implicit int
    Warning at file ../main.c line 35 column 1: (361) function declared implicit int
    Warning at file ../main.c line 39 column 1: (361) function declared implicit int
    Warning at file ../main.c line 44 column 1: (361) function declared implicit int
    Warning at file ../main.c line 46 column 1: (361) function declared implicit int
    Warning at file ../main.c line 48 column 1: (361) function declared implicit int
    picc.exe –output=mcof –errformat=”Error at file %%f line %%l column %%c: (%%n) %%s” –warnformat=”Warning at file %%f line %%l column %%c: (%%n) %%s” –msgformat=”Message at file %%f line %%l column %%c: (%%n) %%s” -G –chip=16F877A -O”Debug.cof” “main.p1” “lcd.p1″
    HI-TECH C Compiler for PIC10/12/16 MCUs (Lite Mode) V9.82
    Copyright (C) 2011 Microchip Technology Inc.
    (1273) Omniscient Code Generation not available in Lite mode (warning)
    Error at file line 0 column : (500) undefined symbols:
    _Lcd8_Write_Char(Debug.obj) _Lcd8_Write_String(Debug.obj) _Lcd8_Init(Debug.obj) _Lcd8_Clear(Debug.obj) _Lcd8_Shift_Left(Debug.obj) _Lcd8_Set_Cursor(Debug.obj) _Lcd8_Shift_Right(Debug.obj)
    make: *** [Debug.cof] Error 1

    Error code 2”

    I used same code for the 8bit mode and i use same circuit with it . please tell me what to do.

    Many Thanks
    Nwafor Austine

  • Hey, Thank you so much for sharing this! I do have a question though, can you display the value of a variable via LCD?

    For example if I define counter as a variable and change it through out my code based on the user’s input, can I display the value of ‘counter’ directly with the LCD? (Of course, I can always try to find what the counter is and send the numbers one at a time, but that seems like a very inefficient way to do it & it’s not always easy to determine what the numbers will be)

  • Hi,
    I have PICDEMâ„¢ 2 Plus Demonstration board and use PIC16F1937. I use your code and did change the output port to associate the board layout, but I always receive first line black box, I don’t understaqnd what;s going on, can you help me for this?
    Thanks

  • hi..i got two inputs from the led..and output as lcd display..if the 1st led lights up,the lcd will display ‘in’ and 2nd led lights up,lcd will display ‘out’,if both led lights up at the same time the lcd will show blank display n every displayed result will be reset after 10 seconds..im using PIC16F877.

    this is the coding for lcd display

    // LCD module connections

    sbit LCD_RS at RB4_bit;

    sbit LCD_EN at RB5_bit;

    sbit LCD_D4 at RB0_bit;

    sbit LCD_D5 at RB1_bit;

    sbit LCD_D6 at RB2_bit;

    sbit LCD_D7 at RB3_bit;

    sbit LCD_RS_Direction at TRISB4_bit;

    sbit LCD_EN_Direction at TRISB5_bit;

    sbit LCD_D4_Direction at TRISB0_bit;

    sbit LCD_D5_Direction at TRISB1_bit;

    sbit LCD_D6_Direction at TRISB2_bit;

    sbit LCD_D7_Direction at TRISB3_bit;

    // End LCD module connections

    void main() {

    TRISB = 0x00;

    PORTB = 0x00;

    Delay_ms(500);

    LCD_Init();

    LCD_Cmd(_LCD_CURSOR_OFF);

    LCD_Cmd(_LCD_CLEAR);

    LCD_Out(1,1,”Smart Badminton”);

    LCD_Out(2,2,”Line Call”);

    while(1){

    Delay_ms(3000);

    LCD_Out(1,1,”In”);

    Delay_ms(3000);

    LCD_Out(1,1,”Out”);

    Delay_ms(3000);

    LCD_Cmd(_LCD_CLEAR);

    }

    }

    i dont know how to do the coding for the led as the input in order to display the output as in,out,blank display and reset after 10 seconds after the result displayed..any idea??thank you..

  • could you help me with this? is this compatible for pic16f877a?

    Define LOADER_USED 1

    Define OSC 4 ‘ Core is running at 4MHz

    ‘ Define LCD registers and bits

    Define LCD_DREG PORTB

    Define LCD_DBIT 0

    Define LCD_RSREG PORTB

    Define LCD_RSBIT 4

    Define LCD_EREG PORTB

    Define LCD_EBIT 5

    ‘ Define ADCIN parameters

    DEFINE ADC_BITS 10 ‘ Set number of bits in result

    DEFINE ADC_CLOCK 3 ‘ Set clock source (3=rc)

    DEFINE ADC_SAMPLEUS 50 ‘ Set sampling time in uS

    LED var PORTB.7

    Relay var PORTD.0

    SW1 var PORTE.0

    SW2 Var PORTE.1

    ‘ —–[ Constants ]——————————————————-

    LcdCmd con $FE

    LcdLine1 con $80

    LcdLine2 con $C0

    ‘ Declare variables

    i var byte

    adVal var word

    lmTemp var word

    targetTemp var byte

    TRISA = %11111111 ‘ Set PORTA to all input

    ADCON1 = %10000010 ‘ Set PORTA analog and right justify result

    Pause 100 ‘ Wait for LCD to start up

    read 0, targetTemp ‘READ FROM PIC EPROM ADDRESS 0

    low led

    low relay

    Lcdout lcdcmd, 1

    MainLoop:

    toggle led

    ADCIN 0, adval ‘ANALOG VALUE FROM LM35

    lmtemp = adval * 500 ‘CONVERT DIGITAL VALUE TO DECIMAL

    lmtemp = lmtemp / 1024

    Lcdout lcdcmd, lcdline1, “LM35:”, dec2 lmtemp,223, “C” ‘223 = SIMBOL 0 BG C

    Lcdout lcdcmd, lcdline2, “TARGET: “, dec2 targettemp,223,”C”

    if sw1 = 0 then ‘SUIS -1

    while sw1 = 0

    wend

    if targettemp > 0 then

    targettemp = targettemp – 1

    else

    targettemp = 99

    endif

    write 0, targettemp

    endif

    if sw2 = 0 then ‘SUIS +1

    while sw2 = 0

    wend

    if targettemp < 99 then

    targettemp = targettemp + 1

    else

    targettemp = 0

    endif

    write 0, targettemp

    endif

    if lmtemp < targettemp then 'IF MORE THAN TARGET THEN

    high relay 'ON RELAY

    Lcdout lcdcmd, lcdline2+13,"ON "

    else

    low relay 'OFF RELAY

    Lcdout lcdcmd, lcdline2+13,"OFF"

    endif

    pause 250

    Goto mainloop ' Do it forever

    End

    *** please help me :(((

  • Hai, this is similar with what I wrote for my program using LCD 16×2. However, after compiled, it said to be undefined identifier “RB4”.. why is that so? Please help me. Thank you.

  • I need to use lcd8_out function and i need header file for that.Can anyone help me asap?

  • It is not a good logic… it executing following functions in a loop..
    1. Read data from keypad
    2. Display it in LCD
    The data read from keypad is already known to microcontroller .. so no need to read again it from LCD…

  • I have seen a pic lock project that reads the user entered password directly from lcd.
    ie, it ask the user for enter the password, then a loop reads the button presses and display the charactor on the lcd, then it reads the whole string from lcd. they didn’t provide the code.

  • An integer can be displayed …. digit by digit.. means character by character…
    if ‘a’ is a single digit number… ie (0,1,2,3…. 9)..
    it can be displayed by..
    Lcd8_Write_Char(a+48); // in 8 bit mode
    or
    Lcd4_Write_Char(a+48); // in 4 bit mode…
    Where 48 is the ASCII value of zero (0)…

  • FANTASTIC!!
    Very good tutorial! You are the best! Ever!

    Please, keep up this good work with Hi-Tech C.


  • >