Pages Menu
TwitterRssFacebook
Categories Menu

Posted by on Jun 16, 2011 in Atmel AVR, Microcontrollers | 210 comments

LCD Interfacing with AVR

LCD Interfacing with AVR

AVR SeriesIn this post, we will learn something cool! Something visual! Something like displaying your name in an LCD and then making it roll over, bounce over, etc etc etc ;)

So basically I am re-posting this tutorial, but in a different manner. I hope it will be useful for you.

LCD – General Introduction

Graphical LCD

Graphical LCD

LCD stands for Liquid Crystal Display. It can be used to display anything (virtually anything!). They are of many types. The ones we commonly use for embedded systems, robotics, etc are of two types – character LCD and graphical LCD. We will discuss about character LCDs in this post whereas graphical LCDs will be discussed later.

The most popular type of character LCD is the HD44780 Character LCD. In this post, we will be using the JHD 162A character LCD shown below. One of my readers, Rizwan, has also worked out this tutorial successfully using the LMB162ABC character LCD. Thanks Rizwan for the update! :)

JHD 162A Character LCD

JHD 162A Character LCD

The JHD 162A LCD is fully compatible with the HD44780 LCD. Hence, the same set of codes will work for both. It is a 16×2 LCD module i.e. it has 16 columns and 2 rows for display. It can operate in either 8 bit mode or 4 bit mode. In 8 bit mode, an 8 bit is data is sent to the LCD from the MCU whereas in 4 bit mode, 4 bits of data are sufficient to operate it.

It has 16 pins, the details of which is given below:

JHD 162A Pin Configuration

JHD 162A Pin Configuration

Now, for the LCD to work in 8 bit mode, it requires the 8 data pins (DB0…DB7) and 3 control pins (RS, R/W, EN) whereas in 4 bit mode, it requires 4 data pins (DB4…DB7, only the upper nibble) and 3 control pins (RS, R/W, EN). Though the 8 bit mode is faster and more accurate, it consumes more pins of the MCU. However, the 4 bit mode is also fast and accurate enough to satisfy most of our need, plus it requires only 7 pins for interfacing. Hence, we will be working in the 4 bit mode. In the 4 bit mode, data pins DB0…DB3 are left open.

Interfacing LCD

First of all, you need to make basic connections of the LCD. You can refer to the following circuit diagram for this. Relate it with the pin configuration given above.

LCD Connector

LCD Connector

Before coding, kindly download the LCD library written by Peter Fleury from here. This is an awesome library with predefined codes so that we can ease out a little bit by not breaking our heads upon the coding part. Thus we get to use the library functions instead of going into the depths of programming. This method is much more productive, efficient and time saving. At this point, don’t worry about how a library is written. May be in days to come, I’ll teach you that as well. ;)

Configuring the library

Now that we are ready for programming, open up AVR Studio 5 and create new project. If you are new to AVR Studio 5, view this page to get started. Now in the right pane, you will find the Solution Explorer window. There, right click on the project name, go to Add and then choose Existing Item…. Now browse to the folder where you have downloaded the libraries and choose lcd.c and lcd.h.

Adding Libraries

Adding Libraries

Added Files and Headers

Added Files and Headers

Now you can find the two files (the c file and the header file) listed in your project. Now follow the following steps in order to configure the library.

  • Double click on the ‘lcd.h’ file (in the Solution Explorer) to open it. Now make sure that you scroll down very slowly or else you will miss out on some important details.
  • As you begin to scroll down, you will find some commented text describing the library. Note the line where it says LCD_IO_MODE = 0 for memory mapped mode, LCD_IO_MODE = 1 for 4 bit mode, whereas 8 bit mode is not supported.
  • Scroll further down and you will find a line asking you to set your XTAL (or F_CPU). By default it’s 8MHz. Replace it with your own exact F_CPU. Make sure that this is correct or else there will be mismatch in delay timings.
  • Scroll down to the place where you need to set your LCD_IO_MODE. Make sure that it is set/defined to 1 (for 4 bit mode).
  • Just below it lies the best part. You can choose your own port where to interface the LCD with! As I said earlier, in 4 bit operation, there will be 4 data pins (DB4…DB7) and 3 control pins (RS, R/W, EN). You can either choose them to be across one port, or distributed across different ports. This is where you do it. By default it’s across PORTA. Choose them as per your pin availability.
  • Now, if you further scroll it down, you can find a list of different commands that can be passed to the LCD using the lcd_command() function.
  • Now, if you continue to scroll, you will find a list of all the functions defined in the library along with their description. You will find functions like lcd_init(), lcd_clrscr(), lcd_home(), lcd_gotoxy(), lcd_putc(), lcd_puts(), lcd_puts_p(), lcd_command(), lcd_data() and lcd_puts_P(). Their description is attached alongwith their declaration.

