Connecting a HD44780 compatible LCD to an AVR

[ The LCD Connector ] [ Example Ciruit ] [ LCD Command Set ] [ Display Data Addressing ] [ Next Page ]

These LCDs are the standard LCDs used everywhere. They come in many sizes and one size that's used a lot is 16x2 characters, so we'll use one of that size for our examples. They're very easy to use in 8 bit mode (4 bit is a little tricky).

The LCD Connector

The LCD Connector has 16 pins and is usually located at the top of the LCD. It offers pins for power, contrast, control lines, data lines and the LED backlight (if installed):

Pin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Gnd 5V Vee RS R/W E D0 D1 D2 D3 D4 D5 D6 D7 LED+ LED-

Gnd and 5V shouldn't need any explanation. Vee is the LCDs contrast voltage and should be connected to a pot (voltage divider). The voltage should be between 0 and 1.5V (this may vary for different manufacturers) and the pin *can* also be tied to ground.

RS is the register select pin. To write display data to the LCD (characters), this pin has to be high. For commands (during the init sequence for example) this pin needs to be low.

R/W is the data direction pin. For WRITING data TO the LCD it has to be low, for READING data FROM the LCD it has to be high. If you only want to write to the LCD you can tie it to ground. The disadvantage of this is that you then can't read the LCDs busy flag. This in turn requires wait loops for letting the LCD finish the current operation, which also means wasting CPU time.

E is the Enable pin. When writing data to the LCD, the LCD will read the data on the falling edge of E. One possible sequence for writing is:

- Take RW low
- RS as needed for the operation
- Take E high
- put data on bus
- take E low

You can also prepare the data before taking E high, which might save 1 word of code space (more on that later).

The purpose of the data lines should be obvious. When no read operation is in progress, they're tri-stated which means that these lines can be shared with other devices. In 4-bit mode only the high nibble (D4..D7) is used. Bit 7 is the busy flag (more on that later).

The Example Circuit

As we want to concentrate on the mega8, the code examples for the LCD are also written for the mega8. PortD is the only "complete" port offering us 8 bits, so PortD will be used for as data port. PortB is used by the ISP, so it will not be used by the LCD. PortC can be used for the LCD control lines (RS, R/W and E):

PortD -> LCD Data
PortC.0 -> RS
PortC.1 -> R/W
PortC.2 -> E

For the LCD to work, three more lines are necessary: Vcc, Ground and Vee. Vee can be tied to ground. The circuit can be built up using our mega8 board or an STK500.

When powered up, you should see a black bar in the first LCD line. That bar will disappear when the LCD is being initialised. Init is done by using a special command set. Commands are issued by writing data to the LCD when RS is low (see above). If the LCD is not initialised correctly, writing display data to it won't work at all. So I'll briefly describe the command set now, then go on with writing characters on the screen. Afterwards I'll describe the commands in detail.

The LCD Command Set

Most of the LCD commands don't need more time fore the LCD to execute them than writing a character. The datasheet of the LCD used for writing this code stated 40µs for a simple command.

Clear Display: 0x01
This command clears the display and returns the cursor to the home position (line 0, column 0). This command takes 1.64 ms to complete!

Cursor Home: 0b0000001x
This commands also sets the cursor position to zero, but the display data remains unchanged. It also takes 1.64 ms for execution, but it also shifts the display to its original position (later!).

Entry Mode:

0
0
0
0
0
1
I/D
S

I/D: Increment/Decrement Cursor bit. If set, the cursor will be post-incremented after any read data or write data operation. If cleared, the cursor will be post-decremented.

S: If set, the whole display will be shifted, depeding on I/D: If I/D and S are set, the display will be shifted to the left, if I/D is cleared (S set), the display will be shifted to the right. Usually I/D = 1, S = 0 is used (increment cursor, don't shift display).

Display On/Off:

0
0
0
0
1
D
C
B

D: Display On/Off. If set, the display is turned on. When the display is turned off, character data remains unchanged!

C: Cursor On/Off. If set, the cursor is visible in the way set by B.

B: Cursor blink on/off. If this bit is set, the cursor will blink as a black block. Otherwise the cursor is shown as an underscore _.

Shift Cursor/Display:

0
0
0
1
S/C
R/L
x
x

S/C: If set, the display is shifted. If cleared, the cursor is shifted. The direction depends on R/L.

R/L: If set, the display/cursor is shifted to the right. If cleared, it's shifted to the left.

Function Set:

0
0
1
DL
N
F
x
x

DL: Interface length. If set, 8-bit mode is selected (as in this example). If cleared, 4 bit mode is selected.

N: Number of display lines. If cleared, the LCD is a one line display. If set, the display is in 2/4 line mode.

F: Font size. If cleared, 5x7 Font is selected. If set, 5x10 font is selected.

The last two features might lead to the question "Why doesn't my display know what it is?" Well the controller (HD44780) is always the same, but it works with many different display types (1 to 4 lines, 8 to 40 characters per line) and the displays also come with different character sizes (5x7 or 5x10).

CG Ram Address Set:

0
1
ACG

ACG is the Address to be set for Character Generator Ram access. The CG can be used to configure and show custom characters.

DD Ram Address Set:

1
ADD

ADD is the address to be set for Display Data Ram access. The display data ram holds the data displayed (the characters). See below for DD Ram organisation.

Busy Flag/DD Ram Address READ:

BF
ADD

If the command register is read, the value actually returned by the LCD is the DD Ram Address (bits 0..6) and the busy flag (bit 7). THe busy flag should be read after every command to achieve max speed. If the busy flag is set, the controller is still busy executing a command/writig data.

Display Data Addressing

The display controller has to offer a way of addressing all display characters which works for ALL kinds of displays (remember: 1 to 4 rows, 8 to 40 characters). That's why the rows don't follow each other. The rows start at fixed addresses:

Display size
1st row
2nd row
3rd row
4th row
N x 8
$00 - $07
$40 - $47
x
x
N x 16
$00 - $0F
$40 - $4F
$10 - $1F
$50 - $5F
N x 20
$00 - $13
$40 - $53
$14 - $27
$54 - $67






Of course this list is not complete, but it shows some mean details about using a 16 x 4 display: The first address of the second row is bigger than the first address of the third row!

Example: For setting the cursor to the 3rd character of the second row in a 16 x 2 display, write 0x42 | 0b10000000 to the display command register.

The following page will explain display initialisation and simple read/write operations together with code examples.

[ Next Page ]