I2C LCD Interfacing with Raspberry Pi Pico Display Text and Custom Characters

In this tutorial, we will learn how to interface I2C LCD with Raspberry Pi Pico and how to display simple text/numbers and custom characters on I2C LCD. This I2C LCD is a 16×2 device which means it can display 16 columns by two rows of characters. The characters are alphanumeric, but you can create custom characters for basic graphics, bar graphs that kind of thing. The LCD has the usual type of hd44780 controller, and it also has an I2C circuit connected with it which makes it easy to connect to the Pi Pico board. 16X2 LCD without I2C circuit has sixteen pins.

I2C LCD with Raspberry Pi Pico Display Text and Custom Characters

You can find more information about the pins by going to this article:16×2 Liquid crystal display

I2C LCD interfacing with ESP32

But if we want to connect this board directly with Raspberry Pi Pico, we have to use at least eight pins of our board which will be a waste. So the better solution is to use an I2C LCD instead of typical 16×2 LCD. In this tutorial, we are using 16×2 I2C LCD, but LCD of any size will also work the same way as we will learn in this tutorial. The advantage of using an I2C LCD is that we only need to use four pins (including the power pins) of Raspberry Pi Pico to connect with this display.

At the backside of this liquid crystal display, you can also see a variable resistor. This variable resistor is used to modify the brightness of the LCD. This potentiometer is very handy when you are using this display module in different light conditions.

Prerequisites

Before we start this lesson, make sure you are familiar with and have the latest version of Python3 installed in your system and set up MicroPython in your Raspberry Pi Pico. Additionally, you should have a running Integrated Development Environment(IDE) to do the programming. We will be using the same Thonny IDE as we have done previously when we learned how to blink and chase LEDs in MicroPython here:

If you are using uPyCraft IDE, you can check this getting started guide:

I2C LCD Pinout

So now let’s start with the pinout of this display. This display has four pins:

  • Ground pin
  • Vcc pin
  • SDA 
  • SCL

Now let’s see how to connect this LCD with Raspberry Pi Pico.

Interfacing I2C LCD with Raspberry Pi Pico

In this section, we will show you how to connect I2C LCD with Raspberry Pi Pico. The I2C LCD will be connected with the Pi Pico with its 4 pins (GND, VCC, SDA and SCL).

I2C LCD Interfacing with Raspberry Pi Pico

Raspberry Pi Pico I2C Pins

Raspberry Pi Pico has two I2C controllers. Both I2C controllers are accessible through GPIO pins of Raspberry Pi Pico. The following table shows the connection of GPIO pins with both I2C controllers. Each connection of the controller can be configured through multiple GPIO pins as shown in the figure. But before using an I2C controller, you should configure in software which GPIO pins you want to use with a specific I2C controller. 

I2C ControllerGPIO Pins
I2C0 – SDAGP0/GP4/GP8/GP12/GP16/GP20
I2C0 – SCLGP1/GP5/GP9/GP13/GP17/GP21
I2C1 – SDAGP2/GP6/GP10/GP14/GP18/GP26
I2C1 – SCLGP3/GP7/GP11/GP15/GP19/GP27

The connections between the two devices which we are using can be seen below.

I2C LCDRaspberry Pi Pico
VCCVBUS pin. This is the power from the microUSB bus (5-volts).
SDAGP0 (I2C0 SDA)
SCLGP1 (I2C0 SCL)
GNDGND

The VCC pin is connected with the VBUS pin from the Raspberry Pi Pico to power up. Both the grounds of the two devices are connected in common. The SCL pin of I2C LCD is connected with I2C0 SCL pin of Pi Pico. Likewise, the SDA pin is connected with the I2C0 SDA pin of Pi Pico.

We have used the same connections as specified in the table above. However you can use other combinations of SDA/SCL pins as well.

Raspberry Pi Pico with I2C LCD connection diagram
Raspberry Pi Pico with I2C LCD connection diagram

Getting I2C LCD Address

When you connect your I2C display with Raspberry Pi Pico, you need to check its address. Because every I2C device has an address associated with it. For many devices of I2C LCD, the default address is 0x27 where 0x shows hex format of the numbers. But address can be different in some cases. This address depends on the position of pads A0, A1, and A2 on the I2C controller on this device.

Now copy this code and upload it your board with the I2C LCD already connected with it.

This code will scan for any I2C devices and will specify the number of devices with the address in the shell console.

import machine

sdaPIN=machine.Pin(0)
sclPIN=machine.Pin(1)
i2c=machine.I2C(0,sda=sdaPIN, scl=sclPIN, freq=400000)

devices = i2c.scan()
if len(devices) == 0:
 print("No i2c device !")
else:
 print('i2c devices found:',len(devices))
for device in devices:
 print("At address: ",hex(device))
I2C LCD address MicroPython

This message shows the address of liquid crystal display is 0x27. You will most likely get the same address for LCD with 16 columns and 2 rows.

I2C LCD MicroPython Libraries

For this project we will require two libraries: lcd_api.py and i2c_lcd.py. Copy both of these libraries and save them in your Raspberry Pi Pico with the respective file names. Open a new file in Thonny. Copy the libraries from the links given above. Save them to Raspberry Pi Pico with names lcd_api.py and i2c_lcd.py under the lib folder.

Displaying Text/Numbers on I2C LCD using Raspberry Pi Pico

In this section, we will display a message along with numbers on the screen.

import machine
from machine import I2C
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
from time import sleep

I2C_ADDR = 0x27
totalRows = 2
totalColumns = 16

i2c = I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, totalRows, totalColumns)