Coding

Now that you have gone through the different functions available, let’s write a sample code for it. Don’t forget to include “lcd.h” header file.

#include <avr/io.h>
#include <util/delay.h>

#include "lcd.h"

int main(void)
{
    lcd_init(LCD_DISP_ON_CURSOR); /* initialize lcd, display on, cursor on */
                                  /* for more options for
                                  /* lcd_init(), view lcd.h file
    while(1)                      /* run continuously */
    {
        lcd_clrscr();             /* clear screen of lcd */
        lcd_home();               /* bring cursor to 0,0 */
        lcd_puts("hello");        /* type something random */
        lcd_gotoxy(0,1);          /* go to 2nd row 1st col */
        lcd_puts("maxEmbedded");  /* type something random */
        _delay_ms(50);            /* wait 50ms */
    }
}

After building the project and burning your code, you will see “hello” written in the first row and “maxEmbedded” written in the second row. This was a basic example. Now it’s up to you upon how to exploit the library resources. Okay, try this one out by yourself. The LCD should display your in the first line, and then create a bouncing effect. Your name should move towards right till it reaches the corner. And then it should move left till it once again reaches the other corner. This should continue. Hint: Use lcd_command() function e.g. lcd_command(LCD_MOVE_DISP_RIGHT), lcd_command(LCD_MOVE_DISP_LEFT), etc.

Now try to create a rolling effect. The text should roll into the view and then move out of it. I found one such code here.

#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"

#define STRING_LENGTH 27
#define LCD_MAX 15 

void main()
{
    char array[STRING_LENGTH] = { "welcome to maxEmbedded blog" };
    int i,j;
    int start;
    int end; 

    lcd_init(LCD_DISP_ON_CURSOR);
    lcd_clrscr();
    while(1)
    {
        for ( j = 0; j < STRING_LENGTH; j++ )
        {
            if ( j >= LCD_MAX )
                lcd_gotoxy( 0, 0 );
            else
                lcd_gotoxy( LCD_MAX - j, 0 ); 

            start = (j <= LCD_MAX) ? 0 : (j - LCD_MAX); 

            end = (j <= LCD_MAX) ? j : (start + LCD_MAX); 

            if ( end >= STRING_LENGTH )
                end = STRING_LENGTH - 1; 

            for ( i = start; i <= end; i++ )
                lcd_putc( array[i] ); 

            _delay_ms(100);
        } 

        lcd_clrscr();
    }
}

How does it look? Cool, eh?

Displaying ‘int’ and ‘float’ values

One drawback of Fleury’s library is that the is no function which can directly display an integer or floating point value on the LCD. For that, we can use lcd_puts() itself in combination with itoa() and sprintf() funtions.

For displaying integer values, the following modification is required.

char buffer[10]; 

int n = 12345; 

itoa(n, buffer, 10);
lcd_puts(buffer);

For displaying floating point values, the following modification is required.

char buffer[10]; 

float f = 3.1415926; 

sprintf(buffer, "%f", f);
lcd_puts(buffer);

Thus, we are done with LCD interfacing. Now you can play with it. ;)

Possible Errors that might show up

While connecting the LCD, you might face some problems. Some of the most common problems that you might face are:

  • Nothing is visible on the screen.
  • Black Squares are visible on the screen.
  • Only the cursor blinks on the screen.
  • Sometimes even the screen blinks.
  • Random/Garbage symbols are displayed on the screen.

