Once you’ve played with LEDs, switches and stepper motors the next natural step is 16×2 alphanumeric LCD modules. These modules are cheap (less than $10) and easy to interface to the Raspberry Pi. They have 16 connections but you only need to use 6 GPIO pins on your Pi.
Most of the 16×2 modules available are compatible with the Hitachi HD44780 LCD controller. This allows you to buy almost any device and be sure it is going to work in much the same way as any other. There are loads to choose from on eBay with different coloured backlights. The one I purchased had a blue backlight.
LCD Module Hardware
- Ground
- VCC (Usually +5V)
- Contrast adjustment (VO)
- Register Select (RS).
RS=0: Command, RS=1: Data - Read/Write (R/W).
R/W=0: Write, R/W=1: Read - Enable
- Bit 0 (Not required in 4-bit operation)
- Bit 1 (Not required in 4-bit operation)
- Bit 2 (Not required in 4-bit operation)
- Bit 3 (Not required in 4-bit operation)
- Bit 4
- Bit 5
- Bit 6
- Bit 7
- LED Backlight Anode (+)
- LED Backlight Cathode (-)
Usually the device requires 8 data lines to provide data to Bits 0-7. However the device can be set to a “4 bit” mode which allows you to send data in two chunks (or nibbles) of 4 bits. This is great as it reduces the number of GPIO connections you require when interfacing with your Pi.
Here is how I wired up my LCD :
| LCD Pin | Function | Pi Function | Pi Pin |
| 01 | GND | GND | P1-06 |
| 02 | +5V | +5V | P1-02 |
| 03 | Contrast | GND | P1-06 |
| 04 | RS | GPIO7 | P1-26 |
| 05 | RW | GND | P1-06 |
| 06 | E | GPIO8 | P1-24 |
| 07 | Data 0 | ||
| 08 | Data 1 | ||
| 09 | Data 2 | ||
| 10 | Data 3 | ||
| 11 | Data 4 | GPIO25 | P1-22 |
| 12 | Data 5 | GPIO24 | P1-18 |
| 13 | Data 6 | GPIO23 | P1-16 |
| 14 | Data 7 | GPIO18 | P1-12 |
| 15 | +5V via 560ohm | ||
| 16 | GND | P1-06 |
NOTE : The RW pin allows the device to be be put into read or write mode. I wanted to send data to the device but did not want it to send data to the Pi so I tied this pin to ground. The Pi can not tolerate 5V inputs on its GPIO header. Tying RW to ground makes sure the device does not attempt to pull the data lines to 5V which would damage the Pi.
In order to control the contrast you can adjust the voltage presented to Pin 3. This must be between 0 and 5V. I tied this pin to ground.
Pin 15 provides 5V to the backlight LED. It wasn’t clear on my device if this could be connected direct to 5V so I played safe and placed a 560ohm resistor in line with this pin.

