My Pi Description

My Experiences With the Raspberry Pi -- Tracking My Learning -- My Pi Projects

Saturday, March 23, 2013

16 X 2 LCD Base Code

I am finally getting to the code.  I will spread this over three posts.  The first code will be the base module that will be imported into python programs for two other projects.  The base module can, of course, be run by itself. If it is run by itself, the LCD will display what you see in the photograph in the header of this blog.  
I did not originate the base module.  I based it on the code found at Matt Hawkins blog (referenced previously).  I added to it, made some modifications, and made it more suitable to be imported into other projects.  Matt was not the originator of the code either.  I believe the original code was modified from code for the Audunio and appears in Micky Skyler's Adafruit tutorial, "Drive a 16x2 LCD with Raspberry Pi" that is referenced in the previous post.  That tutorial presents a python class for the display controller called Adadruit_CharLCD.py.  This code is quite comprehensive and I believe others took what they needed from it for their code.  This is my version of that code, my base module:
#!/usr/bin/python
# For two line X 16 character display using Hitachi HD4478U Display Driver Chip
# Based on Matt Hawkins' code on his blog at www.raspberrypi-spy.co.uk
# Matt Hawkins modified the code by texy (From Raspberry Pi forum)
# Ultimate source is probably Mickey Sklar's python class in the file Adafruit_CharLCD.py
# The above file is at Mickey Sklar's Adafruit turorial, "Drive a 16x2 LCD with Raspberry Pi"
# MJL -- thepiandi.blogspot.com -- 03/23/2013
import RPi.GPIO as GPIO
import time
# Define LCD signal mapping to Pi GPIO port
LCD_RS = 7 # Register Select to GPIO 7
LCD_E = 8 # Data Enable to GPIO 8
LCD_D4 = 25 # Display Data Bus D4 to GPIO 25
LCD_D5 = 24 # Display Data Bus D5 to GPIO 24
LCD_D6 = 23 # Display Data Bus D6 to GPIO 23
LCD_D7 = 18 # Display Data Bus D7 to GPIO 18
# Define switch mapping to GPIO PORT
SwitchInput = 10 # Switch input to GPIO 10
# Define LCD Module Parameters
LCD_WIDTH = 16 # For 16 x 2 Display
LCD_CHR = True # For Character Data Register
LCD_CMD = False # For Command Data Register
# For 16 x 2 display
LCD_LINE_1 = 0x80 # LCD DDRAM Left Hand Address for First Line
LCD_LINE_2 = 0xC0 # LCD DDRAM Left Hand Address for Second Line
# Timing Constants
E_PULSE = 0.00005
E_DELAY = 0.00005
def lcd_init(): # Initialize display
lcd_byte(0x33, LCD_CMD) # To Understand this and the next command, read
lcd_byte(0x32, LCD_CMD) # page 46 of HD 44780U Document
lcd_byte(0x28, LCD_CMD) # Use four bits commands, 2 line display, 5x8 char format
lcd_byte(0x0C, LCD_CMD) # Turn display on with curser off
lcd_byte(0x06, LCD_CMD) # Increment Address, no shift
lcd_byte(0x01, LCD_CMD) # Clear Display
def lcd_string(message): # Prepare and Send One Line of Characters
message = message.ljust(LCD_WIDTH, " ") # Make string 16 characters long
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]), LCD_CHR) # Convert each character to ASCII and send to LCD
def toggle_enable(): # Toggle Enable pin to latch data in LCD
time.sleep(E_DELAY)
GPIO.output(LCD_E, True)
time.sleep(E_PULSE)
GPIO.output(LCD_E, False)
time.sleep(E_DELAY)
def lcd_byte(bits, mode): # Send the data to the LCD Module
# Send byte to data pins
# bits = data
# mode = True for character
# = False for command
GPIO.output(LCD_RS, mode) # Register Select (character or command)
# Send High Bits
GPIO.output(LCD_D4, bits&0x10)
GPIO.output(LCD_D5, bits&0x20)
GPIO.output(LCD_D6, bits&0x40)
GPIO.output(LCD_D7, bits&0x80)
toggle_enable() # latch the data
# Send low Bits
GPIO.output(LCD_D4, bits&0x01)
GPIO.output(LCD_D5, bits&0x02)
GPIO.output(LCD_D6, bits&0x04)
GPIO.output(LCD_D7, bits&0x08)
toggle_enable() # latch the data
# We start doing stuff here
GPIO.setmode(GPIO.BCM) # Use BCM GPIO numbers rather than PI pin numbers
GPIO.setwarnings(False) # Stop Annoying messages that "channel is already in use"
GPIO.setup(LCD_E, GPIO.OUT) # Enable Pin
GPIO.setup(LCD_RS, GPIO.OUT) # Register Select Pin
GPIO.setup(LCD_D4, GPIO.OUT) # LCD D4 Pin
GPIO.setup(LCD_D5, GPIO.OUT) # LCD D5 Pin
GPIO.setup(LCD_D6, GPIO.OUT) # LCD D6 Pin
GPIO.setup(LCD_D7, GPIO.OUT) # LCD D7 Pin
GPIO.setup(SwitchInput, GPIO.IN) # Switch input pin
lcd_init() # Initialize the Display
lcd_byte(0x01, LCD_CMD) # Clear Display
time.sleep(.25)
if __name__ == '__main__':
# test code
try:
lcd_byte(LCD_LINE_1, LCD_CMD)
lcd_string("Hi From My Pi")
lcd_byte(LCD_LINE_2, LCD_CMD)
lcd_string("")
time.sleep(30)
lcd_byte(0x01, LCD_CMD) # Clear Display
GPIO.cleanup()
except KeyboardInterrupt:
lcd_byte(0x01, LCD_CMD) # Clear Display
GPIO.cleanup()
view raw LCD_2X16.py hosted with ❤ by GitHub
You will need to have RPI.GPIO installed to control the GPIO pins on the PI.  I believe some distributions already include it.  Micky Skyler's Adafruit tutorial covers how to get it if you need it.  
Lines 23 and 24 are probably for my situation only.  More on this in my next post.  
If you want to understand the code you have to read it along with the Hitachi data sheet for the HD4478U.  Pages 24 and 25 have the pertinent information.  
Lines 40 through 42 of the code are particularly interesting (and I can't take any credit for this code). The HD44780 must be initialized before it can be used.  See Figure 24 on page 46 for the sequence of events to initialize the chip.  There are timing requirements between steps like "Wait for more than 4.1ms".  The PI is slow enough that we don't have to worry about the timing.  
The initialization starts (line 40 of the code) with the controller in 8 bit mode, not four bit mode.  The first two commands have DB7 - DB4 (data bus pins) set to 0011 which corresponds to hex 3, so the first two hex 3's are sent, one hex 3 at a time in line 40. The next two commands are 0011 and 0010, corresponding to hex 3 and hex 2, which are sent to the controller by line 41.  The next line, 0010 specifies 4 bit operation which is hex 2 (8 bit operation would be 0011), while the following line has N = 1 for a two line display and F = 0 for 5x8 dots.  Therefore the forth command is 1000, or 8 hex. Code line 42 sends those two commands, hex 2 and hex 8, to the controller.  I'll leave the rest of the initialization commands for you to figure out for yourself.  
For those unfamiliar with hexadecimal numbers, I plan to devote a post to hex, binary and decimal numbers and bit manipulation.
Line 105, if __name__ == '__main__', was something that I did not understand at first.  I saw quite a few questions about it on forums, so I guess I was not the only person who wanted to know.  Why do we need this line at all?  I need it because I intend to import this base module into a couple of other programs for my next posts.  This will save me from copying lines 12 to 102 into the new programs, and you will only see the new code giving a cleaner presentation.  
So how do you interpret line 105?  You can consider __name__ and __main__ to be python interpreter or internal variables.  When you run my base module, LCD_2X16.py, the interpreter assigns '__main__' to __name__.  Since line l05 evaluates to true, the code following that line will run, outputting the text to the display.  However, I have imported LCD_2X16.py into other programs by writing from LCD_2X16 import * in those programs.   If I then run one of those programs, everything from LCD_2X16.py will be part of the calling program.  However, when if __name__ == '__main__' is reached it will compute to false because __name__ now equals 'LCD_2X16', not '__main__' thus the test code will be ignored.  Pretty neat!  if __name__ == '__main__' is only written in the base module, not my other programs.

1 comment:

  1. Thanks for doing this, the commenting of this code alone is such a help for noobs like me to start getting around how to do this programming thing.

    Are you able to advise how I can print to the lcd_string a 'moving' number (eg a clock or voltage / temp reading)as I'm still struggling a bit to learn python syntax, tools and terms.

    ReplyDelete