If you plan on using an LCD with your Raspberry Pi, there’s a good chance you’ll need to program it in Python at some point. Python is probably the most popular programming language for coding on the Raspberry Pi, and many of the projects and examples you’ll find are written in Python.

In this tutorial, I’ll show you how to connect your LCD and program it in Python, using the RPLCD library. I’ll start with showing you how to connect it in either 8 bit mode or 4 bit mode. Then I’ll explain how to install the library, and provide examples for printing and positioning text, clearing the screen, and controlling the cursor. I’ll also give you examples for scrolling text, creating custom characters, printing data from a sensor, and displaying the date, time, and IP address of your Pi.

BONUS: I made a quick start guide for this tutorial that you can download and go back to later if you can’t set this up right now. It covers all of the steps, diagrams, and code you need to get started.

I’m using a 16X2 LCD display here, but the examples will work with any LCD that uses the Hitachi HD44780 driver.

You can also connect the LCD via I2C, which uses only two wires, but it requires some extra hardware. Check out our article, How to Setup an I2C LCD on the Raspberry Pi to see how.

I also go over how to program the LCD with C in another article, but for now let’s focus on Python…

Here is the video version of this tutorial, where you can watch all of the example programs below in real time:

Connecting the LCD

There are two ways to connect the LCD to your Raspberry Pi – in 4 bit mode or 8 bit mode. 4 bit mode uses 6 GPIO pins, while 8 bit mode uses 10. Since it uses up less pins, 4 bit mode is the most common method, but I’ll explain how to set up and program the LCD both ways.

Each character and command is sent to the LCD as a byte (8 bits) of data. In 8 bit mode, the byte is sent all at once through 8 data wires, one bit per wire. In 4 bit mode, the byte is split into two sets of 4 bits – the upper bits and lower bits, which are sent one after the other over 4 data wires.

Theoretically, 8 bit mode transfers data about twice as fast as 4 bit mode, since the entire byte is sent all at once. However, the LCD driver takes a relatively long time to process the data, so no matter which mode is being used, we don’t really notice a difference in data transfer speed between 8 bit and 4 bit modes.

Wiring the LCD in 8 Bit Mode

To connect your LCD in 8 bit mode set it up like this:

Raspberry Pi LCD 8 Bit Mode Connection Diagram

The backlight and contrast potentiometers are 10K Ohms, but they can be substituted with 1K to 3K Ohm resistors if you want.

Wiring the LCD in 4 Bit Mode

To connect the LCD to your Raspberry Pi in 4 bit mode, set it up like this:

Raspberry Pi LCD 4 bit mode

The potentiometers here can also be substituted with 1K or 3K Ohm resistors.

Programming the LCD With Python

If this is your first time writing and running a Python program, you might want to read How to Write and Run a Python Program on the Raspberry Pi, which will explain everything you need to know to run the examples below.

We’ll be using a Python library that provides a lot of useful functions. Its called the RLPCD library, and was written by Danilo Bargen.

Installing the RPLCD Library

The RPLCD library can be installed from the Python Package Index, or PIP. It might already be installed on your Pi, but if not, enter this at the command prompt to install it:

sudo apt-get install python-pip

After you get PIP installed, install the RPLCD library by entering:

sudo pip install RPLCD

The example programs below use the Raspberry Pi’s physical pin numbers, not the BCM or GPIO numbers. I’m assuming you have your LCD connected the way it is in the diagrams above, but I’ll show you how to change the pin connections if you need to.

Write to the Display in 8 Bit Mode

Let’s start with a simple program that will display “Hello world!” on the LCD. If you have a different sized LCD than the 16×2 I’m using (like a 20×4), change the number of columns and rows in line 2 of the code. cols= sets the number of columns, and rows= sets the number of rows. You can also change the pins used for the LCD’s RS, E, and data pins. The data pins are set as pins_data=[D0, D1, D2, D3, D4, D5, D6, D7].

Text strings are written to the display using the lcd.write_string() function:

from RPLCD import CharLCD
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[40, 38, 36, 32, 33, 31, 29, 23])
lcd.write_string(u'Hello world!')

Write to the Display in 4 Bit Mode

In 4 bit mode, only LCD pins D4, D5, D6, and D7 are used for data. These are set in pins_data=[D4, D5, D6, D7] on line 2 below:

from RPLCD import CharLCD
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])
lcd.write_string(u'Hello world!')

