This article is based on my previous article 16×2 LCD Module Control Using Python and 16×2 LCD Module Control With Backlight Switch. 20×4 LCD modules are relatively easy and cheap to obtain. They have the same 16 pin interface as the 16×2 modules but still only require 6 GPIO pins on your Pi (an extra pin is required for the backlight switch).
These modules are compatible with the Hitachi HD44780 LCD controller. There are plenty available on eBay with a variety of backlight colours to choose from.
LCD Module Hardware
- VCC (Usually +5V)
- Contrast adjustment (VO)
- Register Select (RS).
RS=0: Command, RS=1: Data
- Read/Write (R/W).
R/W=0: Write, R/W=1: Read
- Bit 0 (Not required in 4-bit operation)
- Bit 1 (Not required in 4-bit operation)
- Bit 2 (Not required in 4-bit operation)
- Bit 3 (Not required in 4-bit operation)
- Bit 4
- Bit 5
- Bit 6
- Bit 7
- LED Backlight Anode (+)
- LED Backlight Cathode (-)
Usually the device requires 8 data lines to provide data to Bits 0-7. However this LCD can be configured to use a “4 bit” mode which allows you to send data in two chunks (or nibbles) of 4 bits. This reduces the number of GPIO connections you need when interfacing with your Pi.
Here is how I wired up my LCD :
|LCD Pin||Function||Pi Function||Pi Pin|
|15||+5V via 560 ohm|
NOTE : The RW pin allows the device to be be put into read or write mode. I tied this pin to ground to prevent the module attempting to send data to the Pi as the Pi can not tolerate 5V inputs on its GPIO header.
Pin 3 : In order to control the contrast you can adjust the voltage presented to Pin 3. I used a 10K ohm trimmer to provide a variable voltage of 0-5V to Pin 3 which allows the contrast to be tweaked.
Pin 15 : This provides power to the backlight LED. In order to allow the backlight to be turned on and off I used a transistor (BC547, BC548 or equivalent) to switch this pin. This required an additional GPIO pin to switch the transistor but allowed my Python script to control the backlight.
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
The script below is based heavily on the code presented in my 16×2 LCD Module Control With Backlight Switch article. This allows the backlight to be switched on and off as well as some basic text justification.
As usual I am using the excellent RPi.GPIO library to provide access to the GPIO within Python.
The features of this setup include :
- 10k variable resistor to adjust the contrast
- 2k variable resistor to adjust the backlight brightness
- A transistor to allow the backlight to be switched on and off
- Left, centred and right justified text
Pin 3 is routed to Ground via a 10K ohm trimming pot so that the display contrast can be adjusted.
Backlight Brightness and Switching
Pin 15/16 are in series with a 560 ohm and 2K ohm trimming pot via an NPN transitor which is activated by an additional GPIO connection. The LCD backlight is treated in exactly the same way I switch standard LEDs in my previous Control LED Using GPIO Output Pin article. Using a fixed resistance ensures the resistance can never be adjusted below 560 ohm which protects the backlight if you set the trimming pot to zero ohms. The base of the transistor is wired to an additional GPIO pin via a 27K ohm resistor.
The function “lcd_string” accepts a second parameter (1, 2 or 3) which determines how the text is displayed on the screen.
Here is the code :
#!/usr/bin/python #-------------------------------------- # ___ ___ _ ____ # / _ \/ _ \(_) __/__ __ __ # / , _/ ___/ /\ \/ _ \/ // / # /_/|_/_/ /_/___/ .__/\_, / # /_/ /___/ # # lcd_16x2.py # 20x4 LCD Test Script with # backlight control and text justification # # 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 LED_ON = 15 # Define some device constants LCD_WIDTH = 20 # 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 LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line # Timing constants E_PULSE = 0.0005 E_DELAY = 0.0005 def main(): # Main program block 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 GPIO.setup(LED_ON, GPIO.OUT) # Backlight enable # Initialise display lcd_init() # Toggle backlight on-off-on lcd_backlight(True) time.sleep(0.5) lcd_backlight(False) time.sleep(0.5) lcd_backlight(True) time.sleep(0.5) while True: # Send some centred test lcd_string("--------------------",LCD_LINE_1,2) lcd_string("Rasbperry Pi",LCD_LINE_2,2) lcd_string("Model B",LCD_LINE_3,2) lcd_string("--------------------",LCD_LINE_4,2) time.sleep(3) # 3 second delay lcd_string("Raspberrypi-spy",LCD_LINE_1,3) lcd_string(".co.uk",LCD_LINE_2,3) lcd_string("",LCD_LINE_3,2) lcd_string("20x4 LCD Module Test",LCD_LINE_4,2) time.sleep(3) # 20 second delay # Blank display lcd_byte(0x01, LCD_CMD) time.sleep(3) # 3 second delay 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,style): # Send string to display # style=1 Left justified # style=2 Centred # style=3 Right justified if style==1: message = message.ljust(LCD_WIDTH," ") elif style==2: message = message.center(LCD_WIDTH," ") elif style==3: message = message.rjust(LCD_WIDTH," ") lcd_byte(line, LCD_CMD) for i in range(LCD_WIDTH): lcd_byte(ord(message[i]),LCD_CHR) def lcd_backlight(flag): # Toggle backlight on-off-on GPIO.output(LED_ON, flag) if __name__ == '__main__': try: main() except KeyboardInterrupt: pass finally: lcd_byte(0x01, LCD_CMD) lcd_string("Goodbye!",LCD_LINE_1,2) GPIO.cleanup()
Remember to update the constants at the top of the script to match the GPIO signals you are using on your Pi. As always these GPIO references are the Broadcom signal names as described in my GPIO header article.
Take a look at my other LCD Screen related posts which include details of the 16×2 version of the screen used in this post.