It's easy to use the Nokia 5110/3310 LCD with CircuitPython and the Adafruit CircuitPython PCD8544 module. This module allows you to easily write Python code to control the display.

You can use this display with a computer that has GPIO and Python thanks to Adafruit_Blinka, our CircuitPython-for-Python compatibility library.

To demonstrate the usage, we'll initialize the library and use Python code to control the LCD from the board's Python REPL.

Since we are running full CPython on our Linux/computer, we can take advantage of the powerful Pillow image drawing library to handle text, shapes, graphics, etc. Pillow is a gold standard in image and graphics handling, you can read about all it can do here.

Initialization

First need to initialize the SPI bus. To do that, run the following commands:

Download: file
import adafruit_pcd8544
import board
import busio
import digitalio

spi = busio.SPI(board.SCK, MOSI=board.MOSI)
dc = digitalio.DigitalInOut(board.D6) # data/command
cs = digitalio.DigitalInOut(board.CE0) # Chip select
reset = digitalio.DigitalInOut(board.D5) # reset

display = adafruit_pcd8544.PCD8544(spi, dc, cs, reset)

The last three parameters to the initializer are the pins connected to the display's DCCS, and reset lines in that order.  Again make sure to use the right pin names as you have wired up to your board!

Controlling the Backlight LED

You can control the display backlight LED as well. Just be sure the LED line is wired up to your microcontroller. Just start by initializing it as a DigitalInOut output line. If you wired it to a different output, be sure to change the port accordingly.

Download: file
backlight = digitalio.DigitalInOut(board.D13) # backlight
backlight.switch_to_output()

To turn it on, just set it to True and to turn it off, just set it to False.

Download: file
# Turn Backlight on
backlight.value = True

#Turn Backlight off
backlight.value = False

Contrast and Bias

Two important settings so that you can see what is on the display are the contrast and Bias Settings. Let's start by taking a look at the Bias Setting.

Bias

The Bias setting controls the amount of voltage that goes to the display. The higher the value, the darker the display will be. It's kind of like the brightness setting on a monitor, but will make the pixels more intense. A value of 4-5 is usually pretty good. For example, to set it to 5, you would type:

Download: file
display.bias = 5

Contrast

The contrast setting controls the difference between the dark and light pixels and can be set to anywhere between 0-127. This is like the contrast setting on a monitor. Too high of a value will make everything appear dark and to low of a value will make everything appear too light. A value of around 50-60 seems to look good. For example, to set it to 50, you would type:

Download: file
display.contrast = 50

You may want to play around with different combinations of these values to see what makes your particular display the most readable.

Example Code

"""
This demo will fill the screen with white, draw a black box on top
and then print Hello World! in the center of the display

This example is for use on (Linux) computers that are using CPython with
Adafruit Blinka to support CircuitPython libraries. CircuitPython does
not support PIL/pillow (python imaging library)!
"""

import board
import busio
import digitalio
from PIL import Image, ImageDraw, ImageFont
import adafruit_pcd8544

# Parameters to Change
BORDER = 5
FONTSIZE = 10

spi = busio.SPI(board.SCK, MOSI=board.MOSI)
dc = digitalio.DigitalInOut(board.D6) # data/command
cs = digitalio.DigitalInOut(board.CE0) # Chip select
reset = digitalio.DigitalInOut(board.D5) # reset

display = adafruit_pcd8544.PCD8544(spi, dc, cs, reset)

# Contrast and Brightness Settings
display.bias = 4
display.contrast = 60

# Turn on the Backlight LED
backlight = digitalio.DigitalInOut(board.D13) # backlight
backlight.switch_to_output()
backlight.value = True

# Clear display.
display.fill(0)
display.show()

# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
image = Image.new('1', (display.width, display.height))

# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)

# Draw a black background
draw.rectangle((0, 0, display.width, display.height), outline=255, fill=255)


# Draw a smaller inner rectangle
draw.rectangle((BORDER, BORDER, display.width - BORDER - 1, display.height - BORDER - 1),
               outline=0, fill=0)

# Load a TTF font.
font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', FONTSIZE)

