Driving a Hitachi HD44780 with Python

Sending stuff to a display is pretty cool, as are cheap Hitachi HD44780 compatible LCD character displays that can be found on ebay. They’re pretty eeasy to work with but they do use a lot (most) of the GPIO a Raspberry Pi has to offer.

This is only really here because it exists, I guess it’s for the noobs. Adding this type of display is a kind of hello world in RPi hardware, I was a nooob when I first did this stuff on an arduino so it’s fine to have something to poke at.

I wrote this very basic python library for a simple project that needed to put two lines of text on a 16×2 screen (next time I’ll be using a display that supports I²C). It’s pretty well documented and has the pin wiring included (although you are not tied to this arrangement if you override init)

#!/usr/bin/python
import RPi.GPIO as GPIO
from time import sleep

# BCMHD44780 - A library for interfacing RPi with Hitachi 44780 driven LCD displays
# Author - Terry Hurcombe
# There are some sleeps in here that you might want to remove if you drive an
# oled display as these update soooo much quicker than their LCD brothers

# The HD44780 is a common LCD driver, a datasheet can be found at
# https://www.sparkfun.com/datasheets/LCD/HD44780.pdf
#
# There are oleds on the market now which claim to use a
# HD44780 "compatible" controller but I wasted way too much time
# on that and no success yet. It definitely needs sorting though
# because the oleds are far superior.
#
# Here are the pinouts for the LCD although I know these
# off the top of my head now
#
# 1 GND
# 2 VCC 5v
# 3 Contrast via pot or tie to ground (which is what I do, works fine)
# 4 Register Select (0=command, 1=data). Tie to GPIO 25
# 5 Read/Write (LCD Operates at 5v logic), tie ths to ground for the rpi's 3.3v
# 6 Enable. Tie to GPIO24
# 7-10 data pins not used in 4bit operation so do not connect
# 11-14 are data pins we will use, tie to GPIO 23,17,21,22
# 15 Backlight +5v (DNC if oled)
# 16 Backlight GND (DNC if oled)

# Caveats
# very basic and coded just for 16x2

class BCMHD44780:

def __init__(self, pinRs=25, pinE=24, pinsDb=[23, 17, 27, 22]):
'Object Constructor'
self.pinRs = pinRs
self.pinE = pinE
self.pinsDb = pinsDb

# use broadcom pin numbering
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

# set lcd enable and register select
# as gpio outputs
GPIO.setup(self.pinE, GPIO.OUT)
GPIO.setup(self.pinRs, GPIO.OUT)

# also set our 4 data pins to out output
for pin in self.pinsDb:
GPIO.setup(pin, GPIO.OUT)

self.init()

def init(self):
'Initialize the display'
# make this a nice slow process to give the screen plenty of time
self.cmd(0x28); # set 4bit mode
sleep(0.5);
self.cmd(0x01) # clear DDRAM
sleep(0.5);
self.cmd(0x0C) # display on, cursor off
sleep(0.5);
self.cmd(0x80) # cursor @ 0,0
sleep(0.5);
self.cmd(0x06) # entry mode

def off(self):
'Turn off the display' # doe not turn off backlight
self.cmd(0x00);

def on(self):
'Turn on the display'
self.cmd(0x0C);

def cmd(self, bits, dataMode=False):
'Send command to LCD'

# convert our bits to a binary string left padded to 8bits
bits=bin(bits)[2:].zfill(8)

GPIO.output(self.pinRs, dataMode)

# set all data pins off
for pin in self.pinsDb:
GPIO.output(pin, False)

# send the first 4 bits
for i in range(4):
if bits[i] == "1":
GPIO.output(self.pinsDb[::-1][i], True)

# pulse enable/clock
GPIO.output(self.pinE, True)
GPIO.output(self.pinE, False)

# all data lines off
for pin in self.pinsDb:
GPIO.output(pin, False)

# send last bits
for i in range(4,8):
if bits[i] == "1":
GPIO.output(self.pinsDb[::-1][i-4], True)

# pulse clock again
GPIO.output(self.pinE, True)
GPIO.output(self.pinE, False)

def message(self, line1,line2):
'Send a 2 line message to the LCD'

# pad out to 16 chars although this should be
# made more generic in the future for different
# character display widths
line1 = line1.ljust(16, ' ');
line2 = line2.ljust(16, ' ');

# sets DDRAM pointer to line 1
self.cmd(0x80);

# send hex to DDRAM for each char in out strings
# to do this we send the char as its UTF-16 decimal
# identifier (think HTML entity)
for char in line1:

self.cmd(ord(char),True)

self.cmd(0xC0) # set DDRAM pointer to line 2

# rinse and repeat
for char in line2:
self.cmd(ord(char),True)

To use

import BCMHD44780
charLCD = new BCMHD44780()
charLCD.message('Text For Line 1','Text For Line 2')

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>