How to Use I2C LCD with ESP32 on Arduino IDE (ESP8266 compatible)

This tutorial shows how to use the I2C LCD (Liquid Crystal Display) with the ESP32 using Arduino IDE. We’ll show you how to wire the display, install the library and try sample code to write text on the LCD: static text, and scroll long messages. You can also use this guide with the ESP8266.

16×2 I2C Liquid Crystal Display

For this tutorial we’ll be using a 16×2 I2C LCD display, but LCDs with other sizes should also work.

The advantage of using an I2C LCD is that the wiring is really simple. You just need to wire the SDA and SCL pins.

Additionally, it comes with a built-in potentiometer you can use to adjust the contrast between the background and the characters on the LCD. On a “regular” LCD you need to add a potentiometer to the circuit to adjust the contrast.

Parts Required

To follow this tutorial you need these parts:

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Wiring the LCD to the ESP32

This display uses I2C communication, which makes wiring really simple.

Wire your LCD to the ESP32 by following the next schematic diagram. We’re using the ESP32 default I2C pins (GPIO 21 and GPIO 22).

You can also use the following table as a reference.

I2C LCD ESP32
GND GND
VCC VIN
SDA GPIO 21
SCL GPIO 22

Wiring the LCD to the ESP8266

You can also wire your LCD to the ESP8266 by following the next schematic diagram. We’re using the ESP8266 default I2C pins (GPIO 4 and GPIO 5).

You can also use the following table as a reference.

I2C LCD ESP8266
GND GND
VCC VIN
SDA GPIO 4 (D2)
SCL GPIO 5 (D1)

Preparing the Arduino IDE

Before proceeding with the project, you need to install the ESP32 or ESP8266 add-on in the Arduino IDE.

Arduino IDE with ESP32

Follow one of the next guides to prepare your Arduino IDE to work with the ESP32:

Arduino IDE with ESP8266

To install the ESP8266 add-on in your Arduino IDE, read the following tutorial: How to Install the ESP8266 Board in Arduino IDE.

Installing the LiquidCrystal_I2C Library

There are several libraries that work with the I2C LCD. We’re using this library by Marco Schwartz. Follow the next steps to install the library:

  1. Click here to download the LiquidCrystal_I2C library. You should have a .zip folder in your Downloads
  2. Unzip the .zip folder and you should get LiquidCrystal_I2C-master folder
  3. Rename your folder from LiquidCrystal_I2C-master to LiquidCrystal_I2C
  4. Move the LiquidCrystal_I2C folder to your Arduino IDE installation libraries folder
  5. Finally, re-open your Arduino IDE

Getting the LCD Address

Before displaying text on the LCD, you need to find the LCD I2C address. With the LCD properly wired to the ESP32, upload the following I2C Scanner sketch.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

#include <Wire.h>
 
void setup() {
  Wire.begin();
  Serial.begin(115200);
  Serial.println("\nI2C Scanner");
}
 