Position the Text

The text can be positioned anywhere on the screen using lcd.cursor_pos = (ROW, COLUMN). The rows are numbered starting from zero, so the top row is row 0, and the bottom row is row 1. Similarly, the columns are numbered starting at zero, so for a 16×2 LCD the columns are numbered 0 to 15. For example, the code below places “Hello world!” starting at the bottom row, fourth column:

from RPLCD import CharLCD
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])

lcd.cursor_pos = (1, 3) 
lcd.write_string(u'Hello world!')

Clear the Screen

The function lcd.clear() will clear the screen. The following code will print “Hello world!” to the screen for two seconds before clearing it:

import time
from RPLCD import CharLCD
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])

lcd.write_string(u'Hello world!')
time.sleep(2)
lcd.clear()

Blinking Text

Combining lcd.clear() and time.sleep() in a while loop will produce a blinking text effect:

import time
from RPLCD import CharLCD
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])

while True:
    lcd.write_string(u"Hello world!")
    time.sleep(1)
    lcd.clear()
    time.sleep(1)

Press Ctrl-C to exit the program.

Turn the Cursor On and Off

The RPLCD library provides several functions for controlling the cursor. You can have a block cursor, an underline cursor, or a blinking cursor. Use the following functions to set the cursor:

  • Blinking block cursor: lcd.cursor_mode = CursorMode.blink
  • Line cursor: lcd.cursor_mode = CursorMode.line
  • Cursor off: lcd.cursor_mode = CursorMode.hide

The code below places a blinking cursor after the last character of text:

from RPLCD import CharLCD
from RPLCD import CursorMode
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])

lcd.write_string(u'Hello world!')

lcd.cursor_mode = CursorMode.blink
#lcd.cursor_mode = CursorMode.line
#lcd.cursor_mode = CursorMode.hide

Line Breaks

Text will automatically wrap to the next line if the length of the text is greater than the column length of your LCD. You can also control where the text string breaks to the next line by inserting \n\r where you want the break to occur. The code below will print “Hello” to the top row, and “world!” to the bottom row.

from RPLCD import CharLCD
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])

lcd.write_string(u'Hello\n\rworld!')

Print the Date and Time

This program will display the date and time on the LCD:

from RPLCD import CharLCD
import time
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])


while True:
    lcd.write_string("Time: %s" %time.strftime("%H:%M:%S"))
    
    lcd.cursor_pos = (1, 0)
    lcd.write_string("Date: %s" %time.strftime("%m/%d/%Y"))

Print Your IP Address

This program will print the IP address of your ethernet connection to the LCD. To print the IP of your WiFi connection, just change eth0 in line 19 to wlan0:

from RPLCD import CharLCD
import socket
import fcntl
import struct

lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915, 
        struct.pack('256s', ifname[:15])
    )[20:24])

lcd.write_string("IP Address:") 

lcd.cursor_pos = (1, 0)
lcd.write_string(get_ip_address('eth0'))

Custom Characters

Each character on the LCD is an array of 5×8 of pixels. You can create any pattern or character you can think of, and display it on the screen as a custom character. Check out this website for an interactive tool that creates the bit array used to define custom characters.

First we define the character in lines 4 to 12 of the code below. Then we use the function lcd.create_char(0-7, NAME) to store the character in the LCD’s CGRAM memory. Up to 8 (0-7) characters can be stored at a time. To print the custom character, we use lcd.write_string(unichr(0)), where the number in unichr() is the memory location (0-7) defined in lcd.create_char().

Printing a Single Custom Character

Take a look at this code, which prints a single smiley face character to the display:

from RPLCD import CharLCD, cleared, cursor
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])

smiley = (
    0b00000,
    0b01010,
    0b01010,
    0b00000,
    0b10001,
    0b10001,
    0b01110,
    0b00000,
)
lcd.create_char(0, smiley)
lcd.write_string(unichr(0))

Printing Multiple Custom Characters

This program will print the Greek letters omega, pi, and mu, along with symbols for temperature (a thermometer) and humidity (a water drop):

from RPLCD import CharLCD, cleared, cursor
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])

omega = (
    0b00000,
    0b01110,
    0b10001,
    0b10001,
    0b10001,
    0b01010,
    0b11011,
    0b00000,
)

