15 min read

In this article by Samarth Shah, author of the book Learning Raspberry Pi, we will take your Raspberry Pi to the real world. Make sure you have all the components listed for you to go ahead:

  • Raspberry Pi with Raspbian OS.
  • A keyboard/mouse.
  • A monitor to display the content of Raspberry Pi. If you don’t have Raspberry Pi, you can install the VNC server on Raspberry Pi, and on your laptop using the VNC viewer, you will be able to display the content.
  • Hook up wires of different colors (keep around 30 wires of around 10 cm long). To do: Read instructions on how to cut the wires.
  • An HD44780-based LCD. Note; I have used JHD162A.
  • A breadboard.
  • 10K potentiometer (optional). You will be using potentiometer to control the contrast of the LCD, so if you don’t have potentiometer, contrast would be fixed and that would be okay for this project.

Potentiometer is just a fancy word used for variable resistor. Basically, it is just a three-terminal resistor with sliding or rotating contact, which is used for changing the value of the resistor.

(For more resources related to this topic, see here.)

Setting up Raspberry Pi

Once you have all the components listed in the previous section, before you get started, there are some software installation that needs to be done:

Sudo apt-get update

For controlling GPIO pins of Raspberry Pi, you will be using Python so for that python-dev, python-setuptools, and rpi.gpio (the Python wrapper of WiringPi) are required. Install them using the following command:

Sudo apt-get install python-dev
Sudo apt-get install python-setuptools
Sudo apt-get install rpi.gpio

Now, your Raspberry Pi is all set to control the LCD, but before you go ahead and start connecting LCD pins with Raspberry Pi GPIO pins, you need to understand how LCD works and more specifically how HD44780 based LCD works.

Understanding HD44780-based LCD

The LCD character displays can be found in espresso machines, laser printers, children’s toys, and maybe even the odd toaster. The Hitachi HD44780 controller has become an industry standard for these types of displays. If you look at the back side of the LCD that you have bought, you will find 16 pins:

Vcc / HIGH / ‘1’

+5 V

GND / LOW / ‘0’

0 V

The following table depicts the HD44780 pin number and functionality:

Pin number

Functionality

1

Ground

2

VCC

3

Contrast adjustment

4

Register select

5

Read/Write(R/W)

6

Clock(Enable)

7

Bit 0

8

Bit 1

9

Bit 2

10

Bit 3

11

Bit 4

12

Bit 5

13

Bit 6

14

Bit 7

15

Backlight anode (+)

16

Backlight cathode (-)

Pin 1 and Pin 2 are the power supply pins. They need to be connected with ground and +5 V power supply respectively.

Pin 3 is a contrast setting pin. It should be connected to a potentiometer to control the contrast. However, in a JHD162A LCD, if you directly connect this pin to ground, initially, you will see dark boxes but that will work if you don’t have potentiometer.

Pin 4, Pin 5, and Pin 6 are the control pins.

Pin 7 to Pin 14 are the data pins of LCD. Pin 7 is the least significant bit and pin 14 is the most significant bit of the date inputs. You can use LCD in two modes, that is, 4-bit or 8-bit. In the next section, you will be doing 4-bit operation to control the LCD. If you want to display some number/character on the display, you have to input the appropriate codes for that number/character on these pins.

Pin 15 and Pin 16 provide power supply to the backlight of LCD. A backlight is a light within the LCD panel, which makes seeing the characters on the screen easier. When you leave your cell phone or MP3 player untouched for some time, the screen goes dark. This is the backlight turning off. It is possible to use the LCD without the backlight as well. JHD162A has a backlight, so you need to connect the power supply and ground to these pins respectively.

Pin 4, Pin 5, and Pin 6 are the most important pins. As mentioned in the table, Pin 4 is the register select pin. This allows you to switch between two operating modes of the LCD, namely the instruction and character modes. Depending on the status of this pin, the data on the 8 data pins (D0-D7) is treated as either an instruction or as character data. To display some characters on LCD, you have to activate the character mode. And to give some instructions such as “clear the display” and “move cursor to home”, you have to activate the command mode. To set the LCD in the instruction mode, set Pin 4 to ‘0’ and to put it in character mode, set Pin 4 to ‘1’. Mostly, you will be using the LCD to display something on the screen; however, sometimes you may require to read what is being written on the LCD. In this case, Pin 5 (read-write) is used. If you set Pin 5 to 0, it will work in the write mode, and if you set Pin 5 to 1, it will work in the read mode. For all the practical purposes, Pin 5 (R/W) has to be permanently set to 0, that is, connect it with GND (Ground). Pin 6 (enable pin) has a very simple function. This is just the clock input for the LCD. The instruction or the character data at the data pins (Pin 7-Pin 14) is processed by the LCD on the falling edge of this pin. The enable pin should be normally held at 1, that is, Vcc by a pull up resistor. When a momentary button switch is pressed, the pin goes low and back to high again when you leave the switch. Your instruction or character will be executed on the falling edge of the pulse, that is, the moment when the switch get closed.

So, the flow diagram of a typical write sequence to LCD will be:

