LCD Interfacing with AVR Microcontroller.
When you start working with LCD modules you will start feeling the real power of MCU and your imaginations will be touching sky you will wonder how many exciting a powerful gadgets you can create and that’s so very easily.
LCD Modules can present textual information to user. It’s like a cheap “monitor” that you can hook in all of your gadgets. They come in various types. The most popular one can display 2 lines of 16 characters. These can be easily interfaced to MCU's, thanks to the API( Functions used to easily access the modules) we provide. LCD interfacing is just fun !
Fig: A 16x2 LCD Module |
PIN Configurations.
The lcd modules has 16 PINs for interfacing. The details are given below.
| LCD Module Pin Configuration |
| 1 VSS (GND Supply) |
| 2 VCC (+5V) |
| 3 VEE (Contrast Adjust) |
4 RS |
5 R/W |
6 E |
7 DB0 |
8 DB1 |
9 DB2 |
10 DB3 |
11 DB4 |
12 DB5 |
13 DB6 |
14 DB7 |
15 LED + |
16 LED - |
Connection with ATmega8/ATmega168 etc.
The lcd module can be easily connected to the any 28 pin AVR MCU like ATmega8/ATmega168/ATmega328 etc. The diagram below shows the LCD connection with AVR MCUs port pins.
![]() |
Fig: Connection with 28 PIN AVR MCUs |
Connect the required pins of PORTB and PORTD as shown in the diagram. The PORTs are clearly marked in the board. For connection you will need single pin female to female wires. Supply the LCD using the onboard 5V supply output using a 2 PIN connecter. Leave D0-D4 of LCD unconnected.
Connection with 40 PIN MCUs like ATmega16/ATmega32
![]() |
Fig: Connection with 40 PIN AVR MCUs |
NOTE: The 10K Pot (RV1) is very important, so please don't omit that ! When powered on for the first time you need to adjust this pot to get a clear display. Without proper adjustment of this pot you can even get a completely blank display !
Adding LCD support to your project
To add LCD support to your C projects we have made a easy to use library. To use this library first create a new project in AVR Studio then copy the following files to your project folder. lcd.c lcd.h myutils.h from lcdlibv20.zip then add them to your project by right clicking project view and selecting “Add Existing Source File(s)…” and then select the “lcd.c”. Similarly add “lcd.h” and “myutils.h” in Header Files section. Now you are ready to start coding LCD applications !!!
Fig: Adding files to projects. |
Programming.
In your main C file include the file lcd.h as #include “lcd.h” then initialize the LCD subsystem using a call to LCDInit(LS_BLINK|LS_ULINE); the argument specify the type of cursor required the LS_BLINK gives a blinking cursor. LS_ULINE gives a underlined cursor. To write any text call LCDWriteString("Welcome"); To write any number call void LCDWriteInt(int val,unsigned int field_length); This will print a integer contained in “val” . The field length is the length of field in which the number is printed.
For example LCDWriteInt(3,4); will print as follows
![]() |
While LCDWriteInt(123,5) will print as follows.
![]() |
To goto any particular position on screen call.
| void LCDGotoXY(uint8_t x,uint8_t y); |
| LCDGotoXY(11,1); |
![]() |
Fig: Cursor Positioning. |
Now anything you write to LCD will be printed at (11,1).
Clearing the display
| LCDClear(); |
This will clear the display and bring the cursor back to (0,0). There are two more functions that will go to specific position and print in one call.
Writing Text at a specific position.
LCDWriteStringXY(x,y,msg); ____________________________ x,y : the location where to print “msg” msg : the message to print Ex: LCDWriteStringXY(3,0,”hello”); LCDWriteStringXY(8,1,”world”); Output:
|
Writing Number at a specific position.
Similarly there is a function for integers.
LCDWriteIntXY(x,y,num,field_length); ____________________________________ x,y : the location where to print “num” num : the integer number to print field_length : the length of field (see LCDWriteInt() function above). |
Sample Program
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
void main()
{
unsigned char i;
//Initialize LCD module
LCDInit(LS_BLINK|LS_ULINE);
//Clear the screen
LCDClear();
//Simple string printing
LCDWriteString("Congrats ");
//A string on line 2
LCDWriteStringXY(0,1,"Loading ");
//Print some numbers
for (i=0;i<99;i+=1)
{
LCDWriteIntXY(9,1,i,3);
LCDWriteStringXY(12,1,"%");
_delay_loop_2(0);
_delay_loop_2(0);
_delay_loop_2(0);
_delay_loop_2(0);
}
//Clear the screen
LCDClear();
//Some more text
LCDWriteString("Hello world");
LCDWriteStringXY(0,1,"By YourName Here"); // <--- Write ur NAME HERE !!!!!!!!!!!
//Wait
for(i=0;i<100;i++) _delay_loop_2(0);
//Some More ......
LCDClear();
LCDWriteString(" eXtreme");
LCDWriteStringXY(0,1," Electronics");
}
Advance Use – Configuring Connections.
The library is designed to be fully customizable. If you want to connect the LCD module to some different i/o ports of the MCU then you can do so easily. You just have to modify the lcd.h file. Let’s see how. Open lcd.h and find a section “LCD Connections” it looks like![]() |
Fig: Configuring LCD Connection. |
Set LCD_DATA to the port where you have connected the LCD data lines. Then set LCD_DATA_POS to the starting pin of data lines. The LCD data lines D4 to D7 must be connected to consecutive pins starting from LCD_DATA_POS. For example if you wise to connect like this.
| PORTD (MCU) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| DATA LINEs (LCD) | D4 | D5 | D6 | D7 |
You must configure like this
#define LCD_DATA D //Because we are using PORTD
#define LCD_DATA_POS 3 // Because LCD DATA4 is connected to PD3
Please note that LCD Data lines DATA0 to DATA3 are always unused only DATA4 to DATA7 are required.
The library uses advance 4-bit mode so DATA0-DATA-3 of LCD are not used, saving 4 MCU pins! Now set the port where you have connected LCD’s ‘E’ signal. In example it is PORTB so #define LCD_E B Then specify to which PIN of PORTB it is connected, this is done by #define LCD_E_POS PB4 So ‘E’ pin of LCD is connected to PORTD-6 In same way set RS and RW signals. And that’s all! So you saw how easy is to customize the library.
Downloads
- Core library files.
- AVR Studio Project for 28 PIN AVR MCUs (Tested on ATmega8).
- AVR Studio Project for 40 PIN AVR MCUs (Tested on ATmega32/ATmega16).
- HEX File ready to burn on ATmega8.
- HEX File ready to burn on ATmega16.
- HEX File ready to burn on ATmega32.
Custom Character ?
Some times we need to show characters that are not the part of standard character set, like some special symbols (say heart or symbols of other language like Hindi). In that case we can use custom characters. They are also easy to make and use. Full article on using custom characters on alphanumeric lcds is available here.
![]() |
Fig: Custom Char Demo ! See the heart and other symbols? |
Going Graphical ?
If you have more sophisticated display requirement then you may go for Graphical LCDs (GLCD) they can render graphics like Icons and bitmaps (images), support graphic primitives like line,circle, rectangle etc. Also they can draw text in different fonts and sizes. That means 100% fun! And they are cheap and very easy to get started (thanks to ProGFX.org). We have some beginners tutorials for it too. So why waiting? Go Graphical!
Have fun and don’t forget to bookmark this page. If you think this tutorial has helped you please post a comment.
Author
Avinash Gupta











