Raspberry Pi Hacking - Controlling a LCD with Buttons and Python

   By: magikh0e 
   magikh0e _aT_ ihtb d0t org
                                                                                        
'\v/`  
     (o 0)  m0o. 
 (_)  /
Last Edit: Mar 23 2013
TOC
Introduction HD44780 Schematic Raspberry Pi Pins/GPIO Connecting the LCD to Power Powering Buttons and Connecting to GPIO Button Function to GPIO Pin mapping Driving the LCD and Buttons with Python Final Outcome

This guide assumes you already have some prior/intermediate knowledge of developing on Raspberry Pi's and utilizing GPIO. It also assumes you will be using a breadboard 
for wiring things up.
If this is your first time, I suggest you start here first: Raspberry.Pi.Hacking.pdf
HD44780 Schematic
Raspberry Pi Pinout

Connecting up the LCD (Power)

1. Connect VSS from the LCD into -/Ground on the breadboard.
2. Connect VCC from the LCD into +/Positive on the breadboard.
3. Connect VO from the LCD into -/Ground on the breadboard.
4. Connect LEDA from the LCD to +/Positive on the breadboard.
	
** Note: By connecting the middle pin of a  10k potentiometer to VO, you will be able to adjust the brightness of the LCD. 
Though this has not been used in this guide..


Powering LCD from Raspberry Pi (5V)

1. Connect Pin 6/Ground from the Raspberry Pi into -/Ground on the breadboard.
2. Connect Pin 2/5V from the Raspberry Pi into +/Positive on the breadboard.
NOTE: Make sure you are using 5V, not 3.3V for the LCD!



Powering the Buttons from Raspberry Pi (3.3V)

1. Connect Pin 1/3.3V from the Raspberry Pi into +/Positive on the opposite side of the 5V pins on the breadboard.

NOTE: Make sure you are using 3.3V, not 5V for the buttons! 
Also verify the 3.3V and 5V source are not connected to the same pins...

Wiring the Buttons to the Raspberry Pi

You have to be careful on this part of building the circit, there is a chance of causing damage to the pins if they are accidentally setup as an output when using 
buttons. If you drive the pin LOW, the output is connected directly to Ground. Pushing the button after will create a short circuit between 3.3v and Ground. 
Your Pi will NOT like this... =) 

NOTE: To keep the Pi happy, you can put a 1k limiting resistor between the pin and the GPIO pin on the Raspberry Pi. 
This resistor will ensure the pi can handle the current being drawn from it in case of accidents and/or user errors... 
Button to Function Mapping

BUTTON NAMEGPIO / NAMEWiringPI
Return1 / SCL 9
OK4 / GPIO 7 7
Down10 / MOSI 12
Right17 / GPIO 0 0
Left22 / GPIO 3 3
UP21 / GPIO 2 2
Before connecting up any wires, make sure you have double checked the datahseets for the buttons you will be using for proper pin configuration.

1. Pin 1 from the button connects to 3.3V on the breadboard with a 10k resistor 
2. Pin 1 from the button connects to GPIO # corelating to the buttons function.
3. Pin 2 from the button connects to -/Ground on the breadboard.
4. Repeat steps 1-3 for each button using the mappings above. 
You will need 6 Buttons total.
Button Schematic Example

When a GPIO pin is set to be an IN/input, it is put into a "floating" state and has no defined voltage level. 
So when wiring the buttons, they need to be wired so they will have a HIGH or LOW change of state when pressed. 

This is done by using a 10k pull down resistor into -/Ground. By using a 10k resistor will create a path to -/Ground and the pin 
will read LOW when the button is not pressed. When the button is pressed and you have the other side connected to 3.3V, there will 
be a lower resistance path to -/Ground and the pin will then read HIGH. 

Using a large 10k resistor will make sure only small amounts of current are pulled from the Raspberry Pi when the button is pressed.

Driving the LCD and Buttons with Python

#!/usr/bin/python

from time import *
import time
import sys
import collections
import datetime
from subprocess import *
import RPi.GPIO as GPIO


# MODE
E_PULSE = 0.00005
E_DELAY = 0.00005
wait = 0.1

# LCD
LCD_WIDTH  = 16
LCD_CHR    = True
LCD_CMD    = False
LCD_LINE_1 = 0x80
LCD_LINE_2 = 0xC0

