Arduino I2C LCD 16×2 Interfacing

This is a comprehensive guide for Arduino I2C LCD 16×2 Interfacing. You’ll learn how to use I2C LCD with Arduino and create some example projects to practice what we’ll be learning in this tutorial. We’ll implement the following examples in this tutorial:

  • Arduino I2C LCD 16×2 Text + Variables Display
  • Arduino I2C LCD 16×2 Scrolling Text Display
  • Arduino I2C LCD 16×2 Custom Characters Display
  • Multiple I2C LCD Displays Interfacing With Arduino

We’ll start off by explaining how the I2C LCD module works, its pinout, and how to connect it to your Arduino board. We’ll display some text and numbers on the I2C LCD screen, make the text scroll on the LCD, and also create some custom characters and emojis. Without further ado, let’s get right into it!

Table of Contents

  1. Arduino I2C LCD
  2. Arduino I2C LCD Interfacing
  3. Arduino I2C LCD Library Installation
  4. Arduino I2C LCD Example
  5. Arduino I2C LCD Scrolling Text Example
  6. Arduino I2C LCD Custom Characters Display
  7. Arduino Multiple I2C LCD Displays Example
  8. Arduino LiquidCrystal_I2C Library Useful Function
  9. Arduino I2C LCD Common Issues Troubleshooting
  10. Wrap Up

Arduino I2C LCD

LCD (Liquid Crystal Display) is typically used in embedded systems to display text and numbers for the end user as an output device. The 16×2 alphanumeric display is based on the Hitachi HD44780 driver IC. Which is the small black circular chip on the back of the LCD module itself. This is the controller that controls the LCD unit and we communicate with using Arduino to send commands and text messages.

Alphanumeric LCD 16×2

The LCD module consists of 16×2 character cells (2 rows x 16 columns), each cell of which is 5×8 dots. Controlling all of these individual dots is a tedious task for our Arduino. However, it doesn’t have to do so. As there is a specific function controller on the LCD itself controlling the display while reading the user’s commands & data (the Hitachi HD44780 controller).

Arduino-LCD-16x2-Interfacing

The tutorial linked below is highly recommended to learn more about Arduino LCD interfacing & LiquidCrystal Library.

💡 Also Read
Arduino LCD 16x2 Interfacing Tutorial

This article will provide you with more in-depth information about Arduino LCD 16×2 interfacing, how LCDs work, how to use the LiquidCrystal library functions, create custom LCD characters & emojis, and more. It’s highly recommended!

I2C LCD Module (PCF8574 IO Expander)

The I2C IO expander IC (PCF8574) is commonly used as a cheap solution to implement an I2C LCD interface that replaces the classic parallel connection to the LCDs (at least 6 pins) with an easy-to-use I2C bus (only 2 pins). Using it saves a lot of Arduino IO pins that would have been consumed to create a generic LCD parallel communication.

PCF8574 I2C LCD IO Expander With PIC Interfacing Tutorial

Moreover, it’s shared with all I2C devices on the bus, so you can still have so many other modules/sensors connected on the same bus. In this previous article, I’ve demonstrated everything about this IC using its datasheet and build a driver library (in Embedded-C) for this IC. You can check it out if you’re interested in learning more about it.

Arduino-I2C-LCD-PCF8574

In this tutorial, we’ll only discuss the important things that you need to know in order to get started with I2C LCD interfacing with Arduino.

I2C LCD Address (Default)

You need to refer to the PCF8574 chip manufacturer’s datasheet to make sure what’s the I2C device address for the chip you’ve got around. If you’ve got an I2C LCD with Ti (Texas Instruments) PCF8574 chip, the default I2C address is 0x27 which is the 7-Bit device address with the three least significant bits (A0 – A1 – A2) are pulled up to HIGH.

If you’ve got an I2C LCD with an NXP PCF8574 chip, the default I2C address is therefore 0x3F. The question is what if we’d like to add multiple I2C LCDs to the I2C bus and control them with Arduino, how is that possible?

First of all, any I2C device on the bus must have a unique address. And therefore, we need to change the I2C address of the PCF8574 module if we’d like to add multiple units of it on the same I2C bus. Let’s next see how to do it!

Change I2C LCD Address

The I2C LCD interface (PCF8574) has 3 solder pads on the module’s board which control the value of the last 3 digits in the 7-Bit address of the device (A0 – A1 – A2). The pins are by default (internally) pulled up to HIGH (1), but if we short the solder pads together, this will drive the corresponding address bit pin to LOW (0). And that’s how we can change the device address.

ESP32 Multi I2C LCD Arduino Example

