Product Description
Test some examples after adding this LiquidCrystal I2C LCD to your Arduino IDE Libraries .....More... (from : lastminuteengineers.com).
Interface an I2C LCD with Arduino

If you’ve ever tried connecting an LCD display to an Arduino, you’ve probably noticed it requires quite a few Arduino pins. Even when using 4-bit mode, you still need seven connections – which takes up about half of the Arduino’s available digital I/O pins.
A better solution is to use an I2C LCD display. It only needs two pins that aren’t even part of the regular digital I/O pin set. Even better, these pins can be shared with other I2C devices. This makes your wiring much simpler and saves those valuable pins for connecting other sensors or components in your projects.
Hardware Overview
A typical I2C LCD display consists of two main parts: an HD44780-based character LCD display and an I2C LCD adapter. Let’s explore both of these components in more detail.
Character LCD Display
Character LCDs are specially designed to display letters, numbers, and symbols. A 16×2 character LCD, for example, can show 16 characters across each line, with two lines total.

If you look very closely at the screen, you’ll notice small rectangular boxes for each character position. Inside each of these rectangles is a grid of 5×8 tiny dots or pixels. These pixels light up in different patterns to form different letters, numbers, or symbols.
For more in-depth information about character LCD displays, check out comprehensive guide.
I2C LCD Adapter
The key component of this adapter is an 8-bit I/O expander chip called PCF8574. This clever chip converts the I2C data from your Arduino into the parallel data that the LCD display needs to function.

The adapter board also includes a small trimpot that lets you make fine adjustments to the display’s contrast.

You’ll notice there’s a jumper on the board that supplies power to the backlight. If you want to control how bright the backlight is, you can simply remove this jumper and connect an external voltage source to the header pin marked ‘LED’.
I2C Address of LCD
If you have multiple devices on the same I2C bus, you may need to set a different I2C address for the LCD adapter to avoid conflicts with other I2C devices.
For this purpose, the adapter comes with three solder jumpers/pads (labeled A0, A1, and A2). For a single LCD, you can leave these untouched; however, if you connect multiple I2C devices or LCDs, you’ll need to make sure each has a unique address by modifying these jumpers. You can change the address by shorting a jumper with a small blob of solder.

An important thing to know is that different companies, like Texas Instruments and NXP Semiconductors, make the same PCF8574 chip. The I2C address of your LCD depends on which company manufactured the chip.
If your LCD has Texas Instruments’ PCF8574 chip:
According to Texas Instruments’ datasheet, the three address selection bits (A0, A1, and A2) are located at the end of the 7-bit I2C address register.

Since there are three address inputs that can be either HIGH or LOW, there are eight possible combinations (2^3 = 8) of addresses.
All three address inputs are pulled HIGH by default using onboard pullup resistors. This gives the PCF8574 a default I2C address of 0x27.
When you short a solder jumper, you pull that address input LOW. If you were to short all three jumpers, the address would change to 0x20. So the range of possible addresses goes from 0x20 to 0x27.
You can set different I2C addresses according to this table:

If your LCD has NXP’s PCF8574 chip:
According to NXP Semiconductors’ datasheet, the three address selection bits (A0, A1, and A2) are also located at the end of the 7-bit I2C address register. However, the remaining bits in the address register are different from the Texas Instruments chip.

Just like with the Texas Instruments chip, there are eight possible address combinations since the three inputs can be either HIGH or LOW.
All three address inputs are pulled HIGH by default using onboard pullup resistors. This gives the PCF8574 a default I2C address of 0x3F.
When you short a solder jumper, you pull that address input LOW. If you were to short all three jumpers, the address would change to 0x38. So the range of possible addresses goes from 0x38 to 0x3F.
You can set different I2C addresses according to this table:

So the I2C address of your LCD is most likely 0x27 or 0x3F. If you’re not sure what your LCD’s I2C address is, don’t worry! There’s an easy way to figure it out, which you’ll learn about later in this tutorial.
I2C LCD Display Pinout
The I2C LCD Display has only four pins. The following is the pinout:

