HD44780 character LCD: pinout, 4-bit wiring and initialization
Driving a 16x2, 16x4 or 20x4 character LCD: pin functions, contrast, 4-bit vs 8-bit mode, the initialization sequence, DDRAM row addresses and timing.
The Hitachi HD44780 (and its many clones: KS0066, SPLC780, ST7066) drives almost every character LCD module — 16x1, 16x2, 20x2, 16x4, 20x4 and 40x2. Once you know one, you know them all.
Pinout
| Pin | Name | Function |
|---|---|---|
| 1 | VSS | Ground |
| 2 | VDD | Supply, usually +5 V (3.3 V versions exist) |
| 3 | V0 / VEE | Contrast — wiper of a 10 kΩ pot between VDD and GND |
| 4 | RS | Register select: 0 = command, 1 = data |
| 5 | R/W | 0 = write, 1 = read. Tie to GND if you never read |
| 6 | E | Enable — data is latched on the falling edge |
| 7–14 | D0–D7 | Data bus; in 4-bit mode only D4–D7 are used |
| 15, 16 | A, K | Backlight anode and cathode (check whether a series resistor is fitted) |
4-bit or 8-bit?
4-bit mode saves four pins: every byte is sent as two nibbles, high nibble first, each with its own pulse on E. It is what most projects use. 8-bit mode is a little faster and simpler to code but costs eight data lines. If R/W is tied to ground you can't read the busy flag, so use fixed delays instead — generous ones.
Initialization sequence (4-bit)
- Wait at least 40 ms after power-up (the datasheet asks for 15 ms after VDD reaches 4.5 V, 40 ms after 2.7 V — waiting longer does no harm).
- With RS = 0, send the nibble
0x3; wait at least 4.1 ms. - Send
0x3again; wait at least 100 µs. - Send
0x3a third time, then0x2— the controller is now in 4-bit mode. - Send full commands (two nibbles each):
0x28function set (4-bit, 2 lines, 5×8 font),0x08display off,0x01clear (wait 2 ms),0x06entry mode (increment, no shift),0x0Cdisplay on, cursor off.
The triple 0x3 exists because the controller may be in an unknown state — mid-byte in 4-bit mode, for example — after a reset without a power cycle. Skipping it is the classic reason a display works after power-up but shows garbage after pressing reset.
Useful commands
| Command | Code | Execution time |
|---|---|---|
| Clear display | 0x01 | 1.52 ms |
| Return home | 0x02 | 1.52 ms |
| Entry mode: increment | 0x06 | 37 µs |
| Display on, cursor off / on / blinking | 0x0C / 0x0E / 0x0F | 37 µs |
| Function set 8-bit / 4-bit, 2 lines | 0x38 / 0x28 | 37 µs |
| Set CGRAM address (custom characters) | 0x40 + address | 37 µs |
| Set DDRAM address (cursor position) | 0x80 + address | 37 µs |
Times are for the standard 270 kHz oscillator; clones can be slower, so add margin. The enable pulse must be at least 450 ns wide — 1 µs is a safe choice.
Row addresses
| Display | Row 1 | Row 2 | Row 3 | Row 4 |
|---|---|---|---|---|
| 16x2, 20x2, 40x2 | 0x00 | 0x40 | — | — |
| 16x4 | 0x00 | 0x40 | 0x10 | 0x50 |
| 20x4 | 0x00 | 0x40 | 0x14 | 0x54 |
So to put the cursor on row 2, column 5 of a 20x4, send 0x80 + 0x40 + 4 = 0xC4. On a 20x4, rows 3 and 4 are simply the continuation of rows 1 and 2 in memory — which is why text “jumps” from row 1 to row 3 if you just keep writing. Many 16x1 modules are wired internally as 8x2: characters 9–16 live at 0x40.
Custom characters
Eight user characters (codes 0–7) live in CGRAM. Each is 5×8 pixels, stored as eight bytes where the low five bits are the pixels. Set the CGRAM address to 0x40 + 8 × n, write eight bytes, then set a DDRAM address again before printing text — otherwise your text goes into CGRAM.
Troubleshooting
- Only a row of solid blocks: the module has power but hasn't been initialized — check E and RS wiring, and the init delays.
- Nothing visible at all: contrast. Turn the pot through its whole range; many modules need V0 at only a few hundred millivolts.
- Random characters: wrong nibble order, E pulse too short, or no delay after clear/home.
- I2C “backpack” modules (PCF8574) usually answer at address
0x27or0x3F, but the mapping of expander bits to RS/E/backlight varies between boards — use the library settings that match yours.
Keep reading
Torry's Delphi Editor & curator
Hi, I'm Torry's Delphi. For more than ten years I've been writing software that collects and organises data — scrapers, catalogues, automation pipelines. Repair documentation turned out to be the perfect mess to clean up.
The files listed here were collected by the community in the Telegram channel @schematicslaptop, plus a Google Drive archive. I wrote a parser that reads every file name, recognises the brand, the ODM manufacturer (Compal, Quanta, Wistron…) and the board number, and turns it into pages you can search and browse.
Next to the catalogue I keep a small set of practical notes on electronics and PCB work — KiCad libraries, moving designs from Eagle, making prototype boards at home, LCDs and EEPROMs. If something is sorted wrong or a note is unclear, write to me and I'll fix it.