You can use the interactive tool below to check the I2C LCD device address after soldering any of the solder pads (A0, A1, or A2). There are 8 different combinations, which means we can connect up to 8 different I2C LCDs on the same bus with a single Arduino board and control all of them at the same time.

I2C LCD Address (Texas Instruments’ PCF8574)

0
1
0
0
A2
A1
A0
1
1
1

I2C LCD Address (NXP’s PCF8574)

0
1
1
1
A2
A1
A0
1
1
1
❕ Note

The I2C LCD module has a default I2C device address of either 0x27 or 0x3F depending on the hardware manufacturer. If you’re not quite sure about the device address, you can use this Arduino I2C Scanner application to detect the exact device address.

Using the solder pads on the PCD8574 module will enable you to set the low 3 address bits (A0-A1-A2). This means we can have up to 8 different address combinations and consequently be able to connect up to 8 I2C LCD units on the same I2C bus and control them with only one Arduino.


Arduino I2C LCD Interfacing

Now, let’s move to interfacing the I2C LCD 16×2 display with Arduino. Let’s check the pinout, wiring diagram, LCD contrast control, and the I2C LCD device address.

I2C LCD Pinout

The I2C LCD Display has only four pins. The pinout is shown below:

Arduino-I2C-LCD-Pinout

GND is the ground pin.

Vcc is the LCD’s power supply input pin (connects to +5v).

SDA is the serial data line for the I2C LCD interface.

SCL is the serial clock line for the I2C LCD interface.

Wiring I2C LCD With Arduino

Here is the wiring diagram for the I2C LCD display with Arduino that we’ll be using in the examples hereafter in this tutorial.

Arduino-I2C-LCD-Wiring-Diagram

And here is a summary table for different Arduino Boards -> I2C LCD connections.

SDASCL
Arduino UNO, Nano, Pro MiniA4A5
Arduino Mega2021
Arduino Leonardo, Micro23

Contrast Adjustment For I2C LCD

After connecting the I2C LCD module, you’ll be able to control the LCD contrast by using the PCF8574 module’s on-board potentiometer. Turn it to the right and to the left until you feel satisfied with the current contrast level.

Get The I2C LCD Address

If you’re not quite sure about the I2C LCD’s device address, you can use the code example below and run it on your Arduino board after connecting the I2C LCD display to your Arduino. It’ll automatically detect and print out the I2C device address for the LCD over the serial monitor.

And here is the result after running this code example on my Arduino UNO board.

Arduino-I2C-LCD-Address-Detect

💡 Also Read
Arduino I2C Scanner (Address Finder)

This article will give you more in-depth information about the Arduino I2C Scanner application and how to use it to detect various I2C devices’ addresses.


Arduino I2C LCD Library Installation

You can download and install the Arduino I2C LCD library manually from GitHub, or alternatively, install it within the Arduino IDE itself. Just open the library manager. Tools > Manage Libraries > Search for LiquidCrystal I2C. Then, click Install and let it finish the installation.

Now, you can easily use the Arduino LiquidCrystal I2C LCD library and check the built-in examples for the library to help you get started.

We’ll move now to the practical code examples to test Arduino I2C LCD display.


Arduino I2C LCD Example

Now, let’s test what we’ve learned so far about the Arduino I2C LCD and create our first project to display numeric variables to the I2C LCD display. We’ll create a counter variable and print it to the LCD using the .print() function.

Which can also accept a lot of variable data types (strings, integers, float, double, etc). So luckily, we won’t be in need to do string manipulations and data type conversion to achieve the goals of this example project.

Wiring

This is the wiring diagram for the I2C LCD with Arduino UNO.

Arduino-I2C-LCD-Wiring-Diagram

Example Code

Here is the full code listing for this example.

Code Explanation

First of all, we need to include the Arduino Wire.h library to use the I2C communication module, then the LiquidCrystal_I2C.h library which we’ll be using to control the I2C LCD module (PCF8574).

Next, we’ll create an object of the LiquidCrystal_I2C class and define its parameters. The parameters for the LiquidCrystal_I2C object are the I2C device address (0x27), the number of LCD columns, and the number of LCD rows. Those are (16, 2) for 16×2 LCDs.

setup()

in the setup() function, we initialize the I2C LCD object ( MyLCD) using the .init() function. We also activate the LCD’s backlight by using the .backlight() function.

Then, we set the LCD cursor position to point to the first line, the first character cell. Any write operation to the LCD will start from the current cursor position value, that’s why it’s important to set it manually before attempting any write operation. To make sure that the text will be displayed exactly where we want it to be.

Next, we’ll print the first text message "Counter Value:" to the LCD starting from the current cursor position (0, 0). Using the .print() function.

