My Pi Description

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

Wednesday, March 27, 2013

16 X 2 LCD Input Text and Display

Here is a more practical program that asks you to input text and then displays that text on the LCD display.  The challenge here was to parse the input text so that words were not broken up.  Click on the video to see it work:
Here is python code for this program:
#!/usr/bin/python
# For two line dispalys using the Hitachi HD4478U Disolay Driver Chip
# Gets input from user and sends it to the display
# The inputed text is parsed into segments no longer than 16 characters that
# end in complete words.
# Will breakdown on words that are over 16 characters in length.
# First segment goes to line 1, the next to line 2, the next to line 1, etc.
# MJL -- www.thepiandi.blogspot.com 0-- 3/23/2013
from LCD_2X16 import *
def getinput(): # inputs text and parses it into a list where each element is no more than 16 characters
text = raw_input('Input your text: ')
text = text + ' '
listtext = []
stop = False
while stop == False:
spacepos = -1
index_pos = 0
while spacepos < 16 and stop == False:
spacepos = text.find(' ', spacepos + 1)
if spacepos <= 16 and spacepos != -1:
index_pos = spacepos
if spacepos == - 1:
stop = True
if stop:
if text != '':
listtext = listtext + [text[:index_pos]]
else:
listtext = listtext + [text[:index_pos]]
text = text[index_pos + 1:]
return listtext
def wait4switch():
lcd_byte(LCD_LINE_1, LCD_CMD)
lcd_string("Push My Button")
lcd_byte(LCD_LINE_2, LCD_CMD)
lcd_string(" Please")
# wait for switch to be pressed
input_switch = GPIO.input(SwitchInput)
while input_switch:
input_switch = GPIO.input(SwitchInput)
# where it all happens
outstrng = getinput() # Get dispaly string and parse
wait4switch()
TopLine = True
for lineChars in outstrng:
if TopLine == True:
lcd_byte(0x01, LCD_CMD) # Clear Display
lcd_byte(LCD_LINE_1, LCD_CMD)
lcd_string(lineChars)
TopLine = False
else:
lcd_byte(LCD_LINE_2, LCD_CMD)
lcd_string(lineChars)
TopLine = True
time.sleep(3)
if TopLine == False:
time.sleep(3)
lcd_byte(0x01, LCD_CMD) # Clear Display
GPIO.cleanup()
I apologize that the name of the program in the video (LCD_Module_1,py) does not match the name in the Gist file (LCD_Disploy2Lines.py). Somewhere along the way, after I made the video, I changed the file name to make the name more meaningful, at least to me.
The program does not take into account individual words of more that 16 characters in length.
Notice line 16 of the code. That makes LCD_2X16.py (discussed in the last post) part of this program.

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.

Tuesday, March 12, 2013

16 X 2 LCD Display Project - Connections

When I asked on the forum, about the controller on the LCD module, Rick Seiden also provided a link to Matt Hawkin's blog entry "16x2 LCD Module Control Using Python".  Matt provided a set of wiring connections between the display and the Pi to go along with his Python code. I have used the same connections, but with a couple of exceptions. I mention this because the connections to the Pi are part of the python code.  Mickey Skyler's Adafruit tutorial "Drive a 16x2 LCD with the Raspberry Pi" uses a different pin combination.  So if you download Mickey's Adafrut_CharLCD python module, use his pin-outs.
The only differences I have with Rick's connection are:
1.  Since my reflective display does not have a backlight, I have no connections to LCD pins 15 and 16.
2.  I have a 10K potentiometer connected so that I can adjust the contrast.  The potentiometer has three pins in a row.  One outer pin connects to 5v, and the other outer pin connects to GND.  The middle pin connects to pin 3 of the LCD Display.
When I talk to my Raspberry Pi, I am sitting at my desktop and the Pi is not in view.  Therefore, I have installed a momentary switch on the breadboard (has a "4" printed on it).  This allows me to pause a running python program to allow me to walk over to the Pi and resume the program.   One of the two contacts of the switch connects to GND.  The other connects to two places: to one end of a 10K resistor, and the other to GPIO 10 (Pin pin 19).  The other end of the resistor connects to 3.3v.
I just glanced up at the photograph above and realized that I was wrong.  That 10K resistor does not connect to 3.3v.   IT CONNECTS TO 5v.  That means, unless I push the switch, I am applying 5V to GPIO 10.  That's supposed to blow up the processor chip on the Pi.  But, I have run the Pi for hours and hours with 5v to that pin.  The saving factor must be that I am connecting the 5v to the processor pin through a rather large resistor, 10K, so the current drawn by the pin's protection circuit will be low.  There will still be some heat generated, but, apparently, not been enough to blow the chip.  If I had connected a 5v output from the display to a GPIO pin, that would be another matter. That 5v would have come from a much lower source resistance, so the current through the processor's protection circuit would be much greater, causing more heating, and probable chip failure. The problem has now been corrected.
Next post will be the python code for the 16x2 LCD display module.

