DEV Community

Cover image for Interfacing an I2C LCD with Arduino Uno
Play with Circuit
Play with Circuit

Posted on

Interfacing an I2C LCD with Arduino Uno

When working with a standard 16×2 character LCD and an Arduino Uno, one of the first problems you may notice is the number of GPIO pins required for the connection. In a typical 4-bit LCD configuration, several digital pins are used for the RS, EN, and data lines. That can become inconvenient when your project also needs sensors, buttons, communication modules, or other peripherals.

An I2C LCD module provides a much simpler approach. Instead of connecting several LCD control and data lines directly to the Arduino, an I2C adapter is attached to the back of the LCD. The adapter handles the parallel LCD interface and communicates with the Arduino using the I2C bus. This reduces the connection to just two communication lines, SDA and SCL, in addition to power and ground. The same I2C bus can also be shared with other compatible devices as long as each device has a unique address.

In this tutorial, we will look at how an I2C LCD works, understand its hardware and pinout, connect it to an Arduino Uno, identify its I2C address, and use the LiquidCrystal_I2C library to control the display.

What is an I2C LCD Module?

An I2C LCD module combines a conventional character LCD with an I2C adapter board. A commonly used version is a 16×2 LCD, which can display 16 characters on each of its two rows, giving a total display capacity of 32 characters at a time.

The LCD itself is generally based on the HD44780-compatible character LCD interface. Each character is generated using a 5×8 dot matrix. Individual pixels within this matrix can be switched on or off to form letters, numbers, symbols, and custom characters.

The advantage of the I2C version comes from the small adapter board attached to the rear of the LCD. Instead of controlling the LCD's parallel interface directly from the Arduino, the adapter receives commands over I2C and converts them into the signals required by the LCD.

I2C LCD Hardware Overview

The two main parts of a typical I2C LCD are the character LCD and the I2C adapter. The character LCD is responsible for displaying text and symbols, while the adapter provides the interface between the LCD and the Arduino.

The adapter commonly uses a PCF8574 8-bit I/O expander. The PCF8574 receives serial data from the Arduino through the I2C bus and provides the parallel output signals needed to control the LCD. This is what allows the Arduino to operate the LCD while using only the SDA and SCL lines.

The adapter also includes a small trim potentiometer that can be adjusted to control the LCD contrast. If the display is powered but the characters are not clearly visible, adjusting this potentiometer is usually the first thing to check.

A jumper is also provided for controlling the LCD backlight. With the jumper installed, the backlight is normally powered directly through the adapter. Depending on the adapter design, the jumper can be removed if external control of the backlight is required. An external voltage source or a suitable control circuit can then be connected to the LED pin.

I2C LCD Pinout

A typical I2C LCD module has only four external pins: GND, VCC, SDA, and SCL. The GND pin should be connected to the Arduino's ground. The VCC pin is connected to the Arduino's 5V supply. SDA is the I2C serial data line, while SCL is the I2C serial clock line.

On an Arduino Uno, the I2C interface is available on the SDA and SCL pins. On the standard Uno R3, SDA corresponds to A4 and SCL corresponds to A5. Therefore, the SDA pin of the LCD is connected to A4/SDA on the Arduino, while the SCL pin is connected to A5/SCL.

Because these pins are being used by the I2C peripheral, A4 and A5 should not be treated as ordinary analog inputs while the I2C LCD is communicating with the Arduino.

Circuit and I2C Adapter

The commonly used adapter is based on the PCF8574 I/O expander. Internally, the PCF8574 has eight quasi-bidirectional I/O pins, P0 through P7. The Arduino sends data to the PCF8574 through the I2C interface, and the expander converts that information into the parallel control and data signals required by the LCD.

The I2C lines of the PCF8574 are connected through pull-up resistors, typically 4.7 kΩ, to VCC. These resistors provide the required pull-up for the I2C communication lines.

The PCF8574 also provides three address-selection pins: A0, A1, and A2. These pins can be configured HIGH or LOW using the address jumpers on the adapter. This allows multiple PCF8574-based devices to use different addresses on the same I2C bus.

The LCD is connected to the adapter through a 16-pin connector. The PCF8574 provides the signals for the LCD's RS, RW, EN, and data lines. In the 4-bit LCD configuration, only D4 through D7 are used for transferring display data.

The adapter also includes a 10 kΩ variable resistor for adjusting the LCD contrast. On the circuit described here, an S9013 transistor is used to control the LCD backlight. The P3 output of the PCF8574 controls the transistor, which switches the backlight connection.

A jumper, JP1, is provided for enabling or disabling the LCD backlight. An SMD LED with a 1 kΩ resistor acts as a power indicator, while a 100 nF capacitor provides power-line decoupling. The external connector provides the I2C communication and power connections to the adapter.

On the LCD connector, pin 1 is GND, pin 2 is VCC, and pin 3 is V0 for contrast adjustment through the 10 kΩ potentiometer. Pin 4 is RS, pin 5 is RW, and pin 6 is EN. Pins 7 through 14 correspond to D0 through D7, although only D4 through D7 are used when operating the LCD in 4-bit mode. Pin 15 is LED+ for the backlight supply, while pin 16 is LED− and is controlled through the backlight switching circuit.

Understanding the I2C Address

Every device connected to an I2C bus needs an address so that the microcontroller can identify which device it is communicating with. This becomes particularly important when multiple sensors, displays, or other I2C peripherals are connected to the same two-wire bus.

The PCF8574 provides three configurable address pins: A0, A1, and A2. Each pin can be either HIGH or LOW, providing eight possible combinations. Since three bits are available, there are 2³, or eight, possible address configurations.