loop()

in the loop() function, we’ll point to the first character location on the second row (line) of the LCD. And write the Counter variable to the LCD using the .print() function.

We also increment the Counter variable and insert a small time delay before repeating the same instructions over and over again.

Simulation

Here is the simulation result for this project on the TinkerCAD simulator.

You can check this simulation project on TinkerCAD using this link.

Testing Results

Here is the result of testing this project code example on my Arduino UNO board.


Arduino I2C LCD Scrolling Text Example

In this example, we’ll print some text messages and shift the entire I2C LCD display to create a text-scrolling effect. We’ll use the scrollDisplayLeft() and scrollDisplayRight() functions to create the scrolling effect.

❕ Note

The LCD’s internal Display data RAM (DDRAM) stores display data represented in 8-bit character codes. Its extended capacity is 80 × 8 bits or 80 characters. The area in display data RAM (DDRAM) that is not used for display can be used as general data RAM.

Therefore, whatever data you send to the DDRAM, it’ll get displayed on the LCD. As long as the characters count is below 32 (for 16×2 LCD), it’ll be visible. Otherwise, written characters are stored in the DDRAM but not visible.

Shifting the LCD display moves the data in the DDRAM in a circular way, when it reaches the end of the RAM space, you’ll find your text coming from the other LCD end. To test this, keep shifting the LCD text to the left maybe 100 times. When the buffer reaches the limit, you’ll find your text message coming from the right side of the LCD. Why? because it’s circulating through the DDRAM.

Wiring

Exactly the same as the previous example project.

Example Code

Here is the full code listing for this example.

Code Explanation

First of all, we need to include the Arduino Wire.h library to use the I2C communication module, then the LiquidCrystal_I2C.h library which we’ll be using to control the I2C LCD module (PCF8574).

Next, we’ll create an object of the LiquidCrystal_I2C class and define its parameters. The parameters for the LiquidCrystal_I2C object are the I2C device address (0x27), the number of LCD columns, and the number of LCD rows. Those are (16, 2) for 16×2 LCDs.

setup()

in the setup() function, we initialize the I2C LCD object ( MyLCD) using the .init() function. We also activate the LCD’s backlight by using the .backlight() function.

Next, we’ll print the first text messages " Arduino LCD " and “ DeepBlueMbedded” to the LCD on lines 1 and 2 respectively. Using the .print() function.

loop()

in the loop() function, we’ll shift the entire display to the right side 10 times using a for loop and the scrollDisplayRight() function from the LCD LiquidCrystal library. The inserted delay here is to allow us to see the scrolling effect, and you can definitely change it to make the scrolling effect even faster or slower.

Next, we’ll repeat the same step but the shifting will be in the opposite direction (left) and the code logic will be repeated forever.

Simulation

Here is the simulation result for this project on the TinkerCAD simulator.

You can check this simulation project on TinkerCAD using this link.

Testing Results

Here is the result for testing this project code example on my Arduino UNO board.


Arduino I2C LCD Custom Characters Display

In this example project, we’ll create some custom characters (emojis and icons) and send them to the I2C LCD display. It has an internal CGRAM that can hold up to 8 custom characters at maximum and you’ll learn how to use it in this example project.

❕ Note

The LCD has an internal Character Generator ROM (CGROM). The character generator ROM generates (5×8) dots or (5×10) dot character patterns from 8-bit character codes. It can generate 208 (5×8) dot character patterns and 32 (5×10) dot character patterns. User-defined character patterns are also available by mask-programmed ROM.

Given that the CGROM has 208 character patterns for (5×8) dot displays, this means that not all the 255 ASCII table characters are available by default in the LCD display. You can refer to this tutorial for more information about this. As we’re more interested in the LCD’s internal CGRAM.

In the Character Generator RAM (CGRAM), the user can write new custom character patterns. For (5×8) dots display, eight-character patterns can be written at maximum. Only 8 custom character seems like a small space but it’s what it’s and we’ll see how to use it in this example project.

Arduino LCD Custom Character Generator

You can use this online LCD Custom Character Generator Tool and it’ll give you the Arduino C-Code for it, which you can easily copy and paste into your project code. And here is how to use it:

Click on the pixels to draw your custom LCD character, you can invert or clear the entire display cell if you want with the buttons below. If you’re satisfied with how your icon/emoji looks, you can copy the code and you’re good to go. Here are some example custom characters generated by this tool.

Arduino-LCD-16x2-Custom-Character-Generation-Display