# Draw Some Text
text = "Hello World!"
(font_width, font_height) = font.getsize(text)
draw.text((display.width//2 - font_width//2, display.height//2 - font_height//2),
          text, font=font, fill=255)

# Display image
display.image(image)
display.show()

Let's take a look at the sections of code one by one. We start by importing the board so that we can access the pin definitions, busio so we can initialize SPI, digitalio, several PIL modules for Image Drawing, and the adafruit_pcd8544 driver.

Download: file
import board
import busio
import digitalio
from PIL import Image, ImageDraw, ImageFont
import adafruit_pcd8544

In order to make it easy to change display sizes, we'll define a few variables in one spot here. We have the border size and font size, which we will explain a little further below.

Download: file
BORDER = 5
FONTSIZE = 10

Next we set the SPI object to the board's SPI with busio.SPI(). We also define some Pins that will be used for the display and initialize the display. See the initialization section above for more details.

Download: file
spi = busio.SPI(board.SCK, MOSI=board.MOSI)
dc = digitalio.DigitalInOut(board.D6) # data/command
cs = digitalio.DigitalInOut(board.CE0) # Chip select
reset = digitalio.DigitalInOut(board.D5) # reset

display = adafruit_pcd8544.PCD8544(spi, dc, cs, reset)

Next we set the Bias and Contrast. See the Contrast and Bias section for more details.

Download: file
# Contrast and Brightness Settings
display.bias = 4
display.contrast = 60

After that we setup the backlight. See the Backlight section above for more information.

Download: file
# Turn on the Backlight LED
backlight = digitalio.DigitalInOut(board.D13) # backlight
backlight.switch_to_output()
backlight.value = True

Next we clear the display in case it was initialized with any random artifact data.

Download: file
# Clear display.
display.fill(0)
display.show()

Next, we need to initialize PIL to create a blank image to draw on. Think of it as a virtual canvas. Since this is a monochrome display, we set it up for 1-bit color, meaning a pixel is either white or black. We can make use of the LCD's width and height properties as well.

Download: file
# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
image = Image.new('1', (display.width, display.height))

# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)

Now we start the actual drawing. Here we are telling it we want to draw a rectangle from (0,0), which is the upper left, to the full width and height of the display. We want it both filled in and having an outline of black, so we pass 255 for both numbers, which represents the amount of fill.

Download: file
# Draw a black background
draw.rectangle((0, 0, display.width, display.height), outline=255, fill=255)

If we ran the code now, it would still show a blank display because we haven't told python to use our virtual canvas yet. You can skip to the end if you would like to see how to do that. This is what our canvas currently looks like in memory.

Next we will create a smaller white rectangle. The easiest way to do this is to draw another rectangle a little smaller than the full screen with no fill or outline and place it in a specific location. In this case, we will create a rectangle that is 5 pixels smaller on each side. This is where the BORDER variable comes into use. It makes calculating the size of the second rectangle much easier. We want the starting coordinate, which consists of the first two parameters, to be our BORDER value. Then for the next two parameters, which are our ending coordinates, we want to subtract our border value from the width and height. Also, because this is a zero-based coordinate system, we also need to subtract 1 from each number.

Download: file
# Draw a smaller inner rectangle
draw.rectangle((BORDER, BORDER, display.width - BORDER - 1, display.height - BORDER - 1),
               outline=0, fill=0)

Here's what our virtual canvas looks like in memory.

Now drawing text with PIL is pretty straightforward. First we start by setting the font to the default system text. After that we define our text and get the size of the text. We're grabbing the size that it would render at so that we can calculate the center position. Finally, we take the font size and screen size to calculate the position we want to draw the text at and it appears in the center of the screen.

Download: file
# Load a TTF font.
font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', FONTSIZE)

# Draw Some Text
text = "Hello World!"
(font_width, font_height) = font.getsize(text)
draw.text((display.width//2 - font_width//2, display.height//2 - font_height//2),
          text, font=font, fill=255)

Finally, we need to display our virtual canvas to the LCD and we do that with 2 commands. First we set the image to the screen, then we tell it to show the image.

Download: file
# Display image
display.image(image)
display.show()
Don't forget you MUST call display.image(image) and display.show() to actually display the graphics. The LCD takes a while to draw so cluster all your drawing functions into the buffer (fast) and then display them once to the LCD (slow)

Here's what the final output should look like.

This guide was first published on Dec 17, 2012. It was last updated on Dec 17, 2012. This page (Python Usage) was last updated on Feb 27, 2020.