A bare character LCD — 1602 (16 columns, 2 rows) or 2004 (20 columns, 4 rows) — has 16 pins and needs most of them wired up just to print text, which eats a huge chunk of an Arduino’s usable I/O for what’s meant to be a simple status display. The fix nearly everyone reaches for is a small blue I2C backpack board, a tiny add-on PCB soldered onto the back of the LCD that reduces the whole thing to four wires: power, ground, and two I2C lines. I’ve got a couple of Freenove I2C LCD 2004 modules on the bench, and the wiring and setup below is exactly what they need.
Pinout
Hover or tap a pin above to see what it does.
The backpack’s header is almost always labelled in this order, but it’s worth checking against the silkscreen on the specific board in hand rather than assuming:
| Pin | Name | What it does |
|---|---|---|
| 1 | GND | Ground — shared with the microcontroller’s ground. |
| 2 | VCC | Supply voltage, 5V on most backpacks. |
| 3 | SDA | I2C data line. |
| 4 | SCL | I2C clock line. |
What the backpack is actually doing
The backpack board is built around a PCF8574 I2C GPIO expander chip — a general-purpose chip that turns eight I2C-controlled digital pins into whatever a microcontroller needs, wired here specifically to drive the LCD’s HD44780 (or compatible) controller in its 4-bit parallel mode. The upshot is that a chip with only two data pins (SDA and SCL) ends up controlling all the parallel lines the LCD actually expects — the backpack is doing the pin-multiplexing so your microcontroller doesn’t have to.
Two other things live on the same small board and are easy to overlook:
- A contrast potentiometer — a small blue trimmer, usually near the header. If the display lights up but shows nothing, or shows a full row of solid blocks, this is almost always where to look first — turn it with a small screwdriver while the display is powered and running text, rather than guessing at a fixed position.
- Address select jumpers — usually three solder pads or a tiny DIP switch labelled A0/A1/A2. Bridging or cutting them shifts the module’s I2C address away from the factory default, which matters if more than one I2C device on the bus would otherwise collide on the same address.
Wiring to an Arduino or ESP32
Only four wires, but which physical pins they land on depends on the board:
- Arduino Uno — SDA to A4, SCL to A5. See the Arduino Uno pinout guide for where those sit on the header.
- ESP32 DevKit — SDA to GPIO21, SCL to GPIO22 by default (some boards can remap these in software, but those are the defaults almost every tutorial and library assumes). See the ESP32 DevKit pinout guide for the full pin map.
VCC goes to the board’s 5V pin — most backpacks are built around the PCF8574 running at 5V logic, and while some tolerate 3.3V, a display that’s noticeably dim or shows nothing on a 3.3V-only board is worth rechecking against its actual supply rating rather than assuming it’s faulty.
Finding the I2C address
Nearly every “the LCD shows nothing” report with an I2C backpack traces back to the code using the wrong I2C address rather than a wiring fault. The two addresses that show up constantly are 0x27 and 0x3F, depending on the PCF8574 variant and the state of the address jumpers, but guessing is unnecessary — an I2C scanner sketch (widely available, a few lines using the Wire library) will report the exact address of every device on the bus. Run one before wiring up the actual display library, note the address it finds, and pass that into whichever LCD library is being used (commonly LiquidCrystal_I2C).
Common mistakes
Wrong address in the library constructor. Covered above — always scan rather than assume 0x27.
Wrong dimensions passed to the library. LiquidCrystal_I2C and similar libraries take the display’s column and row count as constructor arguments — a 2004 initialised as if it were a 1602 will only ever use the top-left quarter of the screen, which looks like a wiring fault but isn’t.
Contrast pot never touched. A brand-new module’s contrast is set to whatever the factory left it at, which is very often “too high” (blank) or “too low” (solid blocks) rather than legible. This is worth checking before any code-level debugging.
Multiple I2C devices sharing the same address. If a second I2C module (an RTC, another sensor) shares the LCD backpack’s default address, both devices need to be on the scanner’s output at distinct addresses — this is what the address jumpers on the backpack are for.
If you haven’t wired up a breadboard circuit before, how a breadboard is actually connected underneath is worth reading first — it explains most of the “nothing lights up” moments before they happen.