Using a 16×2 I2C LCD display with ESP32

A few weeks ago, we examined the features of ESP32 module and built a simple hello world program to get ourselves familiar with the board. Today, we will continue our exploration of the ESP32 on a higher level as we will look at how to interface a 16×2 LCD with it.

I2C 16×2 LCD Display

Displays provide a fantastic way of providing feedback to users of any project and with the 16×2 LCD being one of the most popular displays among makers, and engineers, its probably the right way to start our exploration. For today’s tutorial, we will use an I2C based 16×2 LCD display because of the easy wiring it requires. It uses only four pins unlike the other versions of the display that requires at least 7 pins connected to the microcontroller board.

DOIT ESP32 DevKit V1

ESP32 comes in a module form, just like its predecessor, the ESP-12e, as a breakout board is usually needed to use the module. Thus when it’s going to be used in applications without a custom PCB, it is easier to use one of the development boards based on it. For today’s tutorial, we will use the DOIT ESP32 DevKit V1 which is one of the most popular ESP32 development boards.

To demonstrate the use of I2C driven LCD with the NodeMCU, we will examine how to display both static and scrolling messages on the LCD.

Required Components

The following components are required to build this project;

  1. DOIT ESP32 DevKit V1 board
  2. Breadboard
  3. A 16×2 I2C LCD display
  4. Jumper Wires

The breadboard requirement is optional as you can choose to connect the LCD directly to the DOIT devkit board using female-female jumper wires.

Schematics

The schematics for this project is relatively simple since we are connecting just the LCD to the DOIT Devkit v1. Since we are using I2C for communication, we will connect the pins of the LCD to the I2C pins of the DevKit. Connect the components as shown below.

 

Schematics

A pin map showing how the components are connected is shown below.

LCD – ESP32

GND - GND
VCC - 3.3v/Vin
SDA - D2(GPIO4)
SCL - D1 (GPIO 5)

Due to the power requirements of the LCD, it may not be bright enough when connected to the 3.3v pin of the ESP32. If that is the case, connect the VCC pin of the LCD to the Vin Pin of the ESP32 so it can draw power directly from the connected power source.

Detecting the I2C Address of the LCD

At this point, it is important to note that a special setup is required to enable you to use the Arduino IDE to program ESP32 based boards. We covered this in the introduction to ESP32 tutorial published a few weeks go. So, be sure to check it out.

To be able to easily write the code to interact with the I2C LCD display, we will use the I2C LCD library. The Library possesses functions and commands that make addressing the LCD easy. Download the I2C LCD library from the link attached and install on the Arduino IDE by simply extracting it into the Arduino’s library folder.

Before writing the code for the project, it’s important for us to know the I2C address of the LCD as we will be unable to talk to the display without it.

While some of the LCDs come with the address indicated on it or provided by the seller, in cases where this is not available, you can determine the address by using a simple sketch that sniffs the I2C line to detect what devices are connected alongside their address. This sketch is also a good way to test the correctness of your wiring or to determine if the LCD is working properly.

Copy the code below and paste in the Arduino IDE.

#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++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the 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);          
}

This sketch basically uses a “for” loop to generate a list of addresses and then sends a begin transmission request to the address. The return value of the Write.endTransmission() function shows if a device exists on that particular address. The address at which a response was received is the address we are a looking for.

Verify and upload the code to the ESP32 Board and open the serial monitor.  You should see the address as shown in the image below:

Device Address

If you keep getting “no devices found”, it might help to take a look at the connections to be sure you didn’t mix things up and you could also go ahead and try 0x27 as the I2C address. This is a common address for most I2C LCD modules from China.

Armed with the address, we can now write the code for this project.

Code

Our task for today’s tutorial is to display both static and scrolling text on the LCD, and to achieve that, we will use the I2C LCD library to reduce the amount of code we need to write. We will write two separate sketches; one to display static texts and the other to display both static and scrolling text.

