How to Use an I2C LCD Display With Raspberry Pi Pico

Raspberry Pi Pico with LCD Screen
(Image credit: Tom's Hardware)

LCD screens are useful and found in many parts of our life. At the train station, parking meter, vending machines communicating brief messages on how we interact with the machine they are connected to. LCD screens are a fun way to communicate information in Raspberry Pi Pico projects and other Raspberry Pi Projects. They have a big bright screen which can display text, numbers and characters across a 16 x 2 screen. The 16 refers to 16 characters across the screen, and the 2 represents the number of rows we have. We can get LCD screens with 20x2, 20x4 and many other configurations, but 16x2 is the most common.

In this tutorial, we will learn how to connect an LCD screen, an HD44780, to a Raspberry Pi Pico via the I2C interface using the attached I2C backpack, then we will install a MicroPython library via the Thonny editor and learn how to use it to write text to the display, control the cursor and the backlight.

The LCD screen uses the I2C protocol to interface with the Raspberry Pi Pico. Which means that we only require. 

How to Connect an I2C LCD screen to Raspberry Pi Pico 

(Image credit: Tom's Hardware)

1. Connect the GND of the screen to any GND on the Pico (Black wire).

2. Connect VDD / VCC to VBUS on the Pico (Red wire). Warning this is a 5V pin.

3. Connect SDA to I2C0 SDA (GP0, Physical pin 1, Orange wire).

4. Connect SCK / SCL to I2C0 SCL (GP1, Physical pin 2, Yellow wire).

5. Connect your Raspberry Pi Pico to your computer and open the Thonny application. 

6. Click on STOP to confirm your Pico is connected.

7. Open this link and copy the text from the page.

8. Create a blank file in Thonny and paste the text into it. Save the file to the Raspberry Pi Pico as lcd_api.py

9. Open this link and copy the text from the page.

10. Create a blank file in Thonny and paste the text into it. Save the file to the Raspberry Pi Pico as pico_i2c_lcd.py

 Programming an I2C LCD Screen with Raspberry Pi Pico

With the libraries installed we can now start writing a test script to demonstrate the library functions.

1. Create a new blank file in Thonny.

2. Import four libraries of pre-written code. The first two are from the Machine library and they enable us to use I2C and GPIO pins. Next we import the sleep function from Time enabling us to pause the code. Finally we import the I2C library to interact with the LCD screen.

from machine import I2C, Pin
from time import sleep
from pico_i2c_lcd import I2cLcd

3.  Create an object i2c to communicate with the LCD screen over the I2C protocol. Here we are using I2C channel 0, which maps SDA to GP0 and SCL to GP1. 

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

4. Create a variable I2C_ADDR, which will store the first I2C address found when we scan the bus. As we only have one I2C device connected, we only need to see the first [0] address returned in the scan. 

I2C_ADDR = i2c.scan()[0]

5.  Create an object lcd to set up the I2C connection for the library. It tells the library what I2C pins we are using, set via the i2c object, the address of our screen, set via I2C_ADDR and finally it sets that we have a screen with two rows and 16 columns. 

lcd = I2cLcd(i2c, I2C_ADDR, 2, 16)

6.  Create a loop to continually run the code, the first line in the loop will print the I2C address of our display to Thonny’s Python Shell. 

while True:
    print(I2C_ADDR)

7.  Set the LCD display’s cursor to flash (blink) on and off, similar to an old school terminal interface. 

     lcd.blink_cursor_on()

8.  Write two lines of text to the screen. The first will print “I2C Address:” followed by the address stored inside the I2C_ADDR object. Then insert a new line character “\n” and then write another line saying “Tom’s Hardware" (or whatever you want it to say). Pause for two seconds to allow time to read the text. 

    lcd.putstr("I2C Address:"+str(I2C_ADDR)+"\n")
    lcd.putstr("Tom's Hardware")
    sleep(2)

9.  Clear the screen before repeating the previous section of code, but this time we display the I2C address of the LCD display using its hex value. The PCF8574T chip used in the I2C backpack has two address, 0x20 and 0x27 and it is useful to know which it is using, especially if we are using multiple I2C devices as they may cause a clash on the bus. 

    lcd.clear()
    lcd.putstr("I2C Address:"+str(hex(I2C_ADDR))+"\n")
    lcd.putstr("Tom's Hardware")

10.  Turn off the blinking cursor, then clear the screen ready to print another message, “Backlight Test” to the screen. 

    lcd.blink_cursor_off()
    lcd.clear()
    lcd.putstr("Backlight Test")

11.  To flash the LED backlight, use a for loop that will iterate ten times. It will turn on the backlight for 0.2 seconds, then turn it off for the same time. The “Backlight Test” text will remain on the screen even with the backlight off. 

    for i in range(10):
        lcd.backlight_on()
        sleep(0.2)
        lcd.backlight_off()
        sleep(0.2)

12.  Turn the backlight back on and then hide the cursor. Sometimes, a flashing cursor can detract from the information we are trying to communicate. 

    lcd.backlight_on()
    lcd.hide_cursor()

13.  Create a for loop that will print the number 0 to 19 on the LCD screen. Note that there is a 0.4 second delay before we delete the value and replace it with the next. We have to delete the text as overwriting the text will make it look garbled.

    for i in range(20):
        lcd.putstr(str(i))
        sleep(0.4)
        lcd.clear()

Complete Code Listing

from machine import I2C, Pin
from time import sleep
from pico_i2c_lcd import I2cLcd
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)

I2C_ADDR = i2c.scan()[0]
lcd = I2cLcd(i2c, I2C_ADDR, 2, 16)
while True:
    print(I2C_ADDR)
    lcd.blink_cursor_on()
    lcd.putstr("I2C Address:"+str(I2C_ADDR)+"\n")
    lcd.putstr("Tom's Hardware")
    sleep(2)
    lcd.clear()
    lcd.putstr("I2C Address:"+str(hex(I2C_ADDR))+"\n")
    lcd.putstr("Tom's Hardware")
    sleep(2)
    lcd.blink_cursor_off()
    lcd.clear()
    lcd.putstr("Backlight Test")
    for i in range(10):
        lcd.backlight_on()
        sleep(0.2)
        lcd.backlight_off()
        sleep(0.2)
    lcd.backlight_on()
    lcd.hide_cursor()
    for i in range(20):
        lcd.putstr(str(i))
        sleep(0.4)
        lcd.clear()

Save and run your code. As with any Python script in Thonny, Click on File >> Save and save the file to your Raspberry Pi Pico. We recommend calling it i2c_lcd_test.py. When ready, click on the Green play button to start the code and watch as the test runs on the screen. 

Les Pounder

Les Pounder is an associate editor at Tom's Hardware. He is a creative technologist and for seven years has created projects to educate and inspire minds both young and old. He has worked with the Raspberry Pi Foundation to write and deliver their teacher training program "Picademy".

  • iwestbury
    Hi Tom. Nice tutorial. Works well with the change below.

    I think line 3 should read:

    from pico_i2c_lcd import I2cLcd

    Not:

    from machine_i2c_lcd import I2cLcd
    Reply
  • parisaa.pbn
    hello guys
    when i use lcd i2c with Raspberry Pi pico this error show for me!

    line 5 in my code : I2C_ADDR = i2c.scan()

    MicroPython v1.16 on 2021-06-18; Raspberry Pi Pico with RP2040

    Type "help()" for more information.
    >> %Run -c $EDITOR_CONTENT
    Traceback (most recent call last):
    File "<stdin>", line 5, in <module>
    IndexError: list index out of range
    Reply