For such troubles, you can follow the following troubleshooting methods (most of the time it works out!).

  • Adjust the contrast pot to increase visibility.
  • Check your connections. Check for any short circuit.
  • Check and change the delay. Make sure you have entered the correct XTAL value in “lcd.h” file.
  • And last but not the least, check your code! ;)

Last updated on July 15, 2014.

210 Comments

  1. Your Tutorials are really excellent and I wish you can do a Tutorial based on Graphic LCD both (128×64 and 240×128) interfaced with the ATMEGA328P.
    If yes you have done that type of a tutorial you can gave me link

    Thank you for all your help in Embedded Programming

    • Hey Jack,
      Thanks for the suggestion. We have added it on to our list, but it might be a while before you actually see it here. Currently focus is on embedded Linux. Thanks.

      • K no problem program and I will for that Graphic 128×64 lcd display tutorial.

        Can you also do more tutorials on touch lcd display and TFT color display.

        From JM Mehlape
        Sent via my BlackBerry from Vodacom – let your email find you!

  2. char buffer[10];
    int n = 12345;
    itoa(n, buffer, 10);
    lcd_puts(buffer);

    I have one problem :
    if I have n=100
    n-1
    LCD puts 990
    what I can do with a buffer to get 99 in LCD.

    • Your question doesn’t make sense to me. Could you please explain your question a little bit instead of giving a pseudo code of your question?

      • I found my problem.
        I forgot to write lcd_clrscr();
        thank you for great tutorial.

  3. I find the information here to be very useful for a beginners. It take a patient and a understand person like you to approach this topic with a true concern yours. Thank you for sharing.

    • Thank you so much Tony! :)

  4. Hi
    I have problem with c++ programing:
    when i write #include or #include “lcd.h”
    in CodeVision for using lcd in my program, this error whill happen:
    Error(s) occured during assembly.

    please help me solve the problem
    thanks

    • Is that the only error being shown? Does it specify anywhere which assembly errors occur? Did you include the file in the project, and also in the working directory? Have you invoked the file properly?

  5. Hi Mayank,

    I am confused about RW pin. Actually if we don’t assign port for it then it should be ok ? right ? because in most cases we write to LCD, we don’t read from it. Because in one of my project i am running out of I/O pins and i have only dedicated 6 Pins left of LCD Interfacing. But this library utilizes..7 I/O Pins. So is there any work around for this ?

    • No, you still need to read the command from the LCD, which is done by the library. Whenever you’re writing to the LCD, you need to check the command byte (especially the busy bit) in the LCD to determine whether the LCD is ready to take in more data. This is done by reading the command byte from the LCD. My suggestion would be to make some more room for this pin.

  6. Hi Mayank,

    I am great fan of your blog :) really nice..

    but

    char buffer[10];

    float f = 3.1415926;

    sprintf(buffer, “%f”, f);
    lcd_puts(buffer);

    To show the float values its not really working people above already commented but i did not heard anything from you regarding this ?

    Please solve it…its wrong code its not working…for float… integer code is working fine :)

  7. Hi Max, im using atmega 128, and now im making a digital clock. i wonder how to clear the LCD after i write some text.

    thank you for your consideration.

    peace

    • Isn’t there a command to clear the LCD?

    • to clear screen, u can use simple lcd_clear();
      comand

  8. thnx a lot for ur help..
    u r doing a great job..

    • You’re welcome!

  9. Hey mayank,i need to know that while i increase the clock frequency form F_CPU 1000000UL to F_CPU 8000000UL instead of increase in processing of programmes (eg blinking of LED patterns ) it slows down.I want to undestand how this ting works and on what concepts clock frequency works??

    Thanks in advance!!

    • The behavior can sometimes be unpredictable. You’re trying to increase the FCPU in software, but in reality, it’s the same in hardware. Ideally you would always want to set your FCPU in the software the same as that your hardware is running at.

  10. Does this library work with a 204 LCD? If not where can I find library for a 204 LCD? Please someone help.

    • I think so. Try it out and let us know!

  11. sir,i wanted to know that when we display integer values on lcd,we first make a character array. But why we have to make a character array to store the integer value? Also,why would we even make an array,can’t we just declare a variable only?

    • This is because LCD can display only characters. There’s a difference between an integer as an integer and an integer as a character. Try implementing the following code snippet and see the output for yourself.
      int a = 65;
      char b[] = "65";
      char c = 65;
      printf("int_a = %d, char_a = %c, char_b = %s, char_c = %c, int_c = %d \n", a, (char)a, b, c, (int)c);

    • You are not incrementing the pointer. Have a look at this: http://pastebin.com/vn2qRQ4J
      This is a simple C code to implement the same thing what you’re trying to do. Just add the LCD portion and modify it for AVR.

  12. please send me the lcd.h file that you used in your code as i am using avrstudio 5 and it does not have lcd.h file.
    please send me as soon as possible

    • Hi Faran

      Please go through the post, we have already mentioned the link of the library which we have used. You can find it in “Interfacing the LCD” section.

      Thanks ;)

  13. i could’nt find lcd.h library …please help me

      • Hi my friend still remember me, my name is Jack who requested a tutorial about the 128×64 graphics LCD. I’m just asking when will you do it and. Hey I wanna share something very important with adding more inputs/output to our Microcontrollers (ATMEGA32) .

        • Hello Jack, it still might take a while for the tutorial to come up. We are sorry for that. Our focus is on something else currently. I hope you understand. If you really need it now, then please use Google search and I’m sure you’ll find something there. Thank you.

          • Yes I do and I understand, and your codes or softwares are magnificent, anyway I hope you don’t mind me asking what are you busy with it, cause I was busy with RFID tag reader from Parallax.

  14. how to interface 16×4 lcd to avr

    • It should be pretty much similar to using 16×2 LCD. The only difference is that it has an extended addressing. You might need to write your own functions for that though.

  15. Hi, Thanks for the awesome blog post!

    I have been trying to get the itoa funtion working with 32 bit numbers. The int int atmel studio 6 is not big enough for my project, but itoa is not working int32_t or long. When ever I have tried this the LCD just doesn’t display anything. Do you have any idea as to how to fix this? Thanks.

    • According to the avr-gcc wiki, an int takes 16 bits to store. This means that itoa is designed to work with 16 bits and not 32 bits. No wonder that it doesn’t work.

  16. Sir i want to display float value on lcd 16×2. my code is
    temp1=ADCH;
    // FOR MEASURING VOLTAGE
    temp=(temp1*19.53)*2.51;
    LCD_goto(1,1);

    snprintf(buffer,6, “%2.2f”, temp);
    lcd_data1(buffer);
    lcd_data1(“mV”);
    percent=(temp-11500);
    LCD_goto(2,2);
    snprintf(buffer1,4, “%2.2f”, percent);
    lcd_data1(” “);
    lcd_data1(buffer1);
    lcd_data1(“%”);
    it gives the output “?”… Please help me. I have also include the library printf_flt in avr5.1

  17. I followed your instructions very carefully but yet I can not get the program to compile in Atmel Studio version 6.2 (the latest will all updated made). The errors I get are the same as below for every function:

    Error 4 undefined reference to `lcd_init(unsigned char)’ C:\Users\user\Documents\Atmel Studio\6.2\LCD_Test1\LCD_Test1\Debug/.././LCD_Test1.cpp 8 1 LCD_Test1

    I tried compiling as both a C project and a C++ project but same error messages.

    Can anyone help with this?

    Thanks,

    Hank

    • Hello Hank,
      Undefined reference error means that the compiler is not able to locate where your lcd_init() function is defined. In other words, your LCD library is not getting included in the compilation. Are you sure that you added the LCD files properly? Also, please make sure to physically copy the files into your working directory along with adding them to the project. Thanks!

  18. awesome explenation,sir

Trackbacks/Pingbacks

  1. Interfacing LCD 16×2 dengan ATMEGA16 | Lab 90 - […] http://maxembedded.com/2011/06/16/lcd-interfacing-with-avr/ […]

Leave a Reply

%d bloggers like this: