Friday , January 20 2017
Home / Embedded Systems / Programming LCD in 8 bit mode – Part -2

Programming LCD in 8 bit mode – Part -2

This post documents the steps involved in interfacing the LCD in 8 bit mode with a microcontroller. It belongs to a series of 4 posts. If you landed here straight from a search engine here is an index to help you navigate.

  1. LCD Module Basic Theory. (LCD Controllers, CG&DD RAM, PIN description,Timing Diagram, Commands)
  2. Programming LCDs in 8 bit mode. (programming pic18f4520 in C with C18 compiler under 8 bit mode)
  3. Programming LCDs in 4 bit mode. (programming pic18f4520 in C with C18 compiler under 4 bit mode)
  4. Creating Custom Characters (bit map symbols and arrows that are not usually present in the ASCII table)

Subscribe to our latest posts and newsletters with you email and get notifications on the above post as soon as they are published!

Why Reinvent the wheel?

There are a lot of libraries that are freely available in the internet and most of the compilers themselves have a library for these LCD modules. But the reason I’m re-inventing the wheel is that, becoming too dependent on existing libraries is not a good practice and can prove to be fatal at times. You will soon realize that it will take you no further in this domain.

Using existing  libraries for fonts , FAT and other complex and time consuming applications is understandable but for an application as simple as the character LCD, I would rather write my own library than spending time reading and understanding some one else’s program.

We will first list a set of functions that we will be using to interface the LCD module and then wrap it up into a nice header file that can be included in your program’s main file. It is good practice to use separate C files for each module that you interface so that combining two such module would be easy in the long run.

What do we need?

Most of the time we do not appreciate what is around us like the printf statement  in C. It makes life so simple by taking care of printing data to the screen. So for working comfortably with LCD we will have to have functions to take care of the following tasks,

  • Write one character at a time.
  • Give commands to the module.
  • Read busy the busy flag.
  • Write a string sequentially.

The 8 bit mode of operation of the LCD is relatively faster and simpler than the 4 bit mode. Here as the name suggests, 8 parallel data lines are needed to write data and commands to the LCD module. The source code is written in embedded C and compiled using the C18 compiler from microchip. The code below is successfully compiled without any warnings or errors using the Mplab X IDE and Mplab 8.85

Code Macros:

Before writing the code we have to decide on the pins that we are going to use for use for the interface. Once this is done, we have to put them to use by setting code macros with #define. In C the macros are just shortcuts. If you write #define HIGH 1 Where ever the compiler compiler encounters an instance of HIGH it will consider it as 1. This can be really helpful in providing more readability and portability for you code which you will see by the end of this post.

Use as many macros as you want for all the constants and IO pins. Once all the constant mapped on to a label using the macros, you can start using them in you code.

Write data to LCD

Function Name: LCD_data
Parameters: 8 bit data
Return: None
Description: This function is used to write a 8 bit parallel data into the DD RAM of the LCD at the memory location last pointed to my the AC. Before writing any data the line address or the position address has to be given using the LCD_cmd() function.

Send a command

Function Name: LCD_cmd
Parameters: 8 bit command
Return: None
Description: This function is used to send data to the command register. It can be an internal LCD command or a DD RAM address but commands should be framed properly form the command sheet.

Read busy flag

Function Name: LCD_isbusy
Parameters: None
Return: None
Description: This function is used to check for the busy flag (DB7). The LCD cannot do any operations as long as it is busy. So this function never terminates as long as the LCD is busy (it gets stuck in an infinite loop).

Write a string to LCD

Function Name: LCD_string
Parameters: Character pointer.
Return: None
Description: This function take the address of the first character of the string that you wish to write to the LCD as a parameter and then sequentially calls the LCD_data() function each time with the next successive character of the string. So this is nothing but an automated version of the sequential call to the LCD_data() function. It takes away a lot of headache when trying to print length messages.

Source File lcd.c

Now all that is remaining is to collect all the functions above and put then in a single C source file and include necessary header files and we are good to go. This is how you final C source file should look like. Use the small icon below the source code to copy the code with proper formatting.

Header File lcd.h

With the source file lcd.c ready you will need a means to allow you main C file (one which has the main() function) to access the function in the source file. For doing this you can either extern all the junction in the source file or have a .h file to bridge them together. The first method is a little messy so lets do the latter one. Create a file called lcd.h and add the following code,


In both the above cases, the files lcd.c and lcd.h has to be in the same directory as the main file. If you plan to rename the files, you have to change these lines in lcd.h correspondingly.

#ifndef LCD_H #define LCD_H

Using these functions in you code:

Now that you have the source and header files ready, you can incorporate the functions in you code as shown in this code. This is the program that I wrote for making the video above. It does not demonstrate the use if all the functions but I think with this code you can start the experimenting for yourself.

Related Downloads:

Here is the Mplab X project folder in which the above program has been successfully compiled to get the HEX file for the above description

[sociallocker] [/sociallocker]

My next post will discuss the programming LCD in 4 bit mode.

About Siddharth

Siddharth is a Firmware Engineer, techie, and a movie-buff. His interests include, Programming, Embedded Systems, Linux, Robotics, CV, Carpentry and a lot more. At times, you could see some of his sunday projects converge on release quality. You get to know him on the following social channels.

Check Also


Interfacing 16×2 LCD with C2000 launchpad

  The C2000 Launchpad is an inexpensive evaluation module based on Piccolo family microcontrollers from …

  • ganesh

    MPLAB project files are missing

    • Hi Ganesh,
      The links has been updated to dropbox. It was some security plugin that was blocking you from downloading the files.

  • Ok, for this lines of code, 80 means column 1 row 1. So about the DD RAM address, what is the actually ?


    • As I said, The LCD has DD RAM locations that are directly linked to the display offset. Those C macros are use to define the starting address of each line in the display. So 0xC0 will be second row column 1 and 0xC1 will be second row column 2 and so on. Read this post for more details.

  • Pingback: Make a Digital Clock with DS1307 and PIC18F4520 - Embed Journal()

  • fsmoke

    void LCD_init(void){

    You talking about 8bit mode – but use MODE_4BIT define – why? It’s mistake?

    • Yes, it was a mistake and thanks for spotting it. I have updated the post with the correction. Sorry for the inconvenience.

  • Roger

    Hello, I have a problem to write a text on the lcd.

    I used this code for a 4-line LCD ( and a PICDEM™ PIC18 Explorer
    Demonstration Board.

    It does not display any message, my frequency is 10Mhz, maybe the timing is not good?
    Can you help me please?

    • I’m almost sure that the problem is due to the mismatch in timing. This code was tested with a 20Mhz crystal. If you change the frequency then you will have to read the datasheet and figure out the timing delay.

  • Rafael Sanchez Souza

    Hello Siddarth!

    Congrats for the article, it’s very clear! (And thanks, obviously)

    So, I’m trying to understand how LCD works to use it as an interface for an equipment which will automate temperature steps: you set time and temperature and water will get hot.

    1. I found many references to this HD44780. What is it exactly? You didn’t mention this in your post. Is it because you exchanged the HD44780 for the PIC or is it integrated with your 20×4 LCD?

    2. Do you have any other idea of an simple and efficient interface? I’m thinking about maybe an app for Android


  • Sathish

    Hi Siddharth,

    There is no output in this code, if I will make change in the void LCD_isbusy(void) means working, what is the problem ?

    void LCD_isbusy(void)
    TRISBbits.TRISB7=1; // Make D7 as input
    RS = LOW;
    RW = HIGH;
    EN = LOW; // This is the change I made
    TRISBbits.TRISB7=0; // Back to Output
    EN = LOW;

    I tested the code using proteus, Please reply me thanks in advance !

    • Hi Sathish,

      I have tested this very well and it was working flawlessly. I am not sure how proteus interprets it but I am sure, it cannot be 100% accurate. You should test it on a real LCD. I mean, what use the EN=LOW; twice do? you might as well comment both out and see. I think its a bug in proteus.

  • Bob

    Hello Siddharth

    Thank you for the article, it is very helpful. Can you please post a complete pin to pin mapping in 8 and 4 bit mode? It is not clear to me how to exactly connect the PIC to the LCD.

    Thank you

  • Pawel Cuper

    I’ve been trying to understand this for 2 nights now.
    Code won’t work. It just won’t.
    I don’t know how to add it in. When I opened your project it gave me errors about the text sent to the LCD.

    “main.c:79: warning: (358) illegal conversion of pointer to integer”. All the lines with “LCD_String(xxxxx)” are underlined and won’t let me build the code.

    What is dataport LATD?
    My LCD does not have such a port. Only RW, RS, E and D0-D7.

    • Tom

      I’m having the same issue as well.

    • Tom

      LATD is latch port D on his micro-controller. He has that connected to D0-D7 on the LCD.

    • Tom

      I got it to compile by changing:
      void LCD_string(const rom char *buffer)
      void LCD_string(const char *buffer)

      • Hey sorry for the delay. It been a long time since I wrote that code. So the compiler version must have changed. I am glad you were able to fix that issue.

        The dataport LATD port of the microcontroller that is connected to the LCD data pins D0 to D7.

Keep in touch with the current trends!
Did you like this article? Sign up and get our latest posts delivered to your inbox!
  We hate spam and never share your details.