20x4 character LCD
The big brother of the 16x2: four rows of twenty characters on the same HD44780 controller. Aliases: LCD2004, 2004A, 20x4 LCD.
It comes two ways in the bin, as it does in the shops: lcd2004 with the sixteen
bare pins, and lcd2004i2c with the PCF8574 backpack soldered on, which turns them
into four.
Everything the 16x2 page says about the controller holds here word for word: the four-bit start-up, the busy time after every byte and the 1.52 ms after a clear, CGRAM for eight characters of your own, the contrast pin, the backlight. What is new is the shape of the window.
Pins
The bare module has the 16x2's sixteen pins, in the same order:
| Pin | What it does |
|---|---|
VSS, VDD |
Ground and 5 V. |
V0 |
Contrast. Near VSS is dark text; at VDD the glass is empty. |
RS |
Low for a command, high for a character. |
RW |
Tie it to ground: nothing here answers a read. |
E |
The clock. The byte is taken on the falling edge. |
D0 to D7 |
The data lines. Four-bit mode uses only D4 to D7. |
A, K |
The backlight LED. |
The backpack version has GND, VCC, SDA and SCL, at address 0x27.
Properties
The backpack version has address (0x27, or 0x3F for a PCF8574A board) and
contrast, which stands in for the blue trimmer on its back.
Four rows are two lines
The controller only has two lines of memory, forty characters each: line 1 at
0x00 to 0x27, line 2 at 0x40 to 0x67. A 20x4 shows each of them twice
over. Row 0 is the first twenty characters of line 1 and row 2 is the next
twenty; rows 1 and 3 are the same of line 2. So the rows start at:
| Row | DDRAM address | setCursor sends |
|---|---|---|
| 0 | 0x00 |
0x80 |
| 1 | 0x40 |
0xC0 |
| 2 | 0x14 |
0x94 |
| 3 | 0x54 |
0xD4 |
And that is why text that runs off the end of row 0 carries on in row 2, not row
1: the address counter just keeps counting along line 1. LiquidCrystal_I2C and
every other library carry that table, so setCursor(0, 2) does the right thing;
printing a long string without it is where the surprise comes from. The part models
it because it falls straight out of the memory map, not because it was written in
specially. Scrolling the display (scrollDisplayLeft) moves both halves of a line
together, so text leaving row 0 on the left comes back into row 2.
What it does not model
The same as the 16x2: nothing is read back (the busy flag, the address counter and DDRAM all read nothing), there is no 5x10 font, and bias, temperature and viewing angle do not exist. On the backpack, the PCF8574's input port and its interrupt pin are not there either.
Code
The backpack version, with the stock library:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Four rows of twenty");
lcd.setCursor(0, 3);
lcd.print("and this is row 3");
}
void loop() {}
The bare module works with mokxi_lcd1602.h, the same driver the 16x2 uses: give
setCursor the row start from the table above.
Common mistakes
Printing a line longer than twenty characters and finding the rest in row 2. Telling
LiquidCrystal_I2C the module is 16, 2: setCursor(0, 2) then goes to the wrong
address. On the bare module, V0 left at the supply: an empty glass.
See it in action
Twenty by four at /templates drives both versions from one Uno: the
bare one prints a forty-character line to show it carrying on in row 2, and the
backpack one places each row with setCursor.