best library ever, but can someone help me to use it with 4×16 lcd module, i dont know what to modify or what to add to use it with 4×16.
tnx
Daniel
@Daniel,
I have the improved version ready but I have not still made it public. I will support 20×4 and 16×4 modules, custom chars, more flexible pin mapping etc.
Hi Av..
Uhm.. help?
I damaged an atmega32 trying to disable jtag. Do you know how to resurrect this chip?
Also.. how to disable JTAG using “avrdude” with an atmega32?
@wlevis,
May be you chip is alive, just connect a crystal at the XTAL pins and try.
@wlewis
to make live for some dead chips:
http://diy.elektroda.eu/atmega-fusebit-doctor-hvpp/
Thanks. Meanwhile.. can somebody tell me how to disable JTAG using avrdude? Actually it is alive.. but the device signature is completely out of wack. Have been unable to revive it using the defaults.. even tried 0x3F unlock.
Well.. got this to work on PORTD. Still…
Still.. as I want to use PORTC I need to know:
1) how to disable JTAG using avrdude
2) how to revive chips using avrdude
3) A library tutorial
4) An eeprom tutorial
ATmega32 REVIVED!
Simplicity itself: used a 12mhz xtal instead of the 16mhz I was using and burned the fuses set to default. Will now try to disable JTAG.
SUCCESS!
Lcd Library now running on PORTC. yEs! Feels good. Ok.. for those using avrdude directly.. to disable JTAG use:
avrdude -p m32 -b 19200 -P COM3 -c avrisp -V -F -e -u -U lock:w:0x3F:m -U lfuse:w:0xe1:m -U hfuse:w:0xd9:m
Btw.. Im using the arduino avrisp programmer (found in arduino samples) on an atmega328p chip. Also using a usb to serial cable. Which brings to my next request.. hee hee..
An Attiny mkii programmer tutorial oh Yea.. Avinash you da man!
I cant wait till we get to video interpretation and laser for Robotics mapping. Im so excited im gonna pee.. haha.
Ok.. tested the lcd.h a bit. Your lib incorrectly assumes my 20×4 is a 20×2 lcd. Looked thru your lib for a way to tell it my lcd is 20×4 but if its there its not obvious. So now I have to examine the lib to find a way to implement this option. Of course, I dont mind, as I will learn. Still.. why rebuild the wheel? Given the excellence of your tutorials I was expecting a library on par with the arduino lcd library which is “superb” and “thorough”. Please use Arduino as a reference point in the future. Hmmmm.
@Av
Is this where I tell the lib Im using a 4 line lcd? Where do I get that information? Should i be posting in your forum?
lib.h >>
LCDCmd(0b00001100|style);//Display On
LCDCmd(0b00101000);//function set 4-bit,2 line 5×7 dot format
@wLewis,
I will mail you 20×4 lcd support by evening.
sir,can u please upload the custom characters tutorial for
a 16×2 lcd (4-wire)module.I have been waiting for it long time.
It would be great help for me,sir,Thank you.
@Av..
Hey Av.. wheres that 20×4 support?
hmmm, there is something tricky with this support, when i try to display a longer than 24 character string on one line with scrolling option of text on, i observed that it only scrolls first 24 characters and the next ones on the second line in the limit of another 24 chars, and if the string is longer than 48 chars, what is over 48 is not showed, can you confirm this issue please?
Avrdude code for atmega32 // 16mhz crystal // Jtag disabled.
avrdude -p m32 -b 19200 -P COM3 -c avrisp -V -F -e -u -U lock:w:0x3F:m -U lfuse:w:0xef:m -U hfuse:w:0xd9:m
I have to rectify, that is not an issue, instead is a LCD’s McU limitation in locations of memory available for each display line, and there are 40 characters, not 24 as i said above.
Hello Avinash,
Do you have any serial LCD with you?
Vinod
@Vinod,
Sorry we don’t have serial LCDs
i have been following ur tutorials..
i need information about why we generally use 4 bit mode(4 data lines+3 select lines) operations in programming with lcd
though we have 8 data lines .. why dont we use all data lines instead we use only four..
is thest any difference in operation..please clarify my doubt though it seems simple..
@Phani,
If I say you the cost of LCD is Rs 135 but you may also pay me Rs 270 if you like, then how much would you pay ?
The 4bit mode is bit difficult to program compared to 8 bit mode, but the reward is saving of 4 i/o pins !!! Got it?
Got it..!!as we are more interested in reducing no. of i/o pins we have shifted to 4 bit mode..with a slight change in program compared to 8 bit mode..got it sir..!!:) thank you..:)thanks for clarifying my doubt though its very basic doubt..:)
I’m finding sometimes when I power it up the lcd module does not display characters. It’s like the lCD does not get properly initialized. I noticed if I use a longer power wire it happens more frequently. I’ve tried adjusting the initial power on delay before the init but it doesn’t make a difference. Any ideas what could cause this?
I think I’ve got it fixed. I doubled all the delays in the LCD busy loop function. Now it works on every powerup. Not sure if this is because I am using an atmega48?
void LCDBusyLoop()
{
//This function waits till lcd is BUSY
uint8_t busy,status=0×00,temp;
//Change Port to input type because we are reading data
LCD_DATA_DDR&=(~(0x0f<>LCD_DATA_POS);
status=status<>LCD_DATA_POS);
temp&=0x0F;
status=status|temp;
busy=status & 0b10000000;
_delay_us(1); //0.5
CLEAR_E();
_delay_us(2); //tEL def 1
}while(busy);
CLEAR_RW(); //write mode
//Change Port to output
LCD_DATA_DDR|=(0x0F<<LCD_DATA_POS);
}
hi,
Enclose you a solution for LCD 4x (20/40). All you have to do is replace the existing code with my in lcd.c
void LCDGotoXY(uint8_t x,uint8_t y){
if(x<40){
switch(y){
case 0: // Line 1
x|=0×80;
break;
case 1: // Line 2
x|=0xC0;
break;
case 2: // Line 3
x|=0×94;
break;
case 3: // Line 4
x|=0xD4;
break;
}
LCDCmd(x);
}
}
@Mihael,
Thanks.
Thamks for ur great help
Thanks for ur great help
HI,
after compiling I always get the same error “error: lcd.h: No such file or directory”
The strange thing is if I try the Sample “LCDTest” I don’t have any problems, but if I start a project for an ATmega32 with exactly the same code and adding the lcd.c, lcd.h myutils.h I always get the error explained above.
Where could the problem be?
I know that “ankit agarwal” asked the same question but it seems that it didn’t get answered yet. Hope you can help me.
Thanks for your time.
@Alex,
We would be happy to help you. But please post in the forum. Thanks!
http://forum.extremeelectronics.co.in
I got a problem. I cant use the function #define LCD_DATA A because my data pin is somehow inverted after i have done the PCB , meaing that Pin 0 – D7 , Pin 1 – D6 , Pin 2 – D5, and Pin3 – D4. Please help on how to configure one data pin at a time. Thanks!
Great tutorial! helped a lot of people…
keep working, the other tuts are even better!
Thanks!
@Stefano,
Thanks (from the Author)
Hi Avinash,
I’m using the LCD in order to display the value read from the ADC module.
Is there a kind of “buffer” in the functions that write into the LCD?
I’ll post some code:
volatile char adc_val[5];
..
//ADC, ports and LCD setup and infinite loop in main
..
ISR(ADC_vect){
…
getTemperature();
…
}
getTemperature(){
…
LCDClear();
itoa(ADC,adc_val,10); //itoa adds at the end of adc_val
LCDWriteString(strcat(“ADC= “,adc_val));
_delay_ms(1000);
LCDClear();
strcpy(adc_str, “”);
…
}
here’s the problem: the first time getTemperature runs, it displays “ADC=XXX” correctly, while during the second execution it writes into the LCD this: “ADC=XXXYYY”, being YYY the second value of the ADC.
In the last instruction i try to make the string blank, but this doens’t affect the wrong behaviour.
Any ideas?
Thanks, Stefano
Hy Avinash,
I have a problem or a question… I have an LCD like this, using your configuration with portc and an external 16MHz quartz, modified the library with #define F_CPU 16000000UL i use an atmega168, and avrisp mk2 programmer, made all the settings, but fuses are killing me…
and i dont have the jtag row to enabel/disable… i have set them H.F to DC and L.F to 4e, dont work… i set them H.F. to C9 and L.F. to FF, didnt work…
Please give me an advice how to set them!!
It works!!!
@avinash
great job…….keep continue
i m impressed
There is sone problem with LCDWriteInt() function when we write negative number.It check for negative value whne value have gone to 0 by val/10 statement.
it should be checked in starting .I have corrected that.
LCDWriteInt()
{
char str[5]={0,0,0,0,0};
int i=4,j=0;
if(val<0)
{ val*=(-1);
LCDData('-');
}
while(val)
{
str[i]=val%10;
val=val/10;
i–;
}
if(field_length==-1)
while(str[j]==0) j++;
else
j=5-field_length;
for(i=j;i<5;i++)
{
LCDData(48+str[i]);
}
}
@Sanjay.
That’s right. I left as a homework for the user.
hello
how to make a program that ignores the RW pin signal, because the LCD is still only displaying data. On the LCD RW pin is always tied to GND, which means that the LCD display mode.
I enclose a further correction codes for data display on the LCD with 4×20
void LCDGotoXY(uint8_t x,uint8_t y){
if(x<40){
switch(y){
case 0: // Line 1
x+=0×80;
break;
case 1: //Line 2
x+=0xC0;
break;
case 2: //Line 3
x+=0×94;
break;
case 3: //Line 4
x+=0xD4;
break;
}
LCDCmd(x);
}
}
Sir,
How can we display smileys or say write in hindi on a simple 16*2 lcd in avr using bitmapping??
Thanks in advance,
Manan
Hi Avinash,
Thats an awesome tutorial. It worked for me with ATMega16 and using the given lcd library. Now I want to use an ATTiny 2313 to do the same project and to run the same sample program. I made the necessary changes in lcd.h but it is not working. I just see all black boxes on the first line. Could u help?? Thanx in advance.
this is very help ful:)
@Avinash Thanks very much for your generous release of the code!
Re posts 86/87, Difficulty in turning off flashing and underlined cursor…
It works here ok using the data sheet but after initialization!
ex:
InitLCD(0);
LCDCmd(0x0C); //get rid of U_blink and cursor
//or 0b00001100; of course
I think there is something wrong in using this with
AVR Studio 5
these are error generated on compile, project name ETako!
***
Error 2 ETako.elf section `.text’ will not fit in region `text’ D:\Users\Armen\Documents\AVRStudio\ETako\ETako\Debug 1 1 ETako
Error 3 region `text’ overflowed by 5006 bytes D:\Users\Armen\Documents\AVRStudio\ETako\ETako\Debug 1 1 ETako
@Armen,
This is a common error. That means the output code cannot be put into available flash memory.
From Project menu Goto ETako! Properties (Alt + F7) then goto toolchain tab.
AVR/GNU C Compiler->Optimization
then set Optimization level (-O2)
Then clean and build the project(Ctrl+Alt+F7).
Thank you so much!
Will you explain optimization factors? like between most & more, and why not to use most always?
I can not understand what this has to do with optimization? as you said, since overflow means not enough space for Flash/FlashPage while compiling, I think this is a pre-build error also when you compile as release mode, everything works just fine.
in release mode. which works!
tnx again.
i have no questions to ask every think is best
i don’t know any think before ur website
but i did my big project
about
2 dc motors
3 servo motors
4 pwm
3 ADC
4 relays
1 LCD
3 i/o
all are by PC controlled robot
thanks for every think
about your components are cheep best then but less components are available
the best AVR website
@Sai Krishna
Thanks !!!
robokits have more components
but no avr tutorials
u have best tutorials try for all components by u
because we are waiting for
it will be cheaper with u i think then any another
Great libray, very intuitive to use!
@Yossarian
Thanks!
how to turn off cursor? it blinks every time.
@Rashad,
One idea is to move the cursor off screen so that it is not visible. Like LCDGotoXY(17,0)
x=17 is off screen for a 16×2 module.
You can turn off the LCD cursor the next way.
First add in lcd.h this line:
*************************************
#define LS_OFF 0B00001100
**********************************
Which turns the LCD ON and the cursor off
Then add in your LCDTest.c this line:
**********************************
InitLCD(LS_OFF);
**********************************
This selects the cursor to be turned off and stops LS_BLINK and LS_ULINE
Hope this helps!
will be lcd library improevd? are you going to add new command for lcd
@Rashad
Can you suggest some required improvements?
hi.I have writed small program to send UART messagesto LCD and send mesage back to uart terminal.my message returns to terminal but i can not display it on LCD please help.small part of me code.thanks
void main()
{
unsigned char data;
USARTInit(38); //UBRR = 38
InitLCD(LS_ULINE); //Initialize LCD module
LCDClear(); //Clear the screen
LCDWriteString(“FARSAJIK”);
//Loop forever
while(1)
{
//Read data
data=USARTReadChar();
LCDWriteStringXY(0,1,data);
USARTWriteChar(data);
}
}
change like below and inform.
while(1)
{
//Read data
char data[2];
data[1]='\0';
data[0]=USARTReadChar();
LCDWriteStringXY(0,1,data);
USARTWriteChar(data);
}
}
it doesnt work.
thanx a lot for the tutorial
my lcd is working but light of the lcd in not fully on..it shows very dul characters.
your tutorials are just great it helped me a lot….
my YJ1602A 16*4 lcd module has worked successfully because of your cool lcd library but isn’t working for 20*4 lcd module 2004A . Is the library made for only 1 HD44780 controlled lcds ??? because i heard 20*4 lcd module has 2 HD44780 controllers inside……..& many thanx for other tutorials too
Thanks to author for all those nice tutorials, really good.
Am having problem in using the lcd libs downloaded on Oct 10. With this lib and sample code am not able to see any characters getting printed on LCD, I took the same sample code and used the old lib it works fine. Some changes in new libs are 1.delay has been modified, 2.In all the places 0x0F is replaced with 0xF0 and vice versa 3.#define F_CPU 10000000UL is 12000000UL in new lib. My Hardware connections and port usage are same for both codes.Pls help me to solve this issue.