I used my custom LCD character generator tool to create the above icons/emojis (heart, speaker, smiley face, notification bell, battery level indicator). We’ll display all of those icons in this example project to show you how it’s done in Arduino code.

Wiring

Exactly the same as the previous example projects.

Example Code

Here is the full code listing for this example.

Code Explanation

First of all, we need to include the Arduino Wire.h library to use the I2C communication module, then the LiquidCrystal_I2C.h library which we’ll be using to control the I2C LCD module (PCF8574).

Next, we’ll create an object of the LiquidCrystal_I2C class and define its parameters. The parameters for the LiquidCrystal_I2C object are the I2C device address (0x27), the number of LCD columns, and the number of LCD rows. Those are (16, 2) for 16×2 LCDs.

We’ll also define the byte array for the 8 custom characters that we’ve previously generated using the online tool.

setup()

in the setup() function, we initialize the I2C LCD object ( MyLCD) using the .init() function.

Then, we send the 8 custom characters byte-arrays to the LCD to be stored in its CGRAM memory.

Next, we’ll clear the entire LCD display screen before writing. This step also moves the cursor to the home position (0, 0).

And finally, we’ll print the LCD custom characters. This is not a usual print command, it’s a command for the LCD to print the custom character saved in a specific location in the CGRAM memory. The following line of code tells the LCD to print the custom character saved in the CGRAM address location 0.

And similarly, we’ll do the same for the rest of the custom characters saved in the CGRAM address location 0 up to 7.

loop()

in the loop() function, nothing needs to be done.

Simulation

Here is the simulation result for this project on the TinkerCAD simulator.

Arduino-I2C-LCD-Wiring-Diagram

You can check this simulation project on TinkerCAD using this link.

Testing Results

Here is the result of testing this project code example on my Arduino UNO board.

Arduino-I2C-LCD-Custom-Character-Display


Arduino Multiple I2C LCD Displays Example

In this example project, we’ll connect multiple I2C LCDs with Arduino and write different text messages to each of them. Obviously, we need to change the I2C LCD device address using the solder pads on the PCF8574 module’s board.

In this example, I’ll connect two I2C LCD displays with Arduino UNO. Therefore, I’ll leave one of them with the default address of 0x27 and will change the other I2C LCD’s address by shorting the A0 solder pads. This will change its address to 0x26 as shown in the figure below.

ESP32 Multi I2C LCD Arduino Example2

Example Code

Here is the full code listing for this example.

Code Explanation

First of all, we need to include the Arduino Wire.h library to use the I2C communication module, then the LiquidCrystal_I2C.h library which we’ll be using to control the I2C LCD module (PCF8574).

Next, we’ll create two objects of the LiquidCrystal_I2C class and define their parameters. The parameters for the LiquidCrystal_I2C object are the I2C device address (0x27 and 0x26), the number of LCD columns, and the number of LCD rows.

setup()

in the setup() function, we initialize the I2C LCD objects using the .init() function. We also activate the LCDs’ backlights by using the .backlight() function.

Then, we print a text message to LCD1 and another different message to LCD2.

loop()

in the loop() function, nothing needs to be done.

Simulation

Here is the simulation result for this project on the TinkerCAD simulator.

Arduino-Multiple-I2C-LCD-Displays-Example

You can check this simulation project on TinkerCAD using this link.

Testing Results

Here is the result of testing this project code example on my Arduino UNO board.

Arduino-Multiple-I2C-LCD-Displays


Arduino LiquidCrystal_I2C Library Useful Function

Here is a summarized list of the most important and useful functions in the Arduino I2C LCD LiquidCrystal_I2C.h library that you’d need to use in your Arduino projects.

LiquidCrystal_I2C Library Function Function Description
lcd.init(); Initializes the interface to the I2C LCD screen, and specifies the I2C device address, and dimensions (width and height) of the display. the .init() function needs to be called before any other LCD library commands.
lcd.backlight(); Enabled (Activates) the LCD’s backlight LED.
lcd.noBacklight(); Disables (Deactivates) the LCD’s backlight LED.
lcd.clear(); Clears the LCD screen and points the cursor to the home position (in the upper-left corner).
lcd.home(); Sets the cursor to the home position (in the upper-left of the LCD) without clearing the text on the display.
lcd.setCursor(col, row); Position the LCD cursor to a desired location.
lcd.noCursor(); Hides the LCD cursor.
lcd.cursor(); Display the LCD cursor if it has been hidden.
lcd.blink(); Display the blinking LCD cursor. If used in combination with the cursor() function, the result will depend on the particular display device.
lcd.noBlink(); Turns off the blinking LCD cursor.
lcd.noDisplay(); Turns off the LCD display, without losing the text currently shown on it. This can be done to save some power if needed.
lcd.display(); Turns on the LCD display, after it’s been turned off with the noDisplay() function. This will restore the text (and cursor) that was on the display.
lcd.scrollDisplayLeft();

