Introduction: How to Control a 16x2 LCD Using an AVR ATtiny2313

About: Mechanical Engineer

If you are just getting into microcontrollers there's alot to know as you have likely found out. There's alot of good online tutorials for the Atmel AVR's and chances are you have see a few of those by now. I recently got into microcontrollers and didn't know jack about it. I wanted to have some early success and get my AVR to do something cool (other than blink leds).

I struggled through some terrible blog posts about how to control a common 16x2 LCD with the popular H44780 driver. I had to combine and tweak code from 3 places to get it working.  Anyway, over the past couple months I figured it out and since no one else has this covered on Instructables, I thought I would share my approach and see if you can get some early successes which will keep you diving deeper in to geekery.

There's an embedded video and pic of what this project will look like when you are done.

Here's what you will need:
1 - Atmel AVR ATtiny2313 microcontroller
1 - breadboard w/ 5VDC source (a 7805 will work with a 100uF & 0.1uF Cap)
1 - 16x2 Character LCD Display H44780 driver (available on Ebay for ~$6 or Sparkfun for ~$14)
1 - 16pin  0.1" spacing male header
1 - 330 resistor for LED backlight
1 - 1K for pull down on interrupt switch
2 - 10K resistor  for reset and counter interrupt pull ups
2 - small "breadboardable" momentary switches for reset & counter interrupt
1 - 1.5K resistor for contrast setting (could use a potentiometer), value may vary depending on display
1 - AVR ISP Programmer (see assumptions)
1 - soldering iron & solder
~10 - jumper wires for breadboard


Here's my assumptions:

- You have a AVR ISP programmer of some type (in my case the Atmel AVRISP mkII, but USBtinyISP should also work)
- I am assuming you have already gone through the flashy led tutorials and are somewhat familiar with some of the lingo like PORTs and binary numbers a little.
- I am doing everything in C code using WinAVR GCC.
- I am running the display in 8bit mode which isn't as pin efficient, but it is easier to teach.
- I am assuming you know how to solder
- I am assuming you are using the ATtiny2313, but you could put this code on any ATmega as well, as long as you rename the PORTs respectively. I'm not sure if this will work for Arduino's.
- My set up is using Atmel AVRStudio 4.17 with WinAVR 20090313 GCC C-compiler on a 32bit Window's Vista laptop. ( this is the toughest part because you may be using AVRdude or CodeVision which means my code may not directly work for you, but you will still learn something)
- My approach and my code may not be the most efficient or elegant way to run an LCD, but it does work and I can guarantee that when you see that display work for the first time, it's exciting regardless of how pretty your code is.

With all that said, lets get started!



Step 1: Setting Up the LCD

Ok, So you have 16x2 LCD with the H44780 or equivalent driver. These LCD's basically have a display screen, typically with an LED backlight, and a PCB on the back which has the driver. This driver makes our job really easy for controlling the LCD with a little $1.50 MCU. 

The Hitachi H44780 driver already knows all the characters in the alphabet plus some special symbols. It also has settings we can choose like show/hide the cursor, among others. The trick is, the way we control this is by hitting different combinations of the pins with 5v (binary 1) or 0v (binary 0). We will do this really fast and the driver will lookup and display the letters we pick. You can read a little more about the H44780 here en.wikipedia.org/wiki/HD44780_Character_LCD
When we write a message (character string) in the program, the compiler will compile these letters into the respective ASCII hex codes which means we don't need a font file like in the case of a POV or dot matrix.

So, lets set up the LCD for the breadboard.

To make the LCD easy to work with on the breadboard we will solder the male header to the LCD package. These LCD's typically have 14 data pins and 2 for the LED backlight. So you will snap off a 16 pin piece of header and solder it into each of the 16 holes.

See the pics.



Step 2: Understanding the Pins of the LCD

So you maybe wondering how we are going to control 16 pins of a LCD with a 20 pin MCU. Well, it's actually not that bad. The LCD driver has 16 pins but not all of them will go into the MCU. Let's get familiar with what these pins are going to do and I will try to explain.