Wiring Checks
Here are some sanity checks before you power up your circuit for the first time :
- Pin 1 (GND), 3 (Contrast), 5 (RW) and 16 (LED -) ( should be tied to ground.
- Pin 2 should be tied to 5V. Pin 15 should have a resistor inline to 5V to protect the backlight.
- Pin 7-10 are unconnected
- Pin 11-14 are connected to GPIO pins on the Pi
Python
You can control a HD44780 style display using any programmming environment you like but my weapon of choice is Python. I use the RPi.GPIO library to provide access to the GPIO.
Here is my code :
#!/usr/bin/python
#
# HD44780 LCD Test Script for
# Raspberry Pi
#
# Author : Matt Hawkins
# Site : http://www.raspberrypi-spy.co.uk
#
# Date : 26/07/2012
#
# The wiring for the LCD is as follows:
# 1 : GND
# 2 : 5V
# 3 : Contrast (0-5V)*
# 4 : RS (Register Select)
# 5 : R/W (Read Write) - GROUND THIS PIN
# 6 : Enable or Strobe
# 7 : Data Bit 0 - NOT USED
# 8 : Data Bit 1 - NOT USED
# 9 : Data Bit 2 - NOT USED
# 10: Data Bit 3 - NOT USED
# 11: Data Bit 4
# 12: Data Bit 5
# 13: Data Bit 6
# 14: Data Bit 7
# 15: LCD Backlight +5V**
# 16: LCD Backlight GND
#import
import RPi.GPIO as GPIO
import time
# Define GPIO to LCD mapping
LCD_RS = 7
LCD_E = 8
LCD_D4 = 25
LCD_D5 = 24
LCD_D6 = 23
LCD_D7 = 18
# Define some device constants
LCD_WIDTH = 16 # Maximum characters per line
LCD_CHR = True
LCD_CMD = False
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
# Timing constants
E_PULSE = 0.00005
E_DELAY = 0.00005
def main():
# Main program block
GPIO.setmode(GPIO.BCM) # Use BCM GPIO numbers
GPIO.setup(LCD_E, GPIO.OUT) # E
GPIO.setup(LCD_RS, GPIO.OUT) # RS
GPIO.setup(LCD_D4, GPIO.OUT) # DB4
GPIO.setup(LCD_D5, GPIO.OUT) # DB5
GPIO.setup(LCD_D6, GPIO.OUT) # DB6
GPIO.setup(LCD_D7, GPIO.OUT) # DB7
# Initialise display
lcd_init()
# Send some test
lcd_byte(LCD_LINE_1, LCD_CMD)
lcd_string("Rasbperry Pi")
lcd_byte(LCD_LINE_2, LCD_CMD)
lcd_string("Model B")
time.sleep(3) # 3 second delay
# Send some text
lcd_byte(LCD_LINE_1, LCD_CMD)
lcd_string("Raspberrypi-spy")
lcd_byte(LCD_LINE_2, LCD_CMD)
lcd_string(".co.uk")
time.sleep(20)
def lcd_init():
# Initialise display
lcd_byte(0x33,LCD_CMD)
lcd_byte(0x32,LCD_CMD)
lcd_byte(0x28,LCD_CMD)
lcd_byte(0x0C,LCD_CMD)
lcd_byte(0x06,LCD_CMD)
lcd_byte(0x01,LCD_CMD)
def lcd_string(message):
# Send string to display
message = message.ljust(LCD_WIDTH," ")
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]),LCD_CHR)
def lcd_byte(bits, mode):
# Send byte to data pins
# bits = data
# mode = True for character
# False for command
GPIO.output(LCD_RS, mode) # RS
# High bits
GPIO.output(LCD_D4, False)
GPIO.output(LCD_D5, False)
GPIO.output(LCD_D6, False)
GPIO.output(LCD_D7, False)
if bits&0x10==0x10:
GPIO.output(LCD_D4, True)
if bits&0x20==0x20:
GPIO.output(LCD_D5, True)
if bits&0x40==0x40:
GPIO.output(LCD_D6, True)
if bits&0x80==0x80:
GPIO.output(LCD_D7, True)
# Toggle 'Enable' pin
time.sleep(E_DELAY)
GPIO.output(LCD_E, True)
time.sleep(E_PULSE)
GPIO.output(LCD_E, False)
time.sleep(E_DELAY)
# Low bits
GPIO.output(LCD_D4, False)
GPIO.output(LCD_D5, False)
GPIO.output(LCD_D6, False)
GPIO.output(LCD_D7, False)
if bits&0x01==0x01:
GPIO.output(LCD_D4, True)
if bits&0x02==0x02:
GPIO.output(LCD_D5, True)
if bits&0x04==0x04:
GPIO.output(LCD_D6, True)
if bits&0x08==0x08:
GPIO.output(LCD_D7, True)
# Toggle 'Enable' pin
time.sleep(E_DELAY)
GPIO.output(LCD_E, True)
time.sleep(E_PULSE)
GPIO.output(LCD_E, False)
time.sleep(E_DELAY)
if __name__ == '__main__':
main()
If you use this code the only thing you will need to change is the GPIO pin mapping depending on what pins you use on your Pi GPIO header. Here are some photos :
Additional Notes : RS is low when sending a command to the LCD and high when sending a character. RW is always low to ensure we only ever input data into the module. 8 bit bytes are sent 4 bits at a time. Top 4 bits first and the last 4 bits second. Delays are added between certain steps to ensure the module can react to the signal before it changes.
The code above was inspired by code submitted by ‘texy’ on the RaspberryPi.org forum. I changed the way the bytes are broken down to bits as this significantly increased the response time of the display.






