16×2 LCD Module Control Using Python

LCD Module Hardware

The pinout of the module is :

  1. Ground
  2. VCC (Usually +5V)
  3. Contrast adjustment (VO)
  4. Register Select (RS).
    RS=0: Command, RS=1: Data
  5. Read/Write (R/W).
    R/W=0: Write, R/W=1: Read
  6. Enable
  7. Bit 0 (Not required in 4-bit operation)
  8. Bit 1 (Not required in 4-bit operation)
  9. Bit 2 (Not required in 4-bit operation)
  10. Bit 3 (Not required in 4-bit operation)
  11. Bit 4
  12. Bit 5
  13. Bit 6
  14. Bit 7
  15. LED Backlight Anode (+)
  16. LED Backlight Cathode (-)

16×2 LCD Module Control Using PythonUsually 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.

16×2 LCD Module Control Using Python board+schematic

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 programming 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 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#!/usr/bin/python
#--------------------------------------
#    ___  ___  _ ____
#   / _ \/ _ \(_) __/__  __ __
#  / , _/ ___/ /\ \/ _ \/ // /
# /_/|_/_/  /_/___/ .__/\_, /
#                /_/   /___/
#
#  lcd_16x2.py
#  16x2 LCD Test Script
#
# Author : Matt Hawkins
# Date   : 06/04/2015
#
# https://www.raspberrypi-spy.co.uk/
#
#--------------------------------------
# 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.0005
E_DELAY = 0.0005
def main():
  # Main program block
  GPIO.setwarnings(False)
  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()
  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("RaspberryPi-spy",LCD_LINE_1)
    lcd_string(".co.uk",LCD_LINE_2)
    time.sleep(3)
    # Send some text
    lcd_string("Follow me on",LCD_LINE_1)
    lcd_string("Twitter @RPiSpy",LCD_LINE_2)
    time.sleep(3)
def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD) # 110011 Initialise
  lcd_byte(0x32,LCD_CMD) # 110010 Initialise
  lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
  lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
  lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
  lcd_byte(0x01,LCD_CMD) # 000001 Clear display
  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_E, True)
  time.sleep(E_PULSE)
  GPIO.output(LCD_E, 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:
    lcd_byte(0x01, LCD_CMD)
    lcd_string("Goodbye!",LCD_LINE_1)
    GPIO.cleanup()

This script can be downloaded using this link or directly to your Pi using the following command :

wget https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/python/lcd_16x2.py

It can then be run using :

sudo lcd_16x2.py

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.

Troubleshooting

If you are having issues then try :

  • Double check the wiring.
  • Try adjusting the voltage on the contrast pin between 0V and 3.3V.
  • Change the E_PULSE and E_DELAY parameters from 0.0005 to 0.001. Some screens are sensitive to these times and won’t initialise if they are too small.
  • Use Python 2. I haven’t tested with Python 3 yet.

Source: 16×2 LCD Module Control Using Python


About The Author

Ibrar Ayyub

I am an experienced technical writer holding a Master's degree in computer science from BZU Multan, Pakistan University. With a background spanning various industries, particularly in home automation and engineering, I have honed my skills in crafting clear and concise content. Proficient in leveraging infographics and diagrams, I strive to simplify complex concepts for readers. My strength lies in thorough research and presenting information in a structured and logical format.

Follow Us:
LinkedinTwitter

Leave a Comment

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