GND is a ground pin.
VCC is the power supply pin. Connect it to the 5V output of the Arduino or an external 5V power supply.
SDA is the I2C data pin.
SCL is the I2C clock pin.
Wiring an I2C LCD Display to an Arduino
Connecting an I2C LCD is much simpler than connecting a standard LCD. You only need to connect four pins instead of many more.
First, connect the VCC pin to the Arduino’s 5V output and the GND pin to the Arduino’s ground.
Next, we need to connect the pins used for I2C communication. It’s important to know that different Arduino boards have different I2C pins, and these must be connected correctly. On Arduino boards with the R3 layout, the SDA (data line) and SCL (clock line) pins are also found on the pin headers near the AREF pin. However, internally, they are the same as the A4 (SDA) and A5 (SCL) pins.
The table below shows you all the pin connections you need to make:
I2C LCD | Arduino | |
VCC | 5V | |
GND | GND | |
SCL | SCL or A5 | |
SDA | SDA or A4 |
This diagram shows you exactly how to connect everything:

Adjusting The LCD Contrast
After you finish wiring the LCD to your Arduino, you’ll need to adjust the contrast of the LCD display. Look for a small blue trimpot on the I2C adapter board – this controls the LCD’s contrast.
Now, power up your Arduino. You should see the backlight glow up right away. Take a small screwdriver and gently turn the potentiometer knob. As you adjust it, you’ll start to see the first row of rectangles appear on the screen. These rectangles are where characters will show up. If you can see those rectangles clearly, congratulations—your LCD is working perfectly and is ready for you to display text!

Determining the I2C Address
Before we jump into the example code, you’ll need to know your LCD’s I2C address so you can properly communicate with it. As we mentioned earlier, your LCD’s I2C address is probably either 0x27 or 0x3F. You might find this address printed on a sticker that came with your LCD or listed in the product information. But don’t worry if you can’t find this information anywhere! There’s an easy solution – you can run a simple I2C scanner sketch that will help you discover the correct address automatically. Here’s how:
You can find this sketch by clicking on File > Examples > Wire > i2c_scanner in the Arduino IDE menu.

Load the i2c_scanner sketch into your Arduino IDE.
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
while (!Serial); // Leonardo: wait for serial monitor
Serial.println("\nI2C Scanner");
}
void loop() {
int nDevices = 0;
Serial.println("Scanning...");
for (byte address = 1; address < 127; ++address) {
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
byte error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16) {
Serial.print("0");
}
Serial.print(address, HEX);
Serial.println(" !");
++nDevices;
} else if (error == 4) {
Serial.print("Unknown error at address 0x");
if (address < 16) {
Serial.print("0");
}
Serial.println(address, HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
} else {
Serial.println("done\n");
}
delay(5000); // Wait 5 seconds for next scan
}
After uploading the sketch to your Arduino, open the serial monitor and set it to 9600 baud. In a few moments, you should see the I2C address of your LCD display appear on the screen.

Be sure to write down this address somewhere safe. You’ll need it when we work with the LCD in later examples.
Library Installation
To control the I2C LCD, we will use the Arduino LiquidCrystal_I2C library. This library makes writing to the LCD much easier because it handles all the complicated I2C communication in the background. There are several versions of this library available, but one of the most reliable ones is the version created by Frank de Brabander.
To install the library:
1-First open your Arduino IDE program. Then click on the Library Manager icon on the left sidebar.
2-Type “liquidcrystal” in the search box to filter your results.
3-Look for the “LiquidCrystal I2C library” library created by Frank de Brabander.
4-Click the Install button to add it to your Arduino IDE.