while True:
    lcd.putstr("Lets Count 0-10!")
    sleep(2)
    lcd.clear()
    for i in range(10):
        lcd.putstr(str(i))
        sleep(1)
        lcd.clear()

This code will display the message “Lets Count 0-10!” for two seconds. After that, it will clear the LCD and display numbers from 0 to 10 after a delay of 1 second.

How the Code Works?

Now we will see the working of code. 

Firstly, we will be importing the I2C class from the machine module. We also import the sleep module so that we will be able to add a delay in between our messages. Also, import LcdApi from the lcd_api library that we just uploaded to our board and I2clcd from the i2c_lcd library.

import machine
from machine import I2C
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
from time import sleep

Next specify the address of your I2C LCD device. We ran the sketch given previously and found ours to be 0x27.

Additionally, totalRows and totalColumns specify the number of rows and columns of the display which in our case is 16×2. If you want to use a screen of any other size, you need to need to change the number here accordingly, for example, the 20×4 display.

I2C_ADDR = 0x27
totalRows = 2
totalColumns = 16

i2c object

Next, we will initialize the I2C GPIO pins for SCL and SDA respectively. We have used the I2C0 SCL and I2C0 SDA pins.

We have created an I2C() method which takes in four parameters. The first parameter is the I2C channel that we are using. The second parameter specifies the I2C GPIO pin of the board which is connected to the SDA line. The third parameter specifies the I2C GPIO pin of the board which is connected to the SCL line. The last parameter is the frequency connection.

We are setting the SCL on pin 1 and the SDA on pin 0.

i2c = I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)

lcd object

This line is used to initialize the I2C connection for the library by creating an object ‘lcd’. The first argument to the function I2cLcd() is the i2c object declared previously, the second argument is the address of our I2C LCD. Third and fourth arguments are the size in terms of the number of columns and number of rows.

lcd = I2cLcd(i2c, I2C_ADDR, totalRows, totalColumns)

Display Text/Numbers

Next, we run an infinite loop inside which we first display the message “Lets Count 0-10!” for 2 seconds. Then we clear the screen using the clear() method on the lcd object. After that we use a for loop to display numbers from 0 to 10 after a delay of 1 second each. After each number is displayed, wait for one second, then clear() will erase the text.

while True:
    lcd.putstr("Lets Count 0-10!")
    sleep(2)
    lcd.clear()
    for i in range(10):
        lcd.putstr(str(i))
        sleep(1)
        lcd.clear()

Demonstration

To test this program with Raspberry Pi Pico, upload this main.py file to your board. Once the code is uploaded to the board, adjust the brightness of the display through the potentiometer until the LCD starts displaying the messages:

Display Custom Characters on I2C LCD using Raspberry Pi Pico

In this section, we will display custom characters on the LCD screen.

For our 16×2 LCD display that we are using, we have the option to display custom characters as well. In this particular LCD, each block consists of 5×8 pixels. These can be used to display custom characters by setting the state of each pixel inside a byte array.

There is a very simple way to generate the byte array of your own custom character. Head over to the following custom character generator: (LCD Custom Character Generator).

The following web page opens up. Select the data type as ‘Hex’.

LCD Custom Character Generator

Specify the custom character you want to display by clicking the pixels in the 5×8 pixel block and the corresponding byte variable will be generated.

In our case, we will display a heart character on the screen. We will require the hex data that is highlighted in the red rectangle below to form our byte array. We will use these values inside our byte array while programming the Raspberry Pi Pico to display custom characters.

LCD Custom Character Generator for heart icon

Likewise, you can generate custom characters according to your preference from this generator and just copy the hex numbers to fill the byte array while programming your board in MicroPython.

Lets look at the MicroPython script to display custom characters on the I2C LCD with Raspberry Pi Pico.

MicroPython Display custom Character on I2C LCD

import machine
from machine import I2C
from lcd_api import LcdApi
from i2c_lcd import I2cLcd

I2C_ADDR = 0x27
totalRows = 2
totalColumns = 16

i2c = I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, totalRows, totalColumns)

heart = bytearray([0x00,0x00,0x1B,0x1F,0x1F,0x0E,0x04,0x00])
face = bytearray([0x00,0x00,0x0A,0x00,0x11,0x0E,0x00,0x00])
lcd.custom_char(0, heart)
lcd.custom_char(1, face)
lcd.putstr(chr(0)+" WELCOME "+chr(1))

This code displays the message ‘WELCOME’ in between a heart custom character and a smiley face custom character.

How the Code Works?

Most of the code is similar to the previous sketch. Let us explain the parts where the custom character is involved.

Create a bytearray for heart with hex values obtained from the LCD Custom Character Generator.

heart = bytearray([0x00,0x00,0x1B,0x1F,0x1F,0x0E,0x04,0x00])

Likewise, we also create another bytearray for smiley face with hex values obtained from the LCD Custom Character Generator.

face = bytearray([0x00,0x00,0x0A,0x00,0x11,0x0E,0x00,0x00])

Next, we will create the custom character by calling lcd.custom_char() and pass a number between 0-7 (allocated location) and the variable containing the bytearray as parameters inside it.

lcd.custom_char(0, heart)
lcd.custom_char(1, face)

We will display the heart character followed by ‘WELCOME’ followed by the smiley face character on the screen.

lcd.putstr(chr(0)+" WELCOME "+chr(1))

Demonstration

To test this program with Raspberry Pi Pico, upload this main.py file to your board. Once the code is uploaded to the board, adjust the brightness of the display through the potentiometer until the LCD starts displaying the message.

Raspberry Pi Pico I2C LCD Custom Character demo

You may like to read:

3 thoughts on “I2C LCD Interfacing with Raspberry Pi Pico Display Text and Custom Characters”

Leave a Comment