Learn

A 16x2 LCD on four wires, with an I2C backpack

  • 192parts on the bench
  • 25boards running now
  • 1.00xreal time, on every board
Arduino Uno: I2C LCD thermometerlive0.000 s 0.00x
Click to open it in the editor
The lcdi2c example: a thermistor on A0 and the temperature on a 16x2 LCD at 0x27. Open it in the editor to change the temperature.

A 16x2 character LCD needs six data and control wires on its own. Solder a PCF8574 backpack to the back and it needs two, plus power, which is why the I2C version is the one in every kit now. The circuit above is an Arduino Uno reading a thermistor on A0 and showing the temperature on an I2C LCD at address 0x27, with the lowest and highest readings on the second line.

It is running on a simulated Uno right now. Open it in the editor and drag the slider on the thermistor to warm it up or cool it down.

What you need

  • An Arduino Uno
  • A 16x2 LCD with a PCF8574 I2C backpack
  • A 10 k NTC thermistor and a 10 k resistor, for the thermometer part
  • A breadboard and jumper wires

Wiring

Part and pin
Goes to
Note
LCD backpack SDA
A4
The Uno’s I2C data pin
LCD backpack SCL
A5
The Uno’s I2C clock pin
LCD backpack VCC
5 V
LCD backpack GND
GND
Thermistor
5 V to A0
The 10 k resistor goes from A0 to GND

How the backpack works

The display is the same HD44780 controller as the six-wire module. The backpack is an 8-bit port expander: every byte the board sends it over I2C appears on its eight pins, and those pins are wired to the LCD’s RS, RW, E, backlight and four data lines. So the driver sends each character as a short series of port writes, and the controller sees exactly what it would have seen from six board pins.

That design has one famous consequence. The backlight is just bit 3 of that port. A driver that forgets to set it gets a display that works perfectly and shows nothing you can read, which is the most common I2C LCD fault there is.

The LiquidCrystal_I2C code

The usual tutorial sketch compiles here as it stands. LiquidCrystal_I2C.h is Mokxi’s own header, written on its LCD driver, and it keeps the calls tutorials use: init(), backlight(), setCursor(), print(), clear(), createChar() and the scrolling calls. On an Uno it talks on A4 and A5; on other boards it uses the pins Wire.begin() uses there. One difference from the upstream library: init() turns the backlight on for you.

A first I2C LCD sketch
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Hello, world!");
}

void loop() {}

What the thermometer adds

The built-in example writes the reading without a float anywhere. The thermistor’s resistance falls steeply as it warms, and turning a reading back into degrees properly needs a logarithm. Instead the sketch keeps a table of what A0 reads at every ten degrees from minus 20 to 100, and draws a straight line between the two entries the reading falls between. The error from that shortcut is under half a degree, smaller than the thermistor’s own tolerance.

It also shows a trick for any character display: rather than calling clear() before every update, which blanks the screen and makes it flicker, it overwrites each line and pads the rest with spaces. A shorter number then wipes a longer one without the whole display blinking.

Try it in the editor

Open the circuit in the editor, select the display, and change its address from 0x27 to 0x3F. The screen goes blank, because the sketch is now talking to an address nobody answers. That is the most common I2C LCD fault reproduced in two clicks; set it back, or change the address in the sketch to match.

Then try the LiquidCrystal_I2C sketch above in place of the example: paste it into the editor, press Run, and the display says Hello, world! on the same four wires.

A good next step is a custom character. createChar() lets you define up to eight 5 by 8 pixel glyphs, and a small degree sign is the usual first one for a thermometer.

Common mistakes

The wrong address. Most backpacks answer at 0x27 and some at 0x3F. If nothing appears, run an I2C scanner sketch, which works here because the Wire library finds every module on the bus, and use the address it prints.

A blank display with the backlight on. On real hardware this is usually the contrast potentiometer on the backpack, turned all the way to one end. Turn it until a row of blocks appears.

No backlight at all, with text you can only just see. The backlight bit was never set. Call backlight() after init().

SDA and SCL swapped. Nothing answers and nothing is written. On an Uno, SDA is A4 and SCL is A5.

Calling clear() in every loop. It takes over a millisecond and makes the display flicker. Overwrite instead.

Questions

What is the I2C address of a 16x2 LCD?

Usually 0x27 for backpacks with the PCF8574 chip and 0x3F for the PCF8574A. Solder jumpers on the backpack can change it. The simulated module is set to 0x27 in this example, and the address is a property you can change.

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

A4 for SDA and A5 for SCL, plus 5 V and GND. On newer Uno boards the same two signals are also brought out beside pin 13.

Can I use the six-wire LCD instead?

Yes. The bench has the plain 16x2 module too, and the Uno’s thermometer example drives one in four-bit mode. It uses more pins but no I2C at all.

Can I print floats on the LCD?

With LiquidCrystal_I2C, print() is the board’s own and prints a float with two places, as Serial does, or lcd.print(t, 1) for one. Float arithmetic works too; the example works in whole tenths only to stay small on the Uno.

Build this for real

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