Thursday, March 7, 2013

16 X 2 LCD Display Project - Hardware

Programming a display seemed like a good starting project to get my feet wet with the Pi.  The header at the top of this page shows the hardware I purchased for this project.  There is the Adafruit Pi Dish that includes the breadboard.  The Pi Dish becomes the base that holds the Raspberry Pi and the breadboard. I like the fact that the Pi is secured and not just hanging by the ribbon cable. 
And yes, I know, I forgot to remove the brown paper from the top and bottom of the clear plastic of the Pi Dish.  By the time I remembered, I already had evertthing connected.
Connecting the Pi to the breadboard is the Adafruit Pi Cobbler breakout kit.  This is a small PCB that plugs into the breadboard and a ribbon cable that connects the PCB to the Pi's GPIO pins.  Adafruit has another Pi Cobbler with the ribbon cable on the side.  This makes the labels on one side of the PCB easier to read because the cable is not in the way.
The display is a 16 alphanumeric character by two line LCD display by Lumix, purchased from Newark/element 14 electronics.  This is a reflective type display so does not need a backlight.  I kind of wish I had purchased the transmissive type LCD display.  Adafruit has a number of color options for these sexier displays.  Transmissive displays, of course, have a backlight. 
I purchased Adafruit's Wire Bundle to make the connections on the breadboard.  The blue device is a three pin 10K potentiometer used to adjust the contrast.  It would have been better to purchase a 1K pot as the ideal contrast setting is closer to the 0 ohm resistance.  The white, square, device with the black "4" is a momentary switch.  Since my Pi is controlled from my desktop, I use the switch to have the program wait for me to get over to the Pi before having the Pi do its stuff. The blue rectangular device to the right of the switch is an Adafruit, 4 channel I2C-safe Bi-directional Logic Level Converter.  If I want the Pi to read an output from the display, a channel of the converter must be connected between the display pin and the Pi's GPIO pin.  A logic high from a display pin is nominally 5v, which would be fatal to the Pi.   The converter, or level shifter, will convert 5v from the display to 3.3v to the Pi, and 3.3v from the Pi to 5v to the display.  If it is not necessary for the Pi to read a display pin, it is not necessary to use the converter.  The display is capable of interpreting 3.3v from the Pi as a logic high signal.  In the photo in the header, the converter is not wired into the circuit.  I did experiment by reading the "busy" bit from the display.  In that case, I did use the converter.  There will be more on this experiment in a later post.
I was happy to see that a data sheet was available for the LCD display.  However, it does not tell you much beyond the dimensions, electrical characteristics, and pin-outs.  The little block diagram on the second page shows a "LCD Controller LSI and Driver".  You need the data sheet for that device, but they don't tell you what the device is.  I went to the Raspberry Pi's great webpage and used their forum to ask if anyone knew what that LCD controller was.  Rick Seiden responded to my post saying that the chip is a HD44780.  Here is the data sheet for the Hitachi HD44780U.
My next post will discuss connections made between the display and the Pi.

Sunday, March 3, 2013

Reading Matter

I got started with the Raspberry Pi by reading two books:
We have the Raspberry Pi today because of the author of this book, Eban Upton.  Even if you are an experienced programmer and hardware guru, this book is a must read.  Eban takes you back through the how and, most importantly, the why the Pi came to be. Of course the Pi is not useful by itself, so he takes you through the options of keyboards, monitors, SD cards, networks, etc, etc, etc.  The operating system is discussed as well as your interface to it through Linux.  Most of the book, however, is on programming.  There is enough of a tutorial, with plenty of example  Python code, to get you started .  Connecting to outside world through the GPIO ports is major part of this book.  Finally, he provides you with many, many references to go further in your Raspberry Pi education.

Simon Monk's book "Programming the Raspberry Pi could be considered volume 2 to the "Raspberry Pi User's Guide.  While there is some duplication between the two books, Monk has included really valuable, additional knowledge. His discussion of Python extends to "Modules, Classes, and Methods" (title of one of his chapters).  He covers handling files, accessing the Internet, and creating a graphical user interface.  There is a chapter on creating games using Pygame, and, like "The User's Guide", extensive discussion of the GPIO ports.  He introduces the reader to combining the Pi with the Arduino and using the Pi as a robotics platform.  The book is filled with example code and references to other useful sources of information.

The next book I want to read is Bruce Smith's "Raspberry Pi Assembly Language".
I see there are more and more Raspberry Pi books being published. There is even a "Raspberry Pi for Dummies". You know the Pi has really arrived on the scene if there is a "Dummy" book.
One last resource that needs to be be mentioned is the wealth of websites, forums, and blogs contributed by the Raspberry Pi community to help people like me. By this blog, I hope to be considered a part of that community.