pi = (
    0b00000,
    0b00000,
    0b11111,
    0b01010,
    0b01010,
    0b01010,
    0b10011,
    0b00000,
)

mu = (
    0b00000,
    0b10010,
    0b10010,
    0b10010,
    0b10010,
    0b11101,
    0b10000,
    0b10000,
)

drop = (
    0b00100,
    0b00100,
    0b01010,
    0b01010,
    0b10001,
    0b10001,
    0b10001,
    0b01110,
)

temp = (
    0b00100,
    0b01010,
    0b01010,
    0b01110,
    0b01110,
    0b11111,
    0b11111,
    0b01110,
)

lcd.create_char(0, omega)
lcd.create_char(1, pi)
lcd.create_char(2, mu)
lcd.create_char(3, drop)
lcd.create_char(4, temp)

lcd.write_string(unichr(0))
lcd.write_string(unichr(1))
lcd.write_string(unichr(2))
lcd.write_string(unichr(3))
lcd.write_string(unichr(4))

Scrolling Text

This program scrolls text from right to left in an infinite loop:

framebuffer = [
    '',
    '',
]

def write_to_lcd(lcd, framebuffer, num_cols):
    lcd.home()
    for row in framebuffer:
        lcd.write_string(row.ljust(num_cols)[:num_cols])
        lcd.write_string('\r\n')

from RPLCD import CharLCD
lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])
write_to_lcd(lcd, framebuffer, 16)

import time
long_string = 'This string is too long to fit'

def loop_string(string, lcd, framebuffer, row, num_cols, delay=0.5): #DELAY= CONTROLS THE SPEED OF SCROLL
    padding = ' ' * num_cols
    s = padding + string + padding
    for i in range(len(s) - num_cols + 1):
        framebuffer[row] = s[i:i+num_cols]
        write_to_lcd(lcd, framebuffer, num_cols)
        time.sleep(delay)

while True:
    loop_string(long_string, lcd, framebuffer, 1, 16)

You can change the scroll speed on line 19 where it says delay=0.5.

Print Data from a Sensor

To demonstrate how to print data from a sensor, here’s a program that displays the temperature from a DS18B20 Digital Temperature Sensor. There is some set up to do before you can get this to work on the Raspberry Pi, so check out our tutorial on the DS18B20 to see how.

In general, you take the input variable from your sensor and convert it to an integer to perform any calculations. Then convert the result to a string, and output the string to the display using lcd.write_string(sensor_data()):

import os
import glob
import time
from RPLCD import CharLCD

lcd = CharLCD(cols=16, rows=2, pin_rs=37, pin_e=35, pins_data=[33, 31, 29, 23])

os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')

base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'

def read_temp_raw():
    f = open(device_file, 'r')
    lines = f.readlines()
    f.close()
    return lines

#CELSIUS CALCULATION
def read_temp_c():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != 'YES':
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find('t=')
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = int(temp_string) / 1000.0 # TEMP_STRING IS THE SENSOR OUTPUT, MAKE SURE IT'S AN INTEGER TO DO THE MATH
        temp_c = str(round(temp_c, 1)) # ROUND THE RESULT TO 1 PLACE AFTER THE DECIMAL, THEN CONVERT IT TO A STRING
        return temp_c

#FAHRENHEIT CALCULATION
def read_temp_f():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != 'YES':
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find('t=')
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_f = (int(temp_string) / 1000.0) * 9.0 / 5.0 + 32.0 # TEMP_STRING IS THE SENSOR OUTPUT, MAKE SURE IT'S AN INTEGER TO DO THE MATH
        temp_f = str(round(temp_f, 1)) # ROUND THE RESULT TO 1 PLACE AFTER THE DECIMAL, THEN CONVERT IT TO A STRING
        return temp_f

while True:

    lcd.cursor_pos = (0, 0)
    lcd.write_string("Temp: " + read_temp_c() + unichr(223) + "C")
    lcd.cursor_pos = (1, 0)
    lcd.write_string("Temp: " + read_temp_f() + unichr(223) + "F")

Well, that about covers most of what you’ll need to get started programming your LCD with Python. Try combining the programs to get some interesting effects. You can display data from multiple sensors by printing and clearing the screen or positioning the text. You can also make fun animations by scrolling custom characters.

If you have any problems or questions, just leave a comment below. And be sure to subscribe if you’d like to get an email notification when we publish new articles. Ok, talk to you next time!