Basic Arduino Sketch – Hello World
With the hardware connected and the library installed, we can write a simple Arduino sketch to display text on the LCD. In this example, we’ll print ‘Hello World!’ on the first line of the LCD and ‘LCD Tutorial’ on the second line.
Before you upload the sketch, you need to make two important changes to make it work with your specific LCD. You must enter the correct I2C address of your LCD (which we found earlier) and specify the display dimensions in the LiquidCrystal_I2C()
constructor. If you’re using a 16×2 character LCD, enter 16 and 2; if you’re using a 20×4 character LCD, enter 20 and 4.
// enter the I2C address and the dimensions of your LCD here
LiquidCrystal_I2C lcd(0x3F, 16, 2);
Once you’ve made these changes, you’re ready to try the complete sketch:
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,16,2); // set the LCD address to 0x3F for a 16 chars and 2 line display
void setup() {
lcd.init();
lcd.clear();
lcd.backlight(); // Make sure backlight is on
// Print a message on both lines of the LCD.
lcd.setCursor(2,0); //Set cursor to character 2 on line 0
lcd.print("Hello world!");
lcd.setCursor(2,1); //Move cursor to character 2 on line 1
lcd.print("LCD Tutorial");
}
void loop() {
}
After uploading this code to your Arduino, this is what you should see on the screen:

Code Explanation:
The sketch begins by including the LiquidCrystal_I2C library, which gives us all the functions we need to control the LCD.
#include <LiquidCrystal_I2C.h>
Next, we create an object of the LiquidCrystal_I2C class. The LiquidCrystal_I2C constructor needs three pieces of information: the I2C address, the number of columns, and the number of rows of your display.
LiquidCrystal_I2C lcd(0x3F,16,2);
In the setup function, we call three important functions. First, the init()
function initializes the interface to the LCD. Second, the clear()
function erases anything on the LCD screen and moves the cursor to the upper-left corner. Third, the backlight()
function turns on the LCD’s backlight so we can see the text.
lcd.init();
lcd.clear();
lcd.backlight();
The setCursor(2, 0)
function moves the cursor to the third column of the first row. (Remember that counting starts at 0, so column 2 is actually the third column.) The cursor position tells the LCD where to place new text on the screen. The upper left corner is considered position (0,0).
lcd.setCursor(2,0);
Next, we use the print()
function to display the text “Hello world!” on the LCD.
lcd.print("Hello world!");
Similarly, the next two lines of code move the cursor to the third column of the second row and print ‘LCD Tutorial’ on the LCD.
lcd.setCursor(2,1);
lcd.print("LCD Tutorial");
Scrolling Text Example
If you have a message that is longer than 16 characters, or you want to create a scrolling marquee effect, you can use the scrollDisplayLeft()
or scrollDisplayRight()
functions in a loop to move the text across the screen.
Arduino Example Code
The sketch below shows how to scroll a message continuously to the left:
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,16,2); // set the LCD address to 0x3F for a 16 chars and 2 line display
void setup() {
lcd.init();
lcd.clear();
lcd.backlight(); // Make sure backlight is on
// Print a message
lcd.print("Scrolling Text Demo");
delay(1000); // pause to read the message initially
}
void loop() {
lcd.scrollDisplayLeft(); // scroll everything to the left by one position
delay(300); // small delay for visible scrolling speed
}
When you upload this code to your Arduino, your LCD will display something like this:

Code Explanation:
In this example, we print a message that is 19 characters long (“Scrolling Text Demo”) to the LCD. Since the display can only show 16 characters at once, only the first 16 characters will be visible initially.
// Print a message to the LCD
lcd.print("Scrolling Text Demo");
In the loop()
function, we call lcd.scrollDisplayLeft()
, which moves the entire display content one space to the left. By repeating this with a short delay between each scroll, the message appears to move smoothly across the screen.
void loop() {
lcd.scrollDisplayLeft(); // scroll everything to the left by one position
delay(300); // small delay for visible scrolling speed
}
As the text scrolls, characters that move off the left edge disappear, and blank spaces appear on the right side of the screen. If you want the message to continuously loop, you would need to add code that reprints the message periodically.
To scroll in the opposite direction (right to left), you can use lcd.scrollDisplayRight()
instead.
Other useful functions of the LiquidCrystal_I2C Library
The LiquidCrystal_I2C object gives you many helpful functions to control your LCD. Here are some of the most useful ones:
lcd.home()
moves the cursor back to the upper-left corner of the LCD (the first position on the first row). Unlikeclear()
, it doesn’t erase what’s already on the screen – it just moves the cursor to the starting position.lcd.blink()
andlcd.noBlink()
turn on or off a blinking block cursor. When turned on withblink()
, you’ll see a solid block that flashes on and off at the current cursor position. This is great for getting the user’s attention or showing where text will appear next. If you don’t want this blinking block, usenoBlink()
to turn it off.lcd.cursor()
andlcd.noCursor()
control whether an underscore line (_
) appears at the position where the next character will be written. Thecursor()
function shows this line, whilenoCursor()
hides it. This is different from the blinking block – it’s just a simple line showing where the next character will go.-
lcd.display()
andlcd.noDisplay()
let you turn the entire display on or off without erasing anything. When you usenoDisplay()
, the screen goes blank, but all the text stays stored in the LCD’s memory. When you calldisplay()
again, everything reappears! This is perfect for creating blinking effects or saving power when the display isn’t needed.
Try experimenting with these functions in your own code to see how they work. They’ll help you create more interactive and dynamic displays for your projects!
Create and Display Custom Characters
Sometimes you may want to display special characters that aren’t part of the standard alphabet or numbers – for example, symbols like a smiley face, a degree symbol (°) for temperature readings, or fun icons like hearts, music notes, or arrows.
-
The good news is that HD44780 LCDs allow you to create up to 8 custom characters of your own design! As we learned earlier in this tutorial, each character on the LCD is displayed using a small grid of pixels arranged in a 5×8 pattern (5 pixels wide by 8 pixels tall). To create your own character, you’ll need to decide which of these tiny dots should be turned on and which should be off.
To create your custom character, you first need to make an 8-byte array in your code. Each byte in this array represents one horizontal row in your character, starting from the top row and going down to the bottom row. For each byte, you’ll use the bits (the 1s and 0s in binary) to indicate which pixels should be ON (1) and which should be OFF (0). Only the first 5 bits of each byte are used since the character is 5 pixels wide.
Once you’ve designed your character by setting up this array, you can use the
createChar()
function to store your custom character into the LCD’s CGRAM (Character Generator RAM), which is a special memory area designed just for holding custom characters. -
Now, let’s go ahead and create some cool custom characters for your projects!
CGROM vs. CGRAM
All Hitachi HD44780 driver-based LCDs have two types of memory: CGROM (Character Generator Read-Only Memory) and CGRAM (Character Generator Random Access Memory).
CGROM is non-volatile memory, which means it keeps its data even when power is turned off. It stores predefined dot patterns for standard ASCII characters, such as letters, numbers, and common symbols. When you want to display an “A” on the screen, you send the code for “A” (which is 0x41 in hexadecimal), and the LCD controller looks up the dot pattern for “A” in its CGROM and displays it. This makes showing regular characters super quick and easy!
CGRAM, however, is volatile memory, so it loses its data when power is removed. This memory is flexible and lets you store custom dot patterns that aren’t part of the built-in set. For instance, you can design your own symbols, icons, or unique characters for your project. However, CGRAM has limited space – only 64 bytes total. On a standard 5×8 pixel LCD, this means you can only store 8 custom characters (since each character needs 8 bytes). If you’re using a 5×10 pixel LCD, you can only store 4 custom characters because each one needs more memory.
In summary, CGROM is read-only with fixed character patterns that can’t be changed, while CGRAM is writable, allowing you to create and save custom characters whenever you need them.
Custom Character Generator
Creating custom characters has never been easier! We’ve developed a helpful tool called the Custom Character Generator. See the blue grid below? You can click on any pixel to turn it on or off, and as you do this, the code for your character is automatically created right next to the grid. You can copy this code directly into your Arduino sketch.
byte Character[8] = { 0b10000,
0b01000,
0b00100,
0b00010,
0b00001,
0b00010,
0b01100,
0b10000}; The possibilities for what you can create are almost endless! You could make arrows, simple animals, game characters, weather symbols, or any small icon you can fit in the 5×8 grid. The only limitation is that the LiquidCrystal_I2C library only lets you use eight custom characters at one time. But don’t worry – eight different custom characters are still plenty to make your project unique and interesting!
Arduino Example Code
The sketch below shows you exactly how to display your custom characters on the LCD:
#include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x3F, 16, 2); // set the LCD address to 0x3F for a 16 chars and 2 line display // make some custom characters: byte Heart[8] = { 0b00000, 0b01010, 0b11111, 0b11111, 0b01110, 0b00100, 0b00000, 0b00000 }; byte Bell[8] = { 0b00100, 0b01110, 0b01110, 0b01110, 0b11111, 0b00000, 0b00100, 0b00000 }; byte Alien[8] = { 0b11111, 0b10101, 0b11111, 0b11111, 0b01110, 0b01010, 0b11011, 0b00000 }; byte Check[8] = { 0b00000, 0b00001, 0b00011, 0b10110, 0b11100, 0b01000, 0b00000, 0b00000 }; byte Speaker[8] = { 0b00001, 0b00011, 0b01111, 0b01111, 0b01111, 0b00011, 0b00001, 0b00000 }; byte Sound[8] = { 0b00001, 0b00011, 0b00101, 0b01001, 0b01001, 0b01011, 0b11011, 0b11000 }; byte Skull[8] = { 0b00000, 0b01110, 0b10101, 0b11011, 0b01110, 0b01110, 0b00000, 0b00000 }; byte Lock[8] = { 0b01110, 0b10001, 0b10001, 0b11111, 0b11011, 0b11011, 0b11111, 0b00000 }; void setup() { lcd.init(); // Make sure backlight is on lcd.backlight(); // create a new characters lcd.createChar(0, Heart); lcd.createChar(1, Bell); lcd.createChar(2, Alien); lcd.createChar(3, Check); lcd.createChar(4, Speaker); lcd.createChar(5, Sound); lcd.createChar(6, Skull); lcd.createChar(7, Lock); // Clears the LCD screen lcd.clear(); // Print a message to the lcd. lcd.print("Custom Character"); } // Print All the custom characters void loop() { lcd.setCursor(0, 1); lcd.write(0); lcd.setCursor(2, 1); lcd.write(1); lcd.setCursor(4, 1); lcd.write(2); lcd.setCursor(6, 1); lcd.write(3); lcd.setCursor(8, 1); lcd.write(4); lcd.setCursor(10, 1); lcd.write(5); lcd.setCursor(12, 1); lcd.write(6); lcd.setCursor(14, 1); lcd.write(7); }
When you upload this code to your Arduino, your LCD will display something like this:
Try it out and experiment with creating your own unique characters!
-
Code Explanation:
After including the LiquidCrystal_I2C library and setting up the LCD object, the code defines special arrays for our custom characters. Each array has exactly 8 bytes, and each byte controls one row of dots in our 5×8 character grid.
The example includes eight different custom characters. Let’s look at the
Heart[8]
array as an example:byte Heart[8] = { 0b00000, 0b01010, 0b11111, 0b11111, 0b01110, 0b00100, 0b00000, 0b00000 };
Each line represents one row of pixels, starting from the top of the character. The “
0b
” at the beginning just tells Arduino this is a binary number (made of 0s and 1s). Each 0 means “pixel off” and each 1 means “pixel on.” If you look carefully at the pattern, you can see how the 1s form the shape of a heart!In the setup section of the code, we use the
createChar()
function to store our custom character in the LCD’s memory. This function needs two pieces of information: A number between 0 and 7 (which tells the LCD which of the eight available memory slot to use) and the name of the array that contains our character designThe code below stores our heart design in slot 0 of the LCD’s CGRAM memory.
// create a new character lcd.createChar(0, Heart);
Finally, in the loop section, we display our custom character using the
write()
function. We tell it which character to display by passing the memory slot number:// byte(0) represents Heart character. lcd.write(byte(0));