Learning Raspberry Pi

Connecting LCD pins and Raspberry Pi GPIO pins

Having understood the way LCD works, you are ready to connect your LCD with Raspberry Pi. Connect LCD pins with Raspberry Pi pins using following table:

LCD pins

Functionality

Raspberry Pi pins

1

Ground

Pin 6

2

Vcc

Pin 2

3

Contrast adjustment

Pin 6

4

Register select

Pin 26

5

Read/Write (R/W)

Pin 6

6

Clock (Enable)

Pin 24

7

Bit 0

Not used

8

Bit 1

Not used

9

Bit 2

Not used

10

Bit 3

Not used

11

Bit 4

Pin 22

12

Bit 5

Pin 18

13

Bit 6

Pin 16

14

Bit 7

Pin 12

15

Backlight anode (+)

Pin 2

16

Backlight cathode (-)

Pin 6

Your LCD should have come with 16-pin single row pin header (male/female) soldered with 16 pins of LCD. If you didn’t get any pin header with the LCD, you have to buy a 16-pin single row female pin header. If the LCD that you bought doesn’t have a soldered 16-pin single row pin header, you have to solder it. Please note that if you have not done soldering before, don’t try to solder it by yourself. Ask some of your friends who can help or the easiest option is to take it to the place from where you have bought it; he will solder it for you in merely 5 minutes.

The final connections are shown in the following screenshot. Make sure your Raspberry Pi is not running when you are connecting LCD pins with Raspberry Pi pins. Connect LCD pins with Raspberry Pi using hook up wires.

Learning Raspberry Pi

Before you start scripting, you need to understand few more things about operating LCD in a 4-bit mode:

  • LCD default is a 8-bit mode, so the first command must be set in a 8-bit mode instructing the LCD to operate in a 4-bit mode
  • In the 4-bit mode, a write sequence is a bit different than what has been depicted earlier for the 8-bit mode. In the following diagram, Step 3 will be different in the 4-bit mode as there are only 4 data pins available for data transfer and you cannot transfer 8 bits at the same time. So in this case, as per the HD44780 datasheet, you have to send the first Upper “nibble” to LCD Pin 11 to Pin 14. Execute those bits by making Enable pin to LOW (as instructions/character will get executed on the falling edge of the pulse) and back to HIGH again. Once you have sent the Upper “nibble”, send Lower “nibble” to LCD Pin 11 to Pin 14. To execute the instruction/character sent, set Enable Pin to LOW.

So, the typical 4-bit mode write process will look like this:

Learning Raspberry Pi

Scripting

Once you have connected LCD pins with Raspberry Pi, as per the previously shown diagram, boot up your Raspberry Pi. The following are the steps to develop a digital clock:

  1. Create a new python script by right-clicking Create | New File | DigitalClock.py.

    Here is the code that needs to be copied in the DigitalClock.py file:

    #!/usr/bin/python
    import RPi.GPIO as GPIO
    import time
    from time import sleep
    from datetime import datetime
    from time import strftime
    class HD44780:
    def __init__(self, pin_rs=7, pin_e=8,   pins_db=[18,23,24,25]):
       self.pin_rs=pin_rs
       self.pin_e=pin_e
       self.pins_db=pins_db
       GPIO.setmode(GPIO.BCM)
       GPIO.setup(self.pin_e, GPIO.OUT)
       GPIO.setup(self.pin_rs, GPIO.OUT)
       for pin in self.pins_db:
         GPIO.setup(pin, GPIO.OUT)
         self.clear()
    def clear(self):
       # Blank / Reset LCD
       self.cmd(0x33)
       self.cmd(0x32)
       self.cmd(0x28)
       self.cmd(0x0C)
       self.cmd(0x06)
       self.cmd(0x01)
    def cmd(self, bits, char_mode=False):
       # Send command to LCD
       sleep(0.001)
       bits=bin(bits)[2:].zfill(8)
       GPIO.output(self.pin_rs, char_mode)
       for pin in self.pins_db:
         GPIO.output(pin, False)
       for i in range(4):
         if bits[i] == "1":
           GPIO.output(self.pins_db[i], True)
       GPIO.output(self.pin_e, True)
       GPIO.output(self.pin_e, False)
       for pin in self.pins_db:
         GPIO.output(pin, False)
       for i in range(4,8):
         if bits[i] == "1":
           GPIO.output(self.pins_db[i-4], True)
    GPIO.output(self.pin_e, True)
       GPIO.output(self.pin_e, False)
    def message(self, text):
       # Send string to LCD. Newline wraps to second line
       for char in text:
         if char == 'n':
           self.cmd(0xC0) # next line
         else:
           self.cmd(ord(char),True)
    if __name__ == '__main__':
    while True:
       lcd = HD44780()
       lcd.message(" "+datetime.now().strftime(%H:%M:%S))
       time.sleep(1)
  2. Run the preceding script by executing the following command:
    sudo python DigitalClock.py

    This code accesses the Raspberry Pi GPIO port, which requires root privileges, so sudo is used.

  3. Now, your digital clock is ready. The current Raspberry Pi time will get displayed on the LCD screen.