The PCF8574 uses a 7-bit I2C address. Four bits are fixed by the device, while the remaining three bits are determined by the states of A2, A1, and A0.

On the commonly used adapter described here, the address-selection pins are pulled HIGH by default through 10 kΩ pull-up resistors. When the address jumpers are left open, the resulting address is 0x27. If a jumper is shorted, the corresponding address-selection pin is pulled LOW, changing the address.

This provides an address range from 0x20 to 0x27 for the PCF8574-based adapter. For example, with all three address jumpers shorted, A0, A1, and A2 are LOW and the resulting address becomes 0x20.

It is worth remembering that not every I2C LCD module uses exactly the same address. Some modules may use a different PCF8574 variant or a different default configuration. Therefore, checking the actual address of the module is preferable to assuming that it will always be 0x27.

Connecting the I2C LCD to Arduino Uno

Connecting the LCD to an Arduino Uno is straightforward because the adapter reduces the interface to four external connections.

Connect the LCD's VCC pin to the 5V pin of the Arduino Uno and connect its GND pin to Arduino GND. Next, connect the LCD's SDA pin to the Arduino Uno's SDA pin. On the Uno R3, this is also available on analog pin A4. The LCD's SCL pin should be connected to the Arduino's SCL pin, which is also available on analog pin A5.

In other words, the complete connection is VCC to 5V, GND to GND, SDA to A4/SDA, and SCL to A5/SCL. The SDA and SCL header pins near the USB connector on an Arduino Uno R3 are electrically connected to A4 and A5.

When the I2C peripheral is being used, A4 and A5 should therefore not be used for their analog-input function.

For the example in this tutorial, the LCD is assumed to use the 0x27 I2C address. To obtain this address, the A0, A1, and A2 jumpers on the adapter should remain open. If all three are shorted, the address becomes 0x20.

The hardware setup requires an Arduino Uno R3, a 16×2 LCD with an I2C adapter, jumper wires, and a USB Type-A to Type-B cable for programming the Arduino. The original setup also specifies a 12V supply adapter for powering the Arduino when an external supply is required.

For the software side, Arduino IDE version 2.3.4 or later can be used along with the LiquidCrystal_I2C library by Frank de Brabander, version 1.1.2.

Finding the I2C Address of the LCD

One of the most common problems when setting up an I2C LCD is using the wrong address. Although 0x27 is frequently found on PCF8574-based LCD adapters, it should not be treated as a universal address.

If the address specified in the Arduino program does not match the actual address of the LCD adapter, the Arduino will not be able to communicate with the display correctly. The LCD may remain blank even though it is receiving power and the backlight is turned on.

An easy way to identify the address is to use an I2C scanner sketch. The scanner checks the available I2C addresses and reports any devices that respond. After connecting the LCD to the Arduino, upload the scanner sketch and open the Serial Monitor. The detected address can then be used in the LCD initialization code.

For example, if the scanner reports 0x27, the LCD can be initialized using that address. If it reports another address, such as 0x20, that address should be used instead.

Using an I2C scanner is especially useful when working with modules purchased from different manufacturers because the default address and adapter configuration can vary.

Creating Custom Characters

A useful feature of character LCDs is the ability to create custom characters. Because each character position is based on a 5×8 pixel matrix, you can define your own pattern by specifying which pixels in the matrix should be turned on.

Custom characters can be useful for displaying symbols that are not included in the standard character set. Examples include arrows, degree symbols, simple icons, battery indicators, or graphical elements for small embedded-system interfaces.

The custom character is normally stored in one of the LCD's custom-character memory locations and then displayed at the desired cursor position. This makes it possible to create simple graphical interfaces even though the LCD is primarily designed for text.

Creating Simple LCD Animations

The same custom-character capability can also be used to create basic animations. By defining multiple character patterns and displaying them sequentially, you can create the appearance of movement.

For example, a simple progress indicator, moving arrow, rotating symbol, or changing status icon can be created by repeatedly updating the custom character or switching between predefined character patterns.

The animation capabilities of a character LCD are naturally limited by its small display area and relatively low update speed, but they can still be useful for embedded projects where a simple visual indication is required.

Troubleshooting an I2C LCD

If the LCD backlight turns on but no characters are visible, the first thing to check is the contrast adjustment potentiometer on the I2C adapter. Slowly adjusting the potentiometer can make the characters visible.

If the LCD does not respond at all, check the VCC and GND connections and make sure the SDA and SCL lines are connected correctly. On an Arduino Uno, SDA corresponds to A4 and SCL corresponds to A5.

The next thing to check is the I2C address. Do not assume that every LCD uses 0x27. Run an I2C scanner and verify the address reported by the module.

If multiple I2C devices are connected to the same bus, make sure that their addresses do not conflict. The PCF8574 adapter allows its address to be changed using the A0, A1, and A2 configuration jumpers.

Finally, make sure the correct LiquidCrystal_I2C library is installed and that the LCD dimensions and address specified in the Arduino sketch match the actual hardware.

Conclusion

An I2C LCD is a convenient way to add a character display to an Arduino project without consuming a large number of GPIO pins. The I2C adapter takes care of the LCD's parallel interface and allows the Arduino to communicate with the display using only SDA and SCL.

The combination of a low-cost 16×2 LCD and an I2C adapter is particularly useful for embedded projects where you need a basic local interface for sensor readings, system status, menus, counters, measurements, or other real-time information while keeping most of the Arduino's GPIO pins available for other hardware.

For source code visit Play with Circuit

For more Arduino and embedded electronics tutorials, project guides, and practical hardware interfacing examples, you can also explore Play with Circuit, which covers a range of hands-on projects involving Arduino, ESP32, sensors, displays, and other embedded hardware.

Top comments (0)