Connecting an LCD to a Raspberry Pi

CONNECTING AN LCD TO A RASPBERRY PI
A character LCD display can be a good way to visually output information from your Raspberry Pi. 16×2 alphanumeric LCD modules are cheap and there are loads of different type to choose from on eBay with different coloured backlights. Most of the 16×2 modules available on eBay are compatible with the Hitachi HD44780 LCD controller and it means that it is going to work (hopefully!) in the same way as any other. The LCD modules have 16 connections but they are easy to interface to the Raspberry Pi, requiring only 6 GPIO pins on your Pi in “4 bit” mode. Usually the HD44780 requires 8 data lines to provide data to Bits 0-7. However in the “4 bit” mode, only 4 data lines is required, allowing data to be sent in two chunks of 4 bits. This post focuses on connecting an LCD to a Raspberry Pi and controlling it with Python.

For this post, we bought a 1602 16×2 Character LCD Display Module HD44780 Controller Blue Blacklight from eBay for only £1.17!

LCD connections

We used a Raspberry Pi B+ V1.2 and the connections between the LCD and the Pi are as follows:

LCD Pin Function Pi Pin
1 GND GND
2 +5V +5V
3 Vo (Contrast) GND
4 RS GPIO-14
5 RW GND
6 Enable GPIO-18
7 D0 Not in Use
8 D1 Not in Use
9 D2 Not in Use
10 D3 Not in Use
11 D4 GPIO-24
12 D5 GPIO-23
13 D6 GPIO-8
14 D7 GPIO-25
15 +5V (Backlight) +5V
16 GND(Backlight) GND

A schematic showing how to connect your LCD to a Raspberry Pi is also presented below:
connecting an LCD to a Raspberry Pi

Python Script

There are a range of different code available on GitHub that supports the HD44780 LCD controller. Some online forum posts suggest that the Adafruit LCD library can also be used with third-party HD44780 LCD controllers. A good article can also be found at Raspberry-Spy where the author has written his code from scratch. So we decided to use bits of Adafruit code, the data command from the HD44780 datasheet and Raspberry-Spy code to write our own.

#!/usr/bin/python
#--------------------------------------
#  16x2 LCD Rasbperry Pi Test Script
#
# Author : BehindTheSciences
# Date   : 14/02/2017
#
# https://behindthesciences.com
#
#--------------------------------------
#import
import RPi.GPIO as GPIO
import time

# Commands
LCD_CLEARDISPLAY        = 0x01
LCD_RETURNHOME          = 0x02
LCD_ENTRYMODESET        = 0x04
LCD_DISPLAYCONTROL      = 0x08
LCD_CURSORSHIFT         = 0x10
LCD_FUNCTIONSET         = 0x20
LCD_SETCGRAMADDR        = 0x40
LCD_SETDDRAMADDR        = 0x80
# Entry flags
LCD_ENTRYRIGHT          = 0x00
LCD_ENTRYLEFT           = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# Control flags
LCD_DISPLAYON           = 0x04
LCD_DISPLAYOFF          = 0x00
LCD_CURSORON            = 0x02
LCD_CURSOROFF           = 0x00
LCD_BLINKON             = 0x01
LCD_BLINKOFF            = 0x00
# Move flags
LCD_DISPLAYMOVE         = 0x08
LCD_CURSORMOVE          = 0x00
LCD_MOVERIGHT           = 0x04
LCD_MOVELEFT            = 0x00
# Function set flags
LCD_8BITMODE            = 0x10
LCD_4BITMODE            = 0x00
LCD_2LINE               = 0x08
LCD_1LINE               = 0x00
LCD_5x10DOTS            = 0x04
LCD_5x8DOTS             = 0x00

# Offset for up to 4 rows.
LCD_ROW_OFFSETS         = (0x00, 0x40, 0x14, 0x54)

# GPIO to LCD mapping
LCD_RS            = 14
LCD_EN            = 18
LCD_D4            = 24
LCD_D5            = 23
LCD_D6            = 8
LCD_D7            = 25
# Define some device constants
LCD_WIDTH = 16    # Maximum characters per line
LCD_CHR = True
LCD_CMD = False
LCD_LINE_1 = LCD_SETDDRAMADDR # LCD RAM address for the 1st line
LCD_LINE_2 = LCD_SETDDRAMADDR | LCD_ROW_OFFSETS[1] # LCD RAM address for the 2nd line
 
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
 
def main():
  # Main program block
  GPIO.setwarnings(False)
  GPIO.setmode(GPIO.BCM)       # Use BCM GPIO numbers
  GPIO.setup(LCD_EN, GPIO.OUT)  # EN
  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()
 
  while True:
 
    # Send some test
    lcd_string("Rasbperry Pi",LCD_LINE_1)
    lcd_string("16x2 LCD Test",LCD_LINE_2)
 
    time.sleep(3) # 3 second delay
 
    # Send some text
    lcd_string("1234567890123456",LCD_LINE_1)
    lcd_string("abcdefghijklmnop",LCD_LINE_2)
 
    time.sleep(3) # 3 second delay
 
    # Send some text
    lcd_string("BehindTheScience",LCD_LINE_1)
    lcd_string("s.com",LCD_LINE_2)
 
    time.sleep(3)
 
    lcd_string("1234567890123456",LCD_LINE_1)
    lcd_string("ABCDEFGHIJKLMNOP",LCD_LINE_2)
 
    time.sleep(3) # 3 second delay
 
    time.sleep(3)
 
def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD) # 110011 Initialise
  lcd_byte(0x32,LCD_CMD) # 110010 Initialise
  # 000110 Cursor move direction
  lcd_byte(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT,LCD_CMD) 
  # Initialize display control, function, and mode registers.
  # 001100 Display On,Cursor Off, Blink Off
  lcd_byte(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF,LCD_CMD)
  # 101000 Data length, number of lines, font size
  lcd_byte(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_2LINE | LCD_5x8DOTS,LCD_CMD) # 101000 Data length, number of lines, font size
  # 000001 Clear display
  lcd_byte(LCD_CLEARDISPLAY,LCD_CMD) 
  time.sleep(E_DELAY)
 
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
  lcd_toggle_enable()
 
  # 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
  lcd_toggle_enable()
 
def lcd_toggle_enable():
  # Toggle enable
  time.sleep(E_DELAY)
  GPIO.output(LCD_EN, True)
  time.sleep(E_PULSE)
  GPIO.output(LCD_EN, False)
  time.sleep(E_DELAY)
 
def lcd_string(message,line):
  # Send string to display
 
  message = message.ljust(LCD_WIDTH," ")
 
  lcd_byte(line, LCD_CMD)
 
  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)
 
if __name__ == '__main__':
 
  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    GPIO.cleanup()

The script can also be downloaded here.

Or if you want to download it directly to your Pi, use the following:

wget https://behindthesciences.com/wp-content/uploads/2017/02/LCD_RPi1.py

Use the following to run it:

sudo LCD_RPi1.py

The script was tested with Python 2.7.9. The code presented here was inspired by Raspberry-Spy.
If you use this code with different GPIO pin mapping, make sure to change it in the code. Here are some photos of our working LCD with the Raspberry Pi:
Raspberry Pi connections to LCD
Raspberry Pi LCD test
Raspberry Pi LCD test 1
If you have any comments or questions, please email us at contact@behindthesciences.com

4 Comments

Add a Comment

Your email address will not be published. Required fields are marked *

Show Buttons
Hide Buttons