void loop() {
  byte error, address;
  int nDevices;
  Serial.println("Scanning...");
  nDevices = 0;
  for(address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address<16) {
        Serial.print("0");
      }
      Serial.println(address,HEX);
      nDevices++;
    }
    else if (error==4) {
      Serial.print("Unknow 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);          
}

View raw code

After uploading the code, open the Serial Monitor at a baud rate of 115200. Press the ESP32 EN button. The I2C address should be displayed in the Serial Monitor.

In this case the address is 0x27. If you’re using a similar 16×2 display, you’ll probably get the same address.

Display Static Text on the LCD

Displaying static text on the LCD is very simple. All you have to do is select where you want the characters to be displayed on the screen, and then send the message to the display.

Here’s a very simple sketch example that displays “Hello, World!“.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

#include <LiquidCrystal_I2C.h>

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;

// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);  

void setup(){
  // initialize LCD
  lcd.init();
  // turn on LCD backlight                      
  lcd.backlight();
}

void loop(){
  // set cursor to first column, first row
  lcd.setCursor(0, 0);
  // print message
  lcd.print("Hello, World!");
  delay(1000);
  // clears the display to print new message
  lcd.clear();
  // set cursor to first column, second row
  lcd.setCursor(0,1);
  lcd.print("Hello, World!");
  delay(1000);
  lcd.clear(); 
}

View raw code

It displays the message in the first row, and then in the second row.

In this simple sketch we show you the most useful and important functions from the LiquidCrystal_I2C library. So, let’s take a quick look at how the code works.

How the code works

First, you need to include theLiquidCrystal_I2C library.

#include <LiquidCrystal_I2C.h>

The next two lines set the number of columns and rows of your LCD display. If you’re using a display with another size, you should modify those variables.

int lcdColumns = 16;
int lcdRows = 2;

Then, you need to set the display address, the number of columns and number of rows. You should use the display address you’ve found in the previous step.

LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

In the setup(), first initialize the display with the init() method.

lcd.init();

Then, turn on the LCD backlight, so that you’re able to read the characters on the display.

lcd.backlight();

To display a message on the screen, first you need to set the cursor to where you want your message to be written. The following line sets the cursor to the first column, first row.

lcd.setCursor(0, 0);

Note: 0 corresponds to the first column, 1 to the second column, and so on…

Then, you can finally print your message on the display using the print() method.

lcd.print("Hello, World!");

Wait one second, and then clean the display with the clear() method.

lcd.clear();

After that, set the cursor to a new position: first column, second row.

lcd.setCursor(0,1);

Then, the process is repeated.

So, here’s a summary of the functions to manipulate and write on the display:

  • lcd.init(): initializes the display
  • lcd.backlight(): turns the LCD backlight on
  • lcd.setCursor(int column, int row): sets the cursor to the specified column and row
  • lcd.print(String message): displays the message on the display
  • lcd.clear(): clears the display

This example works well to display static text no longer than 16 characters.

Display Scrolling Text on the LCD

Scrolling text on the LCD is specially useful when you want to display messages longer than 16 characters. The library comes with built-in functions that allows you to scroll text. However, many people experience problems with those functions because:

  • The function scrolls text on both rows. So, you can’t have a fixed row and a scrolling row;
  • It doesn’t work properly if you try to display messages longer than 16 characters.

So, we’ve created a sample sketch with a function you can use in your projects to scroll longer messages.

The following sketch displays a static message in the first row and a scrolling message longer than 16 characters in the second row.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

#include <LiquidCrystal_I2C.h>

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;

// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);  

String messageStatic = "Static message";
String messageToScroll = "This is a scrolling message with more than 16 characters";

// Function to scroll text
// The function acepts the following arguments:
// row: row number where the text will be displayed
// message: message to scroll
// delayTime: delay between each character shifting
// lcdColumns: number of columns of your LCD
void scrollText(int row, String message, int delayTime, int lcdColumns) {
  for (int i=0; i < lcdColumns; i++) {
    message = " " + message;  
  } 
  message = message + " "; 
  for (int pos = 0; pos < message.length(); pos++) {
    lcd.setCursor(0, row);
    lcd.print(message.substring(pos, pos + lcdColumns));
    delay(delayTime);
  }
}

void setup(){
  // initialize LCD
  lcd.init();
  // turn on LCD backlight                      
  lcd.backlight();
}

void loop(){
  // set cursor to first column, first row
  lcd.setCursor(0, 0);
  // print static message
  lcd.print(messageStatic);
  // print scrolling message
  scrollText(1, messageToScroll, 250, lcdColumns);
}

View raw code

After reading the previous section, you should be familiar on how this sketch works, so we’ll just take a look at the newly created function: scrollText()

void scrollText(int row, String message, int delayTime, int lcdColumns) {
  for (int i=0; i < lcdColumns; i++) {
    message = " " + message; 
  } 
  message = message + " "; 
  for (int pos = 0; pos < message.length(); pos++) {
    lcd.setCursor(0, row);
    lcd.print(message.substring(pos, pos + lcdColumns));
    delay(delayTime);
  }
}

To use this function you should pass four arguments:

  • row: row number where the text will be display
  • message: message to scroll
  • delayTime: delay between each character shifting. Higher delay times will result in slower text shifting, and lower delay times will result in faster text shifting.
  • lcdColumns: number of columns of your LCD

In our code, here’s how we use the scrollText() function:

scrollText(1, messageToScroll, 250, lcdColumns);

The messageToScroll variable is displayed in the second row (1 corresponds to the second row), with a delay time of 250 ms (the GIF image is speed up 1.5x).

Display Custom Characters

In a 16×2 LCD there are 32 blocks where you can display characters. Each block is made out of 5×8 tiny pixels. You can display custom characters by defining the state of each tiny pixel. For that, you can create a byte variable to hold  the state of each pixel.

To create your custom character, you can go here to generate the byte variable for your character. For example, a heart:

Copy the byte variable to your code (before the setup()). You can call it heart:

byte heart[8] = {
  0b00000,
  0b01010,
  0b11111,
  0b11111,
  0b11111,
  0b01110,
  0b00100,
  0b00000
};

Then, in the setup(), create a custom character using the createChar() function. This function accepts as arguments a location to allocate the char and the char variable as follows:

lcd.createChar(0, heart);

Then, in the loop(), set the cursor to where you want the character to be displayed:

lcd.setCursor(0, 0);

Use the write() method to display the character. Pass the location where the character is allocated, as follows:

lcd.write(0);

Wrapping Up

In summary, in this tutorial we’ve shown you how to use an I2C LCD display with the ESP32/ESP8266 with Arduino IDE: how to display static text, scrolling text and custom characters. This tutorial also works with the Arduino board, you just need to change the pin assignment to use the Arduino I2C pins.

We have other tutorials with ESP32 that you may find useful:

We hope you’ve found this tutorial useful. If you like ESP32 and you want to learn more, we recommend enrolling in Learn ESP32 with Arduino IDE course.

Thanks for reading.

February 1, 2019


Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »

Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »


Enjoyed this project? Stay updated by subscribing our weekly newsletter!

36 thoughts on “How to Use I2C LCD with ESP32 on Arduino IDE (ESP8266 compatible)”

  1. Thanks for this excellent tutorial! I was just trying to get I2C working for a project and this was very helpful. My display was VERY VERY faint, even with the potentiometer turned all the way up. Do you think powering it via 5V versus 3 might help with that problem?

  2. I tried this project but got an error during compilation. At the line

    LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

    this error came out during compilation:

    sketch_jan14c:14: error: invalid conversion from ‘int’ to ‘t_backlighPol’ [-fpermissive]

    LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

    ^

    In file included from C:\Users\KKC231~1.LIM\AppData\Local\Temp\arduino_modified_sketch_441632\sketch_jan14c.ino:6:0:

    C:\Users\K. K. Lim\Documents\Arduino\libraries\LiquidCrystal_I2C/LiquidCrystal_I2C.h:53:4: error: initializing argument 3 of ‘LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t, uint8_t, t_backlighPol)’ [-fpermissive]

    LiquidCrystal_I2C (uint8_t lcd_Addr, uint8_t backlighPin, t_backlighPol pol);

    ^

    C:\Users\K. K. Lim\Documents\Arduino\libraries\LiquidCrystal_I2C/LiquidCrystal_I2C.h: In function ‘void setup()’:

    C:\Users\K. K. Lim\Documents\Arduino\libraries\LiquidCrystal_I2C/LiquidCrystal_I2C.h:154:9: error: ‘int LiquidCrystal_I2C::init()’ is private

    int init();

    ^

    sketch_jan14c:18: error: within this context

    lcd.init();

    ^

    Multiple libraries were found for “Wire.h”
    Used: C:\Users\K. K. Lim\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.2\libraries\Wire
    Not used: C:\Users\K. K. Lim\Documents\Arduino\libraries\Wire
    exit status 1
    invalid conversion from ‘int’ to ‘t_backlighPol’ [-fpermissive]

    I have no idea what it means. Can you point out what is preventing the compilation.

    • Hi.
      There are several libraries for the Liquid Crystal I2C. Please make sure that you’re using the same library we use in this example.
      The library is available in this link: https://github.com/johnrickman/LiquidCrystal_I2C
      After downloading and installing the library as described in the instructions, try our example or one of their examples and see if it works.
      Regards,
      Sara

      • His Sara, Thanks for your reply. Actually I was wondering if I had used the wrong library as I found I got the same error with some other sketches. I will follow up on your suggestion. Thanks very much for taking the time to reply.

          • Your tutorials are great. I learned a lot from them. Adding some research on the Internet in Github and Instructables, I have just finished a Weather Monitor using the DS18B20 probe for temperature measurement and the BME280 for Humidity and Atmospheric pressure measurement. The project uses the NodeMCU/WeMos D1 and the results are displayed on a LCD2004 and also on Thingspeak. The display can also be on my local WLAN using NGROK which I learned from your book on Home Automation using the ESP 8266. Not very sophistacated software structure but it works!

          • Hi!
            That’s great! I’m really glad you’ve built that project on your own with the help of our tutorials.
            Thank you for you interest in our content and for supporting our work.
            Best regards,
            Sara 🙂

  3. my 1602 shows up in an i2scan program correctly at 21 SDA and 22 SCL with id 0x27. I have 4 of the boards. they light up, but it doesn’t display text. I have found ALL of your projects to be fully tested and clearly documented. How do I decide if Amazon sent me bad boards. While its almost always user error (me) I need to determine if the boards are bad. Thank you, Bradshaw, Buzzards Bay, MA, on the Cape Cod Canal

    • Hi.
      Sorry for taking so long to get back to you.
      Do you get text on any of the boards? Do you get any error on the serial monitor?
      Please make sure that you have the display wired properly and you are using the right library.
      Regards,
      Sara

      • I had the same error using
        banggood.com/Geekcreit-Doit-NodeMcu-Lua-ESP8266-ESP-12F-WIFI-Development-Board-p-985891.html?rmmds=myorder&cur_warehouse=CN

        and
        amazon.com/SODIAL-Interface-Module-PCF8574T-Arduino/dp/B072FJM1SL/ref=sr_1_4?ie=UTF8&qid=1549380540&sr=8-4&keywords=sodial+i2c+lcd+adapter

        Used this library successfully
        arduinolibraries.info/libraries/liquid-crystal_pcf8574

        • Hi Ben.

          Thanks for letting me know.
          So, the project didn’t work with the library we recommend, but it did work with that library that you’re pointing out?

          I’ll have to test this project again and see if it is working. It may be due to library updates or something. I’ll check that out.
          Thank you.

    • Hi.
      I don’t know the reason for that.
      But if you’re using a similar display, this address should probably work: 0x27
      Regards,
      Sara

  4. Hi,
    Using 3.3v with the lcd is too dim, Connecting the lcd to 5v, could it be risky damaging the esp? Do you need a level translator?
    Thanks,
    Ken

  5. Hi,
    There is an issue with using LCDs that have more than 2 rows.
    I tried with a 16 x 4 LCD with lcdRows set to 4.

    Writing to top 2 rows work as described.
    But writing to the 3rd row [ lcd.setCursor(0,2);] writes to the 3rd row, but shifted left 4 characters.

    Seems this library is optimised for 20 x 4 characters, and will need some work to modify it for other column values.

    This is because by its internal setup the 1st row carries over to the 3rd, and 2nd row to the 4th.

    The library has assumed 20 columns by default, after which it resets the column value to 0.

  6. Hi, In your connections diagram you have mentioned to connect
    I2C LCD ESP32
    SDA to GPIO21,
    SCL to GPIO22

    I have a Starglow 1602A LCD 16X2. Is it possible to connect LCD to ESP32 “without” the I2C module in between ?

Leave a Comment

Download our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.