Here's the H44780 Pin out. You will likely see a 16 and 1 printed on your LCD indicating the beginning and ending pin numbers.

  1. Ground       - Wired to the breadboard GND rail
  2. VCC (+5V)    - Wired to +5V breadboard power rail
  3. Contrast adjustment    - the 1.5K resistor will go from here to +5V rail to set the contrast of the display. A small potentiometer can be used here too.
  4. Register Select (R/S)  - Our program will control this pin depending on what we are doing - Sending Instructions or Sending Characters - wired to PORTD 4
  5. Read/Write (R/W)  - We will only be writing to the display, the program handles this - wired to PORTD 5. If you needed to free up pins you could change the program and wire this to GND if you will only ever write to the display.
  6. Clock (Enable)  - This pin gets toggled high-low to "clock in" the data that is on the data pins - wired to PORTD 6
  7. Bit 0  - LSB data pin to PORTB 0
  8. Bit 1  - data pin PORTB 1
  9. Bit 2  - data pin PORTB 2
  10. Bit 3  - data pin PORTB 3
  11. Bit 4  - data pin PORTB 4
  12. Bit 5  - data pin PORTB 5
  13. Bit 6  - data pin PORTB 6
  14. Bit 7  - MSB data pin PORTB 7
  15. LED Backlight (+)  - wired to +5V breadboard power rail
  16. LED Backlight (-)   - wired to breadboard GND with the 330 resistor (don't forget the resistor
So we will be using 11 pins of the ATtiny2313. If you get fancy and run this is 4 bit mode vs 8 bit you will drop pins 7-10, thus only using 7 pins of your MCU, but my program isn't set for that and I'm ok with using 10 of the available 18 pins. Plus as you'll see in the next step, this thing is super easy to breadboard because of the pin assignments I used.



Step 3: Breadboard It!

Hopefully you are following along. We are now going to put all of our pieces on the breadboard and get ready to go over the program.

This should take about 5 minutes.

I have included a schematic and a photo, but I will also talk you through it

1. Set up your power supply - a 7805 with a >5V power supply or battery pack. 100uF and 0.1uF capacitors are recommended to stabilize the input. See Schematic.
2. Place the ATtiny2313 on the board
3. Wire up the GND, +5V, and reset switch with the 10K resistor going to +5V and the switch going to GND.
4. Wire up the INT0 interrupt trigger switch from PORTD 2 to the switch with the 1K resistor from from the switch to GND. Also put the second 10K resistor from PORTD 2 to +5V so it's tied high until you hit the button. You can also parallel a small capacitor (0.1uF) across this to help debounce it.
5. Here's the smooth part, Place the LCD on the board so that the header pins on the LCD match up so pin 15 (LED backlight +5v) of the LCD plugs into pin 11(VCC +5V) of the ATtiny2313. This will line everything up nicely.  It's great because you barely have to do any wiring and all the LCD data pins are aligned with PORTB.
6. Then you will use jumpers to wire up the control lines from PORTD and put the 330 resistor from GND to pin 16 of the LCD (GND for backlight). Refer to the schematic.

I didn't show it but you will need to hook up your programmer as well. You should know the drill on that part. VCC, GND, SCK, MISO, MOSI, and RESET.

Take a look at the picture and schematic and get things wired up accordingly.

I have included the schematic with the code download on the Intro page in case you can't see it here.





Step 4: Download & Unzip the Code

Well, not quite. I have provided the code you will need to make this work in AVRStudio 4.16 with WinAVR GCC version 20090313. The code is adapted from a handful of tutorials, but I will give credit to Bibin John and his book "My Experience in Programming AVR Microcontrollers in C Using WinAVR/AVRGCC."  I found this code online and tweaked it and improved it to make things easier and better.

The 16X2 LCD is actually two 16x1 displays stacked together. The lines don't word wrap or drop to the next line unless you program them to. Once you write something it stays there unless you overwrite it or you clear the display. You have to make sure you only write 16 characters per line, any more and they will overflow off the screen. I believe the H44780 has 60 registers so the overage just flows into those, which you can't see.

I am struggling with how deep to dive into this. There's alot of very in depth info out there about doing advanced things with LCDs like scrolling and using special characters and the list goes on.

This instructable will focus on getting some text on the display and doing something useful in the process. We aren't just going to display the alphabet.

But wait, there's more. Since displaying variable information (i.e. the value of a variable or something like a counter) is a common thing to do in projects, We will also throw in a simple counter and update the screen each time you click the button.Plus we will use both lines of the display and navigate the cursor to begin away from the "home" position.

So finally, the code. It's all in C using AVRStudio. Down load the zip file, extract it, Make a new Project in AVR Studio and put the "LCD_2313_Instructable.c" file into the folder for the new project. Add it as a source file in the Project and then BUILD!. It should compile no problem.

I commented the heck out of the code so you should be able to follow it.

I can't go too deep into everything or else this instructable will be like 20 steps. So I apologize if I whitewash this a little bit, but you'll learn more from seeing and playing with the code.





Step 5: Build and Burn

Ok, so you have walked through the code by now.  And read all my comments line by line. Hopefully it is working for you.  I can't guarantee everything because everyone's system is setup different, but I think it's pretty solid code.

So let's build it and burn it.

I have the Clock Frequency set at 4,000,000Hz and I removed the CLKDIV8 fuse so my delays were more accurate. Aside from all that you should be all set

If you haven't already, take a look at my youtube video of the project in action on the Intro page.

Hopefully you can now take the core functions of the code and work them into your projects to control LCD's all over the place.

A couple of great places to get familiar with these codes and the technicalities of Character LCD's is
home.iae.nl/users/pouweha/lcd/lcd.shtml

www.dinceraydin.com/lcd/commands.htm