Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

20x4 I2C LCD with Arduino Uno — wiring, address and four-line code

Wire a 20x4 LCD with a PCF8574 I2C backpack to an Arduino Uno R3, find it at 0x27 or 0x3F automatically and update four lines without flicker.

Arduino C++Verified — core avr 1.8.8, LiquidCrystal I2C 1.1.2, 3 Nov 2026Compile-only

Community draft — report a mistake

A 20×4 character LCD shows twice as much as the common 16×2 — enough for four sensor values or a small menu. With a PCF8574 I2C backpack soldered on, it needs four wires.

On the Uno everything runs at 5 V, so the backpack connects straight to 5V, GND and the SDA/SCL header (the same signals as A4/A5). Two things trip people up: the backpack’s address (0x27 or 0x3F, depending on the chip maker) and the odd row order. The sketch handles the first by trying both addresses. For the second, it always places text with setCursor().

It labels four lines, then refreshes a live analog reading and the uptime twice a second by overwriting only the changing digits.

Wiring

Arduino Uno R3Only the pins used are shown · 5 V logic20×4 LCD + I2C backpack5VGNDSDA · 18SCL · 19GNDVCCSDASCL
Every connection
Arduino Uno R320×4 LCD + I2C backpackWireNotes
GNDGNDblack
5VVCCredBacklight and logic together draw about 30–60 mA — fine from the Uno’s 5V pin.
SDASDAblueSame signal as A4
SCLSCLyellowSame signal as A5

5 V part, 5 V board. The LCD needs 5 V for proper contrast, and the backpack pulls SDA/SCL up to 5 V. On ESP32 or Pico, put a BSS138 level shifter between the board and the backpack instead of wiring SDA/SCL straight to 3.3 V pins.

Board quirks

  • The 20x4 shares the 16x2’s controller, and its memory makes text that runs past column 20 on row 0 continue on row 2. Always place text with setCursor(col, row).
  • Rewriting a value with padding spaces (as the sketch does) avoids the flicker of clear(), which also takes about 2 ms.
  • The library and a 20x4 buffer use very little RAM, so this display is a good fit for the Uno when an OLED’s 1 KB buffer won’t fit.
  • Everything is 5 V, so no level shifter. SDA/SCL and A4/A5 are the same pins — use one pair.

Code

lcd-20x4-uno.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// 20x4 LCD with a PCF8574 I2C backpack on an Arduino Uno R3.
// GND → GND, VCC → 5V, SDA → SDA (A4), SCL → SCL (A5).
// Finds the backpack at 0x27 or 0x3F by itself.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

uint8_t findLcd() {
  const uint8_t addrs[] = {0x27, 0x3F};
  for (uint8_t a : addrs) {
    Wire.beginTransmission(a);
    if (Wire.endTransmission() == 0) return a;
  }
  return 0;
}

LiquidCrystal_I2C* lcd;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  uint8_t addr = findLcd();
  if (!addr) {
    Serial.println(F("No LCD backpack at 0x27 or 0x3F - check SDA/SCL"));
    for (;;) {}
  }
  static LiquidCrystal_I2C display(addr, 20, 4);
  lcd = &display;
  lcd->init();
  lcd->backlight();
  // Rows must be set with setCursor: text that runs past column 20
  // continues on row 3, not row 2 (that's how the controller's memory is laid out).
  lcd->setCursor(0, 0);
  lcd->print(F("Arduino Uno + 20x4"));
  lcd->setCursor(0, 1);
  lcd->print(F("I2C at 0x"));
  lcd->print(addr, HEX);
  lcd->setCursor(0, 2);
  lcd->print(F("A0 raw:"));
  lcd->setCursor(0, 3);
  lcd->print(F("Uptime:"));
  Serial.print(F("LCD ready at 0x"));
  Serial.println(addr, HEX);
}

void loop() {
  char buf[8];
  lcd->setCursor(8, 2);
  snprintf(buf, sizeof(buf), "%-5d", analogRead(A0));  // pad with spaces, no flicker
  lcd->print(buf);
  lcd->setCursor(8, 3);
  lcd->print(millis() / 1000);
  lcd->print(F(" s   "));
  delay(500);
}

Library: LiquidCrystal I2C (Frank de Brabander) — compiled with LiquidCrystal I2C 1.1.2.

Expected serial output

Serial Monitor · 9600Output
LCD ready at 0x27

Common errors

Backlight on, but only white blocks or nothing

Turn the blue contrast trimmer on the backpack slowly with a screwdriver. See LCD shows blocks or blank.

Only the first letter of each word appears

A library mismatch. Install “LiquidCrystal I2C” by Frank de Brabander — see this fix.

“No LCD backpack at 0x27 or 0x3F”

SDA/SCL swapped or loose. Run the I2C scanner; some backpacks use 0x20–0x26.

↑↓ to move · Enter to open