Source: https://mokxi.com/learn/arduino-i2c-lcd-not-working
Updated: 2026-09-27

Learn

# Arduino I2C LCD not working: find the cause from what you see

Written by the Mokxi team, updated September 27, 2026

Try it now, no account Sign up free or see every lesson

- 192 parts on the bench
- 25 boards running now
- 1.00x real time, on every board

Click to open it in the editor

A 16x2 LCD at 0x27 on A4 and A5, showing a temperature. Open it and change the address or the contrast to break it.

A 16x2 LCD with an I2C backpack needs four wires and a handful of lines of code, and it still fails more often than any other part in a starter kit. The good news is that what the screen shows narrows the cause down quickly. This page is organized by symptom, with what each one means and how to fix it.

The circuit above is a working one: an Arduino Uno with the LCD at address 0x27 on A4 and A5, showing a temperature. Open it in the editor and you can make every fault below on purpose. For building the circuit from scratch, the I2C LCD tutorial covers the wiring and the library in order.

## First, find out whether the LCD answers at all

Before changing anything else, run an I2C scanner. It asks every address from 1 to 126 whether a device is there and prints the ones that answer. If it finds nothing, the problem is wiring or power, and no amount of work on the display code will help. If it finds an address, put that address in your sketch.

On the thermometer circuit the Uno’s i2cscan program printed "found 0x27" and took 59 milliseconds for the whole bus. We then changed the display’s address property to 0x3F, the other common address, and it printed "found 0x3f". Backpacks built on the PCF8574 chip usually answer at 0x27 and those with the PCF8574A at 0x3F, but solder jumpers can move either one, so trust the scan over the listing.

The scanner works because `Wire.endTransmission()` reports whether the address was acknowledged. On this circuit it returned 0 for 0x27 and 2, "no acknowledge", for 0x3F. You can use the same check in your own setup() to print a clear message instead of a blank screen.

Check the address before using it

## The scanner finds nothing

Check the four wires. On an Uno, SDA is A4 and SCL is A5. The pins labeled SDA and SCL near AREF on newer boards are the same two signals, and in our run the display worked the same from either pair. Swapping SDA and SCL is the most common mistake: we swapped them on the thermometer circuit and the scanner reported "0 device(s)" with both lines idling HIGH. Nothing is damaged; swap them back.

Other boards use other pins. In Mokxi, `Wire.begin()` uses A4 and A5 on the Uno and Nano, 20 and 21 on the Mega, GPIO 8 and 9 on the ESP32-C3, and GP4 and GP5 on the Pico, the same pins each board’s own Arduino core uses. Then check power: VCC to 5 V and GND to GND. Most of these displays are 5 volt parts and look faint or blank on 3.3 volts, which is a real trap on ESP32 and Pico boards.

## The backlight is on, but there is no text

This is the classic one. First turn the small blue trimmer on the back of the backpack with a screwdriver. At one end of its travel the characters vanish, and at the other every cell is a solid block. Somewhere between, the text appears. A display fresh out of the bag is often set too far one way. In Mokxi the trimmer is the display’s contrast property; below 0.1 our run showed nothing at all, and anything above it showed the text.

If the contrast is right and the scanner found the display, check that the address in the constructor matches. We ran the working sketch with the address changed to 0x3F: the screen stayed empty, because the sketch was talking to a device that is not there. The code compiles and runs happily either way, which is why this one is so confusing.

## A row of solid blocks on the top line

Blocks on the first row only mean the display has power and the contrast is turned up, but the controller has never been set up. It powers on in one-line mode, which shows the top row of cells as dark rectangles. The sketch either did not call `lcd.init()` (or `lcd.begin()`, depending on the library), or its commands never arrived because of the address or the wiring.

This is one symptom Mokxi does not draw. Its backpack starts with every output low, so a display that was never initialized is simply dark with the backlight off. On a real module the backlight usually comes on at power-up and the blocks appear. The causes and the fixes are the same.

## The backlight is off

The backlight is one bit on the backpack’s port, so it only comes on when the sketch sets it. Call `lcd.backlight()` after `lcd.init()`. A sketch that calls `noBacklight()`, or never sets it on a library that needs it, gives a display you cannot read even though everything else works. In our run, `noBacklight()` left the simulated display blank. Mokxi’s `init()` turns the backlight on for you; some real libraries do not, so keep the call anyway. Many backpacks also have a two-pin jumper for the backlight, and it must be fitted.

## Wrong or leftover characters

Printing a shorter number over a longer one leaves the old digits behind. We printed 100 and then 99 in the same place, and the display showed "990". Print a few spaces after the value, or print it at a fixed width, rather than calling `clear()` in every loop, which blanks the screen for a moment and makes it flicker.

Text past the sixteenth column does not wrap to the second line. Each line in the controller’s memory is forty characters long and the display shows a sixteen-character window onto it. We printed twenty letters and the display lit exactly the same pixels as for the first sixteen; the last four went to memory nobody can see. Use `setCursor(0, 1)` to move to the second line.

Garbage across the whole screen on real hardware usually means the library does not match the backpack. Several libraries share the name LiquidCrystal_I2C, and older examples pass a pin map to the constructor that newer ones do not accept. If the address is right and the text is still wrong, the hd44780 library’s hd44780_I2Cexp class detects both the address and the pin mapping, and its I2CexpDiag sketch tests the whole connection and reports what it finds.

Overwrite a value without leftovers or flicker

## Questions

Why does my I2C LCD show only blocks?

Blocks on the top row mean it has power and contrast but was never initialized. Check that lcd.init() or lcd.begin() is called, that the address matches what an I2C scanner finds, and that SDA and SCL are not swapped.

What is the address of my I2C LCD?

Usually 0x27 for a PCF8574 backpack or 0x3F for a PCF8574A, but jumpers can change it. Run an I2C scanner sketch and use the address it prints.

Why is my I2C LCD lit but blank?

Most often the contrast trimmer on the backpack needs turning. After that, check the address in the sketch against the scanner’s result.

Which pins does an I2C LCD use on an Arduino Uno?

A4 for SDA and A5 for SCL, plus 5 V and GND. The SDA and SCL pins beside AREF on newer Uno boards are the same two signals.

Related

## Keep going

Arduino I2C LCD 16x2: Wiring and Code I2C Explained: Addresses, Pull-Ups and a Scanner How to Debug Arduino Code: Prints to Breakpoints Arduino OLED Display (SSD1306) Tutorial The I2C LCD part, pin by pin Help: how the character LCD is modeled Help: I2C modules and their addresses The Arduino Uno simulator The project page, with the full sketch

Sources

## Where the facts on this page come from

- Arduino reference: Wire.endTransmission() and its return codes
- The hd44780 library, with hd44780_I2Cexp and the I2CexpDiag sketch
- Texas Instruments: PCF8574 datasheet, addresses and power-on state

## Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.

Start building Open the editor