Hi,
your example works fine but i’m hving problems using 20×4 LCD – what do I need to change in the script to show all 4 lines?
thanks, dex
I haven’t got a 20×4 LCD so I can’t check this but try …
Change LCD_WIDTH = 16 to LCD_WIDTH = 20
Update the line addresses to :
LCD_LINE_1 = 0×00 # LCD RAM address for the 1st line
LCD_LINE_2 = 0×80 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0×40 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xC0 # LCD RAM address for the 4th line
Hmm, am I misreading something or is there some confusion under
“Here is how I wired up my LCD”
you say you wire LCD pin 1 to +5V p1_02 – but the LCD pin 01 is GND right?
So under “Here is how I wired up my LCD” the LCD pin 01 should actually be to GND (p1_06) and LCD pin 02 to +5V (p1_02)?
And in the schematics and “Wiring Checks” you say connect pin 1 to GND.
Am I just tired and misreading?
Thanks for the tutorial, making my way through it now! Just wanted to ask you that
You are correct. Thanks for spotting it. I’ve updated the table . LCD Pin 1 is Ground and Pin 2 is +5V.
Very nice tutorial, but there is another slight mistake. Under “Here is how I wired up my LCD” you used GPIO 7 and 8 for RS and E, but in your python code you set RS to 26 and E to 24. I had to change these lines to get my LCD working.
Thanks Markus. I’ve corrected it now. The example uses GPIO pins that make the breadboard diagram easier but this is different to my real test circuit. I got confused between the two!
hi I’m getting stuck with this, i cant get any output from the screen. It’s lit but nothing when I run the code.
1. I’m running 2.7 python
2. I’m running Raspbian
3. I’m running the RPi.GPIO-0.3.1a
4. I’m running python-rpi.gpio_0.3.1a-1_armhf.deb
5. And i’m pretty sure my wireing is correct.
Was a problem with my contrast pin (3) fixed now
Hi Matt.
Thank you for this tutorial.
I had a problem.
When the python’s script has finished, display fills by 32 characters of “inverted P”.
Here is video:
http://youtu.be/mrIJaIcRGkE
It caused probably by electomagnetic noise (long wires between Raspberry and display).
http://www.astromik.org/raspi/dis-wired.jpg
I solved this problem attaching resistor 150k between pins 2 and 6 on the display port.
Here is a picture:
http://www.astromik.org/raspi/dis-resistor.jpg
Now is all OK.
—
… excuse my english
I think this is because when the script finishes the RPi.GPIO library configures all the pins as inputs. This leaves the Enable pin floating. Adding a resistor pulls it high so the screen doesn’t reset. I might give this a try on my circuit.
i wired my screen up the same as yours but its VERY dark.
theres no colour to the screen (i.e blue) and the character blocks are barely visible.
using a 3.3k resistor as i couldnt find a 5600ohm. only other ones i have are 10k, 430, 330 resistors
The LED backlight resistor is 560 ohm not 5600 ohm. If you are using 3.3K then the LED isn’t getting enough current. Use a 430 instead and that should light up the screen a bit better.
I have gotten everything wired up and double checked everything, though I only get squares all the way across the LCD screen. I re wired everything just to make sure it was done correctly, still the same issue.
Any ideas?
Side note: I am also a bit unsure on the need for the resistor, the LCD can operate between 2.7 to 5.5V. Is the resistors purpose to stop the LCD from pulling more than 5v?
All fixed, was connectivity issues with the squares showing up. Once I had fixed that problem I then started getting weird characters showing up. That was also fixed by setting up my locale settings OR by ignoring what the SSH client sent as a locale. Everything is working good now, nice tutorial! Bit confusing in parts though.
The resistor is for the LED backlight not the LCD itself. It usually isn’t clear but some LCD modules do not include a resistor to limit the current drawn by the LED backlight. So I always put one in to be sure.
Thanks for the great tutorial.
I’ve tried this and have a worrying problem. I don’t see any text, just black squares accross the lower line of the display. What concerns me is that the data lines each read 5v when I run the Python script.
Pin 5 is *definitely* grounded, and since the Pi should only ouput 3.3v on these pins I’m guessing this must mean a fault in the LCD?
Any suggestions would be greatly appreciated.
Many thanks,
Matt
Unhelpfully I’ve signed the above comment “Matt”. Apologies!