Static Text

To start with the sketch for static text display, we start the code by including the library to be used for it, which in this case, is the I2C LCD library.

#include <LiquidCrystal_I2C.h>

Next, we create an instance of the I2C LCD library class with the address of the display, the number of columns the display has (16 in this case), and the number of rows (2 in this case) as arguments.

LiquidCrystal_I2C lcd(0x27, 16, 2);

With that done, we proceed to the void setup() function. Here we initialize the display and issue the command to turn the backlight on as it might be off by default depending on the LCD.

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

Next is the void loop() function. The idea behind the code for the loop is simple, we start by setting the cursor to the column and row of the display where we want the text to start from, and we proceed to display the text using the lcd.print() function. To allow the text to stay on the screen for a while (so its visible) before the loop is reloaded, we delay the code execution for 1000ms.

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
}

The complete code for the project is available below and also attached under the download section.

#include <LiquidCrystal_I2C.h>

// 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, 16, 2);  

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
}

Scrolling Text

For the scrolling text, we will use some code developed by Rui Santos of RandomNerdTutorials.com. This code allows the display of static text on the first row and scrolling text on the second row of the display at the same time.

As usual, we start by including the libraries that we will use for the sketch which in this case is the same I2C LCD library.

/*********
  Rui Santos
  
Home
*********/ #include <LiquidCrystal_I2C.h>

Next, we create an instance of the I2C LCD library class with the address of the display, the number of columns the display has (16 in this case), and the number of rows (2 in this case) as arguments.

LiquidCrystal_I2C lcd(0x27, 16, 2);

Next, we create variables to hold the messages to be displayed.

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

Next, we create the function to display scrolling text. The function accepts four arguments; the row on which to display the scrolling text, the text to be displayed, the delay time between the shifting of characters, and the number of columns of the 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);
  }
}

Next is the void setup() function. The function stays the same as the one for the static text display as we initialize the display and turn on the backlight.

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

With that done, we move to the void loop() function. We start by setting the cursor, then we use the print function to display the static text and the scrollText() function is called to display the scrolling text.

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);
}

The complete code for this sketch is available below and also attached under the download section of the tutorial.

// Adapted from the code by
//  Rui Santos
//  https://randomnerdtutorials.com  


#include <LiquidCrystal_I2C.h>

// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, 16, 2);  

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, 16);
}

Demo

Ensure your connections are properly done, connect the DOIT Devkit to your PC and upload either of the two sketches. You should see this display come up with the text as shown in the image below.

Demo

That’s it for today’s tutorial guys. Thanks for following this tutorial. This cheap LCD display provides a nice way of providing visual feedback for your project and even though the size of the screen and the quality of the display is limited, with the scrolling function you can increase the amount of text/characters that can be displayed.

Feel free to reach out to me via the comment section, with questions and general comments on the tutorial.

Please follow and like us:
Pin Share



Downloads

Subscribe
Notify of
guest

4 Comments
Inline Feedbacks
View all comments
Shaun

I just noticed that your display SDA is mislabelled in your image and should go to pin D21 on the ESP32.

Uleg

Where to get the LiquidCrystal_I2C library?

All of the versions I tried end up with an error on esp32 – cannot compile for esp32

mixos
Todd

Thanks for the tutorial, it has helped me get a start on using the ESP32.
Three things that I learned from this tutorial:

  1. You get a compiler warning that the liquidCrystal_I2C is for Atmel architecture and it might not work with ESP32. This doesn’t appear to be a problem, it works anyway.
  2. If you don’t get any text on your display you can use lcd.backlight() and lcd.nobacklight() to blink the backlight, showing that you are addressing the lcd properly and the fault is not a configuration problem.
  3. If you don’t get any text on your display, and you can blink the backlight then check the contrast setting. Even though you thought it was still set properly from last time you used the display module in another tutorial, try changing the contrast setting again.

RELATED PROJECTS

TOP PCB Companies