Following my first article on the initial findings and results of my tests on the ATMega8, this article will show basic steps on how to connect a 2×16 characters LCD to the micro chip.
The reason for this is to have a way of debugging the microchip functionality, to output the results, the data and various other stuff. I can tell you this is a must have.
To use a minimum of I/O pins, I’ve decided to build a 4bit interface with the LCD. The hard part was to write the code, but finally after fixing several bugs and reading a lot of HD44780 documentation, I can say that I’ve completed a nice flexible code – meaning that you can easily configure the LCD pin connection.
The code interface is also attached, not much to say about it here, since it’s full of technical details and bit-wise operations, but if anyone has questions feel free to use the comments form at the bottom.
To edit some parameters like frequency or PIN connections (you can change the I/O pins used by the LCD on the ATMega), have a look in lcd.h . Zip attached: (update available, see below).
Function lcd_string2 is very useful for outputting text, since it supports variable parameters similar to printf. So you can use it for outputting misc content: lcd_string2(“Hello World! %d\npocketmagic.net”,i);
Here are some pictures with my LCD running:
Next thing to do is to start connecting various sensors.
Update October 16, 2009
LCD Code update to fix some issues in the delay functions. (update available, see below).
Update May 1, 2012
Some time has passed since this article was written, meanwhile I had the chance to improve the code a lot. The issue with character corruption requiring a first reset is fixed, so are other small issues I found. All in one, here is a better solution for you to use.
The LCD PINS are configured as following:
LCD D4 -> PORTD 5
LCD D5 -> PORTD 6
LCD D6 -> PORTD 7
LCD D7 -> PORTB 0
LCD RS -> PORTD 3
LCD E -> PORTD 4
You can change all these in HD44780.h
The speed of your MCU should be configured in aux_globals.h, by default it is set for 16MHz:
#define F_CPU 16000000UL
Here is the code for C:
And here is the code for C++, with the LCD interface as a dedicated class! To compile this code, you will need to set your AVR as C++ compatible. It is easy and well worth the time. See my tutorial here, to learn how to do it. C++ code: LCDTestCPP
This code will work perfectly with 1line, 2Line or 4 Lines HD44780 LCDs.
Update February 21, 2013
I have published two updates for this library. One using direct LCD connections (similar to what I have shown here) and another variant that uses a 74HC164 shift register to reduce the connections to only 3 wires. See it here.
This article has 108 Comments
do u have any work on the connections of LCD HD44780 with ATMEGA 32…. if u have then send to mee…
it’s the same as for atmega8, simply connect the LCD to some free pins on your uC, and compile the software in the post for your hardware.
how can i connect for 4*20?
Ioana, you can do it in the same way as for 2×16.
Regarding the software, in LCD.h change LCD_LINES to 4 and LCD_DISP_LENGTH to 20.
I also have a 4×20 lcd, I’ll see if I can hook it up to the uC, and post the modified code.
How can I make that work for an Atmega128. I have also a HD44780 controller. But I don’t understand how it works to just get something on the screen thats why I w<ant a simple excample
Hello Nils, making it work with the Atmega 128 is pretty much the same thing.
Connect the HD44780 to the atmega 128, change the code to reflect the correct PIN connections, and recompile for the atmega128 (code currently is for atmega8).
This should be all. good luck!
But I don’t understand much of the pin connections. Does it mather that i connect them to ie. PortA or PortB.
Do I need to change something in the make file or just in AVR Studio.
hey!!do u have any work on the connections of LCD HD44780 with ATMEGA 16….i just need the coding at this point… if u do then plz send them to me..i need it for VMLAB and the code in C and assembly…
Currently I’m not using the Atmega16, but the code I’ve posted is easily configurable to work with any pin layout.
just go in LCD.h and select the PINs you’re using according to the 4bit model, and recompile the code for atmega16.
hope this helps.
Nils, you can connect them to what port you want.
Simply choose 6 pins and configure the code in lcd.h and that’s it!
Do I need to change something in the make file of do something with the clock frequency? Ik work with a extern christal on 7372800 HZ.
The clock frequency is also defined in lcd.h (XTAL…) Change that as well and recompile.
Stupid question – I’m not exactly sure how to connect the AVR to the LCD screen. Is it simply a case of soldering the pins of the AVR to the appropriate holes in the LCD display?
In addition, what are pins 1,2,3 and 5 for? A power supply?
Yes you need to provide 5V for the LCD.
I have download the library and when I try to compile it with AVR Studio the program collapses as if it was in an infinite loop.
Do you know if there is some kind of incompatibility with newest AVR versions?
I’d need more details to be able to help.
Can you try to comment-out small parts of the code, to see what goes wrong and where?
I have created a project called ATMegatest with AVR Studio.
I have download your files: ATMegatest and the others included in the zip file and copied them in the folder of the project.
I add lcd.h and lcd.c in the menu in the left.
Then I try to Build the project. AVR Studio begins and writes some of the lines in the bottom but it does not end, the program is collapsed and can not end.
Do I need to change something in the project configuration before building the project?
Some more information: I have tried creating a new project and copying only led.c and led.h and the same has happened.
So I guess your project is somehow not correctly configured. Do you get any error messages or AVR Studio simply crashes?
Did you install all the AVR Studio components? See:
http://www.pocketmagic.net/?p=375 “Writing the software”.
I’m trying to use you lib with ATmega32@8MHz and displayteach162 2×16 at portA. Unfortunately I’m getting some wired chars but only occassionaly, more often i cant see anything. So my question is how to adjust timing for Enable latching. Maybe is this problem.
Dragomir, most probably the delay function doesn’t work correctly, because your atmega is configured to 8MHz (faster then in my tests).
Try to change the default delay parameters in the LCD.c functions.
I programmed my ATmega168 microcontroller with your sample code (ATMegatest.c) after modifying the makefile for my microcontroller, but my LCD won’t initialize.
1.Are you using the same LCD controller (HD44780)?
2.Is it a 2×16 LCD?
3.Does your Atmega run on 1MHz?
If not please pay extra attention to each of these. For 2) and 3) code modifications are required. Let me know if this helps.
1)yes 2)yes 3)yes
You should double check the wiring, and the LCD itself – maybe try with a second one.
I had some strange lcd displaytech162 maybe it has some problem, now I changed to other lcd some DEM 16217 and library works just fine….
Glad it works. Feel free to post pics or links to your project.
To run it on 4/8Mhz just put a small delay between characters sending in the lcd_string function. e.g:
while ((c = *text++) )
Anyone tried to print the symbol ‘%’ ?
just curious, cuz it’s not working for me!
In C, printf interprets some special characters found in strings.
You need to display “%%”.
I just got into the AVR scene recently. Glad to see other people showing off their work.
See my ATmega168 projects (same amount of pins as your ATmega8).
i’m trying to run this on a atmega168@12mhz so far no luck
the first line is empty and the second line is full of whole squares…
you asked someone if he was running the thing at 1mhz but in your .h files there’s something about 8mhz (#define XTAL 8000000) i change it to 12000000.
same thing it the makefile.
also it’s a 2×16 with the same controler.
the wiring is ok (checked a lot)
let me know if you have any idea 😉
update now i get some jibberish not what is expected at all
The “jibberish” characters are caused by problems in the delay functions (your MCU’s real speed is not corresponding to the values in the code).
The LCD datasheet specifically requires precise delays after sending various LCD commands.
Try adjusting the delay function used in LCD.c (_auxToggleE)
I’ll also post an updated version of the LCD code (the one in the post is old by now).
Post updated. Have a look on the new LCD.c / LCD.h files.
thanks man !
it works now (i had to change a few things tho, delay_us(us(700)); instead of 600, and had to get rid of the global(.h/c) files by coping everything in the lcd(.h/c) files.
Anyway, thanks a lot !!
ew for some reason it works when my isp programmer resets the whole thing but not when i unplug/plug the battery… i’m going to try to figure it out
See the new code, and only change the values in _auxToggleE .
A new sample with different connections here.
A wonderful article…. In my life, I have never seen a man be so selfless in helping others around him to get along and get working. I feel good that there are people like you too. Thanks for this great weblog of yours.
I build it (triple check the connections) but it’s not working. Some kind of strange chars. I changed fuses (also changed the F_CPU) but nothing. Then I used new lcd.c and globals.c but then I got few errors when I build it.
Any suggestions ?
Hi Dan. The weird chars mean you have the hardware ok, but the timing in the software commands is not right.
Try changing the delay values in _auxToggleE in lcd.c .
THX for quick response. I’ll play with those values and let you know if it helps or not. BTW: The strange char appears only on the forst row. Second one is always off.
i had the same issue at first, then i was able to make it work by changing the timings, but after that it would only work after a reset signal on the reset pin… not when i just plug the battery…
after a day and not seeing any improvements I ended up using another library wich works fine without changing timings or anything
Can you provide me with the link with that library ? It would help me.
dan: it’s on avrfreaks. here’s a link: http://ez4u.fr/fg55x
you may have to login to view the page !
here’s the direct link to the library: http://home.earthlink.net/~alank2/avr/hd44780_111.zip
Guys, good thing that you’ve found a solution and sorry for the little issues in my code.
When I get some time, I’ll fix them and update the LCD library. I’m also planning posting a 4 rows LCD sample.
Kevin: THX for the link. This link could be also usefull http://extremeelectronics.co.in/avr-tutorials/using-lcd-module-with-avrs/
Radu: THX to you for the start kick 🙂
I also had strange behavior with LCD running your code. After analizing LCD.c, finally I removed unecessary lcd_e_toggle() (3 occurrences just after 3 lcd_instr(…) in lcd_init())
and now it works very well for me.
Thanks for the feedback Jacek, I will test this and update the code.
hi i have interfaced a 6×1 lcd with atmega88 via HT1621 lcd driver. nw i want to program my lcd, so can u tell me from where i get lcd.h file for that…
Hi there, Ive installed winavr and avrstudio (the latest versions as of now 2009-12-04 16:41:50 ) and tried to compile your code Atmegatest.c. I get two errors
1. _auxDelay (undefinded reference to auxDelay) ive searched around to find the header/library containing auxdelay but to no avail. If you search google for “_auxDelay”, youll notice that its only you who use this function in your code, or websites using your code directly with no other references. Is there a solution to this problem?
2. delay_us doesnt compile correctly, although i found its definitions in global.h. I solved this by removing any reference to delay_us in global.h, copied in time.h and wrote in #include “time.h” in lcd.c and atmegatest.c.
But problem 1 remains. I would be very glad if i were to get any answers from you.
( i got time.h from a library at pololu robotics website)
I am trying to use LCD – ADM1602K 2×16 with Atmega168. But I am not able to initialize the LCD. Do I need to do anything different for ADM1602K LCD? Can you upload the code?
Looks like it got stuck in the delay function. I check the delay timing for each command for the LCD I have and the HD44780. Both have the same time delay. When I step through the code, it is getting stuck at the Delay function .please HELP
Please use the new updated files posted above. I really need to get some spare time and re-do the LCD code. it would be to also support a 4 lines LCD.
let me know if you need additional help.
Cormack, I will check that and get back to you. I’m currently on a linux box doing an Android bluetooth project and don’t have my microcontroller work here.
hello sir the lcd r/w pin is connected to the port for many connection i have seen and wat is that u have done ?
I’ve connected R/W to ground as in my approach I do not read from the LCD, I only write to it.
In case your question was about something else, please rephrase.
Don’t work 🙁
I write to manufacturer – not answer 🙁
You blog rocks!!
Hi Radu, and thanks for a very neat demo on using the HD44780!
I’ve compiled the program to an Atmega32, but one problem remains: the display will only initialize to one-line mode. Writing text to that one line works fine though. The clock frequency is correct, and I’ve only changed the port settings (our display is hooked up to port C instead of the default D). Any ideas?
Also, can we use this library in a student project of ours? Retaining the copyright notice of course.
Hi jrw, feel free to use it as long as you keep the (C).
I’ll think of a reason for the issue you’ve mentioned too.
I should probably also mention that the init-sequence only works about every 1 in 3 times. When it doesn’t, the display goes either blank, full of dark squares or (about 1/15 of the time) into two-line mode but the characters are gibberish. So this is in all likelihood a timing issue. We’ve tried compiling both with and w/o optimizations, doesn’t seem to matter.
I have similar behavior: worked every other init-sequence. Remove unecessary commands => See mu post #48.
Hi Radu, I have compiled the code for atmega 8. but display show some abrupt messages. Controller is working with 8 Mhz so accordingly i changed fuse with ponyprog. Also made changes in lcd.h and lcd.c still problem remains.Even i changed frequency to 4MHz and compiled original code still problem remains same. Thanks in advance
Thank you for posting your code — I’m using it (alas, unsuccessfully so far) to bring up a surplus LCD board. I am also having “gibberish” and other issues issues like post #62.
While looking for timing issues, I came across something in your code that looks suspicious. In lcd.c, the last line of function lcd_init() “lcd_home;”. I think you wanted “lcd_home()”. I don’t think it will make any difference in the operation of your code but I thought you would want to know.
Hi Joe, thanks for that. I do have plans to update the library, but I don’t have the time for it yet.
I have a lcd that works fine with the code but if i try to use USART an print on the lcd what i am receiving the whole thing gets stuck.
this only happends if i read something from the usart, otherwise i can print mesages by pushing a button, but after i try to read form USART it gets stuck and doesn’t print anithing.
Am gasit si eu pe net libraria facuta de tine si functioneaza cat de cat corect, o folosesc pentru un lcd 16×2, cu 5×8,cu 4 linii de date (RC1602B), dar am o singura problema, nu pot folosi decat primul rand(randul 0) al ecranului, banuiesc ca problema e din init. Folosesc Atmega16 ,cu 16 Mhz. Daca poti sa-mi spui te rog care linie trebuie modificata as fi recunoscator. Mersi
Finally a working LCD library! You need to do some code editing/fusion and linux adaptation, but all in all, everything is working now! Thanks 🙂
Hello Mauricio, thanks! Indeed I need to update the code and fix some initialization issues as well. Hope to find some time for this as well.
Just an update. Definitely, as Jacek stated above: “I also had strange behavior with LCD running your code. After analizing LCD.c, finally I removed unecessary lcd_e_toggle() (3 occurrences just after 3 lcd_instr(…) in lcd_init())
and now it works very well for me.”
That DID, I mean *DID* the trick to get the code working flawlessly so far ( I removed the auxdelay and the for loop to check stability ). So far, initial tests point to those extra lcd_e_toggle() as the only “guilty” for these LCD artifacts. It even works when I turn the uC on! ( I used to have to reset from the programmer for proper initialization of the LCD ). Really, I turned the uC on and off dozens of times right now to check it out: Flawless 🙂
Radu, by “You” I meant the user (about linux/code):p
AVR-GCC code is fully compatible cross-platform, thanks to GNU 🙂
BTW: I do know some C coding ( still rusty, long time no coding ), but I’m new to the AVR(uCs in general)/LCD world; is it possible to create custom chars using only these 4 I/O bits?
BTW2: I loved those PORT_ON /PORT_OFF macros from globals.h, those game me new ideas 🙂 ( Although I haven’t tested them yet, I already loved the idea )
Enough writing! Bye.
Worked for me also just after I have commented the lcd_e_toggle as said before, by the others. It’s strange that I did finish another project with another type of LCD (using the same HD44780 controller), and the library used there was not working with my new cheap LCD. Anyway, I’ve managed to make it work with your code.
Thank you Radu, and I’m very happy to see that you are doing a lot of interesting projects.
Thank you Florin, much appreciated.
I need to update this library, to make it work out of the box and support additional LCD’s, but it just got postponed. Hope to do it someday soon.
I have an old project card i trying to use.
This card datalines is PORTD, but same number as the diplay pin number.
But i use PORTC1 for RS and PORTC2 for Enable. What changes do i need to do
Had done it changes the right, but forgot to add RW to 0V
bit of it
# define LCD_E_PORT LCD_PORT
# define LCD_E_PORT PORTC
You can change the PINs in the LCD code. Open the lcd.h file and change the pins defined there accordingly.
Why i have any errot like this
ATMegatest.c:29: error: ‘for’ loop initial declaration used outside C99 mode
I appreciate your work here.
I want to connect 16×1 LCD too ATmega32. I am using 8MHz external crystal. After connecting everything the LCD is dead and displays nothing.What do you thing is the problem. Am not sure if the controller is HD447805. Rather this is what is on the LCD back. PHICO D-0 94v-0. I can not find any LCD controller like that….
This code will only work with HD44780 LCD’s . Can you get another LCD and test again?
> this is what is on the LCD back. PHICO D-0 94v-0
Phico is the manufacturer of the LCD assembly and 94v-0 is the Underwriters Laboratory rating of the PCB. Neither is the type of the controller; that should be printed on the largest SMT chip but not the PCB.
Just FYI, I am successfully using this code with a Phico LCD assembly that uses an HD44780 clone (not an actual Hitachi HD44780). Chances are good that your controller is also HD44780-compatible and the problem is something else.
@ Radu….I see that this code works with HD447805 Only.
@Joe yes I also tried to have a look at the chip’s back. I tested if the LCD lights when a back light connection is provided and it does not. How can I know whether the device is functioning or no? Can you tell me the test methods??
@ Radu….I see that this code works with HD44780 Only.
@Joe yes I also tried to have a look at the chip’s back. I tested if the LCD lights when a back light connection is provided and it does not. How can I know whether the device is functioning or no? Can you tell me the test methods??
hi i’m trying to make a pulse counter with an Atmega8 and i have to show the counter in the lcd so i wanna connect it to the uc i’m new in programming and i know this counter is easy but indeed i can’t :S coul you help me please i need it!!!
hi cami, you can try the code I posted
hiiiz,, could i got that code in assambly??
Hi, how can i remove the cursor? i try to put LCD_DISP_ON instead of LCD_DISP_ON_CURSOR_BLINK, but the cursor is still there.
I’m also using your library, and it works well! So first of all, thanks for your effort!
But I also want to know, how to disable the cursor, if that’s possible. Thanks
go to lcd_init in lcd.c, and instead of lcd_instr(LCD_DISP_ON_CURSOR_BLINK); use lcd_instr(LCD_DISP_ON );
I wrote a better / new LCD lib, that was also used for my microspot welder ( http://www.pocketmagic.net/?p=2518 ) , I will post the code soon.
Thanks a lot!
Hi Radu, I am working on MCs as a hobby. I am not very conversant with software although I am a 50 year old hardware engineer:) can you please explain the macros you have in auxdelay? Also, what is the facor 4000 you have in the _auxdelay function? As I said, I ma not good at software, but I like to analyse any code before I use it. I do not like to blindly copy & paste. Using ATMeag8 @ 1MHz and ATMega128 @ 16MHz.
By the way, your blog is excellent… Thanks.
@Morawala, thank you, it is always a great pleasure to receive compliments from my readers.
Before I provide any additional details, you should re-download the updated code that I’ve just posted. I had it sitting around for some time now, just didn’t have the time to upload it and provide a few details. This code is better organized, and has some bug fixes. You will also find a C++ variant that I recommend.
The new code is at the bottom of the article. See the new delay function, and let me know if you have any questions on it. Good luck with your projects!
I use LTN111R-10 1×16 LCD screen with atmega8 DIP.
I’m kinda stuck with two problems:
I’m able to see only first 8 characters of sent string on screen. It looks like for some reason program controlls only half of the screen. I did modified .h files for my configuration.
After powering up, screen sends some mess on first 8 characters and black fields in the 2nd half of this screen. Messes are fo random ASCII characters. Those first 8 characters are allright once I verify memory through my ISP programmer (which resets atmega during startup). What might be the reason? Some race conditions when power up?
can i plz get an assembly equivalent prgrm fr this…
Radu, just to say thanks for your work ptting this together. This library works perfectly on output pins of my own choosing with an ATMega328.
That’s great, Mart, thanks for your feedback.
I am having a problem with the coding. I have installed the C++ extension for AVR but what do I do after I have extracted the .zip file? I try to build the code but it fails. I am unsure where the files should be located and which files I actually need. Any help will be appreciated!!
It is very easy: download LCDTestCPP.zip, extract all files, open LCDTestCPP.avrgccproj as new project in AVR Studio. Compile, then upload the .hex to your microcontroller.
Hi Radu! I have interfaced LCD with Atmega8…
But in the starting it shows only blocks…
But after sorting Vcc with the ground for a while it works well..
What can be the cause of it….
And please can u send me the Proper Hardware schematic with the microcontroller…..
I mean with power supply and all….
make sure you are using the latest version, see my updates at the bottom of the post. the schematic is in the article, let me know if you need anything else.
what’s about the function of lcd_waitbusy?
static uint8_t lcd_waitbusy(void)
this function should return a value of type uint8_t but in the file LCDTestC.zip inside the file HDD44780.c the function returns nothing.
Thanks very much for the tutorial, I’m a complete newbie to this game.
I’m trying to compile it all in AVR studio 6, but on trying it I’m getting “undefined reference to…” errors with all the lcd_ commands.
Not sure why, I have the headers linked in there and have even tried putting everything in the same .c file (with the same result) so it doesn’t look like an error caused by the dependency files.
Thanks for the tutorial, i m a final year student in one of the Polytechnics in Nigeria.
I choose to design an microcontroller based automatic vehicle screening gate(ATmega8 with LCD). This gate system allow only lighter weight vehicle to pass through but denied bigger ones frm accessing the drive way. The LCD display either WELCOME/ACCESS DENIED.please i need a writeup to guide me through. Please ur response is highly required as time of submission is fast approaching.
The library doesn’t work. Tried removing “lcd_toggle_e” but all I get is a blinking cursor.