Only 4 data pins of LCD are being connected, so this script will work for the LCD 4-bit mode.

I have used the JHD162A LCD, which is based on the HD44780 controller. Controlling mechanisms for all HD44780 LCDs are same. So, the preceding class, HD44780, can also be used for controlling another HD44780-based LCD.

Once you have understood the preceding LCD 4-bit operation, it will be much easier to understand this code:

if __name__ == '__main__':
while True:
   lcd = HD44780()
   lcd.message(" "+datetime.now().strftime(%H:%M:%S))
   time.sleep(1)

The main HD44780 class has been initialized and the current time will be sent to the LCD every one second by calling the message function of the lcd object. The most important part of this project is the HD44780 class.

The HD44780 class has the following four components:

  • __init__: This will initialize the necessary components.
  • clear: This will clear the LCD and instruct it to work in the 4-bit mode.
  • cmd: This is the core of the class. Each and every command/instruction that has to be executed will get executed in this function.
  • message: This will be used to display a message on the screen.

The __init__ function

The _init_ function initializes the necessary GPIO port for LCD operation:

def __init__(self, pin_rs=7, pin_e=8, pins_db=[18,23,24,25]):
self.pin_rs=pin_rs
self.pin_e=pin_e
self.pins_db=pins_db
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.pin_e, GPIO.OUT)
GPIO.setup(self.pin_rs, GPIO.OUT)
for pin in self.pins_db:
   GPIO.setup(pin, GPIO.OUT)
   self.clear()

GPIO.setmode(GPIO.BCM): Basically, the GPIO library has two modes in which it can operate. One is BOARD and the other one is BCM. The BOARD mode specifies that you are referring to the numbers printed in the board. The BCM mode means that you are referring to the pins by the “Broadcom SOC channel” number. While creating an instance of the HD44780 class, you can specify which pin to use for a specific purpose. By default, it will take GPIO 7 as RS Pin, GPIO 8 as Enable Pin, and GPIO 18, GPIO 23, GPIO 24, and GPIO 25 as data pins. Once you have defined the mode of the GPIO operation, you have to set all the pins that will be used as output, as you are going to provide output of these pins to LCD pins. Once this is done, clear and initialize the screen.

The clear function

The clear function clears/resets the LCD:

   def clear(self):
     # Blank / Reset LCD
     self.cmd(0x33)
     self.cmd(0x32)
     self.cmd(0x28)
     self.cmd(0x0C)
     self.cmd(0x06)
     self.cmd(0x01)

You will see some code sequence that is executed in this section. This code sequence is generated based on the HD44780 datasheet instructions. A complete discussion of this code is beyond the scope of this article; however, to give a high-level overview, the functionality of each code is as follows:

  • 0x33: This is the function set to the 8-bit mode
  • 0x32: This is the function set to the 8-bit mode again
  • 0x28: This is the function set to the 4-bit mode, which indicates the LCD has two lines
  • 0x0C: This turns on just the LCD and not the cursor
  • 0x06: This sets the entry mode to the autoincrement cursor and disables the shift mode
  • 0x01: This clears the display

The cmd function

The cmd function sends the command to the LCD as per the LCD operation, and is shown as follows:

   def cmd(self, bits, char_mode=False):
     # Send command to LCD
     sleep(0.001)
     bits=bin(bits)[2:].zfill(8)
     GPIO.output(self.pin_rs, char_mode)
     for pin in self.pins_db:
       GPIO.output(pin, False)
     for i in range(4):
       if bits[i] == "1":
         GPIO.output(self.pins_db[i], True)
     GPIO.output(self.pin_e, True)
     GPIO.output(self.pin_e, False)
     for pin in self.pins_db:
       GPIO.output(pin, False)
     for i in range(4,8):
       if bits[i] == "1":
         GPIO.output(self.pins_db[i-4], True)
     GPIO.output(self.pin_e, True)
     GPIO.output(self.pin_e, False)

As the 4-bit mode is used drive the LCD, you will be using the flowchart that has been discussed previously. In the first line, the sleep(0.001) second is used because a few LCD operations will take some time to execute, so you have to wait for a certain time before it gets completed. The bits=bin(bits)[2:].zfill(8) line will convert the integer number to binary string and then pad it with zeros on the left to make it proper 8-bit data that can be sent to the LCD processor. The preceding lines of code does the operation as per the 4-bit write operation flowchart.

The message function

The message function sends the string to LCD, as shown here:

   def message(self, text):
     # Send string to LCD. Newline wraps to second line
     for char in text:
       if char == 'n':
         self.cmd(0xC0) # next line
       else:
         self.cmd(ord(char),True)

This function will take the string as input, convert each character into the corresponding ASCII code, and then send it to the cmd function. For a new line, the 0xC0 code is used.

Discover more Raspberry Pi projects in Raspberry Pi LED Blueprints – pick up our guide and see how software can bring LEDs to life in amazing different ways!

LEAVE A REPLY

Please enter your comment!
Please enter your name here