Scrolls the contents of the display (text and cursor) one space to the left.

lcd.scrollDisplayRight();

Scrolls the contents of the display (text and cursor) one space to the right.

lcd.autoscroll();

Turns on automatic scrolling of the LCD. This causes each character output to the display to push previous characters over by one space. If the current text direction is left-to-right (the default), the display scrolls to the left; if the current direction is right-to-left, the display scrolls to the right. This has the effect of outputting each new character to the same location on the LCD.

lcd.noAutoscroll();

Turns off the automatic scrolling feature of the LCD.

lcd.leftToRight();

Set the direction for text written to the LCD to left-to-right, the default. This means that subsequent characters written to the display will go from left to right, but does not affect previously-output text.

lcd.rightToLeft();

Set the direction for text written to the LCD to right-to-left (the default is left-to-right). This means that subsequent characters written to the display will go from right to left, but does not affect previously-output text.

You can also refer to LiquidCrystal_I2C library page for more information and examples of the available APIs (functions) in this library.


Arduino I2C LCD Common Issues Troubleshooting

In this section, we’ll discuss some of the most common Arduino I2C LCD 16×2 interfacing issues and how to troubleshoot those issues if you’re facing any of them in your project.

Garbage Characters Display

If your LCD is displaying garbage characters, it’s a strong indicator that there is an issue with data communication between your Arduino board and the I2C LCD module itself. Make sure your connections are correct and the device address is correct. The Default I2C address is 0x27 for Ti’s PCF8574 and 0x3F for NXP’s PCF8574 modules.

LCD Showing Black Boxes or Blank Display

This can be a contrast issue at the Vo pin, so make sure you’re connecting the contrast control potentiometer and turn it to the right and left until it’s properly set to an acceptable level.

Contrast is Ok, But Still Blank Display

This can be a power supply issue, make sure you’re connected to a stable +5v power supply. Sometimes powering from a USB port in a computer can cause power issues like this, so try using a power bank or a proper power supply and check if the issue is still persistent.

Using a poor power supply USB port, poor quality USB cables, or even USB extender cables can cause all sorts of power issues. And the LCD display module is sensitive to such issues that you’d not detect during LEDs and buttons example projects.


Parts List

Here is the full components list for all parts that you’d need in order to perform the practical LABs mentioned here in this article and for the whole Arduino Programming series of tutorials found here on DeepBlueMbedded. Please, note that those are affiliate links and we’ll receive a small commission on your purchase at no additional cost to you, and it’d definitely support our work.

Download Attachments

You can download all attachment files for this Article/Tutorial (project files, schematics, code, etc..) using the link below. Please consider supporting my work through the various support options listed in the link down below. Every small donation helps to keep this website up and running and ultimately supports our community.


Wrap Up

To conclude this tutorial, we can say that the Arduino LiquidCrystal_I2C library eases the process of interfacing Arduino with I2C LCD 16×2 display modules. You can even use it with different sizes of LCD displays like 16×4 or 20×4. This tutorial is a fundamental part of our Arduino Series of Tutorials because we’ll use it in so many tutorials and projects hereafter. So make sure, you’ve learned all the concepts and implemented the practice examples whether on your Arduino board or at least in the simulation environment.

If you’re just starting with Arduino, check out the Arduino Getting Started [Ultimate Guide] here.

And follow this Arduino Series of Tutorials to learn more about Arduino Programming.

💡 Also Read
Arduino I2C Communication Tutorial (Wire Library)

This is the ultimate guide for Arduino I2C communication. It’ll give you an in-depth explanation of Arduino I2C fundamentals, wire library functions, Arduino I2C device programming, and a handful of Arduino I2C communication example projects.

Share This Page With Your Network!
Join Our +25,000 Newsletter Subscribers!

Stay Updated With All New Content Releases. You Also Get Occasional FREE Coupon Codes For Courses & Other Stuff!

Photo of author
Author
Khaled Magdy
Embedded systems engineer with several years of experience in embedded software and hardware design. I work as an embedded SW engineer in the Automotive & e-Mobility industry. However, I still do Hardware design and SW development for DSP, Control Systems, Robotics, AI/ML, and other fields I'm passionate about.
I love reading, writing, creating projects, and teaching. A reader by day and a writer by night, it's my lifestyle. I believe that the combination of brilliant minds, bold ideas, and a complete disregard for what is possible, can and will change the world! I will be there when it happens, will you?