Using LCD HD44780 on Raspberry Pi – part 1: GPIO


Right or left 🙂


So we can get weather data for our town and it would be good idea to display it somewhere. Time has come to dig into all kinds of LCDs. We will start from basic one – char LCD 20×4 based on HD44780.




  • Raspberry Pi B r2 / Raspberry Pi B+
  • LCD 20 chars / 4 rows or LCD 16 / 2 or any based on HD44780
  • prototype board and wires to connect everything
  • 2 potentiometers (10k or 5k)

Before we will play with code download and open documentation. Its our holy book :).

We will draw +5V from Raspi, its not the best way but enough for this tutorial.

This part wont require any additional installations. Raspi out of the box is ready.

There are few kinds of char screens. It goes for size and pin outs.


We have lots of way to connect LCD with Raspi. First we will focus on using GPIO pins as its the simplest way. You may use 20/4 or 16/2 with pins on top, there is also version with pins on left. I’m using 20/4 top pins but our code will support all combinations.


LCD 20 / 4 pins on top



LCD 16 / 2 pins on left



LCD <———————-> Raspberry Pi

LCD1 [VSS] ------------- GND
LCD2 [VDD] ------------- +5V
LCD3 [V0] ------/\/\/\ [potentiometer]
                   \---- GND
LCD4 [RS] -------------- GPIO 25
LCD5 [R/W] ------------- GND
LCD6 [E] --------------- GPIO 24
LCD7 [DB0]
LCD8 [DB1]
LCD9 [DB2]
LCD10 [DB3]
LCD11 [DB4] ------------ GPIO 22
LCD12 [DB5] ------------ GPIO 23
LCD13 [DB6] ------------ GPIO 27
LCD14 [DB7] ------------ GPIO 17
LCD15 [A] ------/\/\/\ [potentiometer]
                   \---- +5V
LCD16 [K] -------------- GND

As you can see we will be using 6 GPIOs. Not much but if you want to plug more than one LCD… well it would be better to use I2C  – but this later.
Using only 4 data signals is possible because HD44780 support 4bit and 8bit interface.

Now adjust potentiometers so you will some some backlight and something on the screen. After powering you should see one line of squares.

WARNING: DB0 – DB7 may work as input or output. Output is +5V – it may damage your Raspberry Pi ! Double, triple check if R/W is connected to the ground !

And because of this we wont read busy signal from LCD, we will just sleep for some time.


Lets begin ! Create project in your favourite IDE (PyCharm :P). Create project lets name it lcds, and in this project create package charlcd. Now add two empty files and according to this structure:


Lets open and copy:

# -*- coding: utf-8 -*-
__author__ = 'kosci'
import RPi.GPIO as GPIO
import time


LCD_LINE_1 = 0x80
LCD_LINE_2 = 0xC0
LCD_LINE_3 = 0x94
LCD_LINE_4 = 0xD4

class CharLCD (object):
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.PINS = {
            'RS': 25, #0 -&gt;instruction, 1-&gt;data
            'E': 24,
            'DB4': 22,
            'DB5': 23,
            'DB6': 27,
            'DB7': 17
        self.DATA_PINS = [

    def init(self):
        #setup pins
        for p in self.PINS:
            GPIO.setup(self.PINS[p], GPIO.OUT)
            GPIO.output(self.PINS[p], 0)



    def string(self, s):
        for l in s:

    def char(self, c):
        GPIO.output(self.PINS['RS'], 1)

    def cmd(self, c):
        GPIO.output(self.PINS['RS'], 0)

    def cmd4(self, c):
        GPIO.output(self.PINS['RS'], 0)

    def shutdown(self):

    def _send(self):
        GPIO.output(self.PINS['E'], 1)
        GPIO.output(self.PINS['E'], 0)

    def _write4(self, c):
        for i in self.DATA_PINS:
            t = c &amp; 0x01
            GPIO.output(self.PINS[i], t)
            c &gt;&gt;= 1

    def _write(self, c):
        data = (c &gt;&gt; 4)
        for i in self.DATA_PINS:
            t = data &amp; 0x01
            GPIO.output(self.PINS[i], t)
            data &gt;&gt;= 1

        data = (c &amp; 0x0F)
        for i in self.DATA_PINS:
            t = data &amp; 0x01
            GPIO.output(self.PINS[i], t)
            data &gt;&gt;= 1


Each cell on LCD have its own address. Each line begins with each address. So we define beginning of 4 lines. Maximum for this type of LCD is 20 chars per 4 lines. But you probably saw 40 chars / 4 lines – they are actually two LCDs in one. Don’t worry for now, later we will plug such screen.

Lets look at __init__(self, width, height). Its very simple and incomplete for now. We are sending width and height but never use them. Next we define pins and separately data pins. Data pins will make our life easer in self._write function.

Now time for important function init(). First we setup GPIO pins and set output to 0. At this point we have GPIOs ready, LCD ready and all wiring ready. Time to initialize screen.

Open documentation  and search for Initialization of the HD44780. You will read in what state is LCD after boot. Next are two sections 8bit and 4bit initialization. We are going with 4bit one and using only DB7, DB6, DB5 and DB4 as data input. In 4bit mode we are sending 8bit in 2 steps, first high bits and next low bits.

Sending data/command to LCD in 4bit mode goes like this:

  • set pin RS low for command or high for data
  • from byte get 4 high bits and set data pins
  • set pin E high
  • set pin E low
  • set data pins to 4 low bits
  • set pin E high
  • set pin E low

After start LCD is in 8bit mode but we need 4bit mode. Now lets look at documentation. We need to setup our screen. To do this we need to send command.

We need to send DB5 & DB4 (its 3), wait and do it three times. Next we need to tell LCD that we want 4bits mode. So just send 2 (only DB5 = 1). Because we are in 8bit mode and we are sending only DB5 – others bits are undefined. After setting 4bits mode we need to set settings again. So we need two send function, one that works in 8bit mode (just send high bits) and second that send high and low bits. That’s why we have self.cmd(self, c), self._write(self, c)  and self.cmd4(self, c), self._write4(self, c). First send high and low, second only 4 high bits.

Next commands sets more screen options. Lets see what they do:


Hex 0x28 is binary 0010 1000,  position of first 1 tells us that this is Function set.  Now decode it, after 1 is DL bit – it tells if its 4 or 8 bit mode. We have 0 – 4 bit mode.  Next we have N bit = 1, so we have two lines. Next is F bit = 0, 5×8 dots per char. Last two 0 are irrelevant.

Next commands decode yourself 🙂

And after all this we are ready to display something.

Last two functions are to display char on screen or string.


Test code

And time for, copy:

# -*- coding: utf-8 -*-
__author__ = 'kosci'

from charlcd import lcd

l = lcd.CharLCD(20, 4)
l.string('Tutorial v 1')
l.char(' ')



lcd_20_tutorial_1Its very simple code to display string on screen. Its not aware of LCD size and doesn’t have functions to format input. Its also GPIO only version.

In next tutorial we will extract functions that drive a hardware into driver class. It will allow us later to add different kind of drivers, for I2C, larger screens and other strange wiring methods.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.