LCD_RS =  7
LCD_E  =  8
LCD_D4 = 25
LCD_D5 = 24
LCD_D6 = 23
LCD_D7 = 18
LED_ON = 15

# MAPPING OF BUTTONS
RT =  1
OK =  4
DN = 10
RI = 17
LE = 22
UP = 21

tag = 0
val = 0
p = 0
try:
   def main():
      print "Loaded..."

      tag = 0
      val = 0
      p = 0

      GPIO.setmode(GPIO.BCM)
      GPIO.setup(LCD_RS, GPIO.OUT)
      GPIO.setup(LCD_E,  GPIO.OUT)
      GPIO.setup(LCD_D4, GPIO.OUT)
      GPIO.setup(LCD_D5, GPIO.OUT)
      GPIO.setup(LCD_D6, GPIO.OUT)
      GPIO.setup(LCD_D7, GPIO.OUT)
      GPIO.setup(LED_ON, GPIO.OUT)

      GPIO.setup(RT, GPIO.IN)
      GPIO.setup(OK, GPIO.IN)
      GPIO.setup(DN, GPIO.IN)
      GPIO.setup(RI, GPIO.IN)
      GPIO.setup(LE, GPIO.IN)
      GPIO.setup(UP, GPIO.IN)

      rt = GPIO.input(RT)
      ok = GPIO.input(OK)
      dn = GPIO.input(DN)
      ri = GPIO.input(RI)
      le = GPIO.input(LE)
      up = GPIO.input(UP)

      lcd_init()

      GPIO.output(LED_ON, False)
      time.sleep(1)
      GPIO.output(LED_ON, True)
      time.sleep(1)

      lcd_byte(LCD_LINE_1, LCD_CMD)
      lcd_string("magikh0e")

      lcd_byte(LCD_LINE_2, LCD_CMD)
      lcd_string("ihtb.org")

      p   = 0
      tag = 0
      val = 0

      while True:
         #lcd_byte(LCD_LINE_2, LCD_CMD)
        #Return
        rt = GPIO.input(RT)
        #Ok
        ok = GPIO.input(OK)
        #Down
        dn = GPIO.input(DN)
        #Right
        ri = GPIO.input(RI)
        #Left
        le = GPIO.input(LE)
        #Up
        up = GPIO.input(UP)
        if rt == False:
                 p = "rt"
        if ok == False:
                 p = "ok"
        if dn == False:
                p = "dn"
        if ri == False:
                p = "ri"
        if le == False:
                p = "le"
        if up == False:
                p = "up"
        if p != 0:
                result = message(tag, val, p)
                val = result['val']
                tag = result['tag']
                p = 0
                sleep(wait)

   def message(tag, val, button):
      lcd_byte(LCD_LINE_1, LCD_CMD)
      lcd_string("you have pressed " + button)
      if button == "ok":
         tag = tag + 10
      if button == "rt":
         if tag >= 10:
            tag = tag -10
         else:
            tag = 0
      if button == "dn":
         val = val - 1
      if button == "up":
         val = val + 1
      if button == "le":
         tag = tag - 1
      if button == "ri":
         tag = tag + 1

      lcd_byte(LCD_LINE_2, LCD_CMD)
      lcd_string("val " + str(val) + " tag " + str(tag))

      return{'tag':tag, 'val':val}

   def lcd_init():
      lcd_byte(0x33, LCD_CMD)
      lcd_byte(0x32, LCD_CMD)
      lcd_byte(0x28, LCD_CMD)
      lcd_byte(0x0C, LCD_CMD)
      lcd_byte(0x06, LCD_CMD)
      lcd_byte(0x01, LCD_CMD)

   def lcd_string(message):
      message = message.center(LCD_WIDTH, " ")

      for i in range(LCD_WIDTH):
         lcd_byte(ord(message[i]), LCD_CHR)

   def lcd_byte(bits, mode):

      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
      time.sleep(E_DELAY)
      GPIO.output(LCD_E, True)
      time.sleep(E_PULSE)
      GPIO.output(LCD_E, False)
      time.sleep(E_DELAY)

      # 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
      time.sleep(E_DELAY)
      GPIO.output(LCD_E, True)
      time.sleep(E_PULSE)
      GPIO.output(LCD_E, False)
      time.sleep(E_DELAY)


   if __name__ == '__main__':
      main()

except Exception,e:
   print str(e)