Raspberry Pi, I2C LCD screen and Safe Power Down button




The Raspberry Pi, just sitting there, asking to be played with…
As I looked over my existing projects I noticed this sad little lone R-Pi sitting on my desk. Some time ago I bought it. Played with it a bit, installed NOOB image on the SD card, connected I2C LCD text display to it and a shutdown switch and played a bit with GPIO programming in Python. I want to make a car trip computer out of this R-Pi. You know, a computer that will read car’s ECU via OBD2 port and display information in real time, like the average and current gas usage, trip time and length, how many miles left on the remaining fuel and such. In the future perhaps I could add a camera and trip log. This may be a cool project. I commute to work 15 miles, so there will be plenty opportunity to test the toy.
I remembered that this LCD screen, connected to GPIO pins via some prototyping wire (female connectors at both ends) gave me a lot of trouble related to poor contact, so I decided to upgrade it and make a dedicated connector with wires soldered to it. I also need a keypad for the project, but since I did not buy or make one yet, I just connected a LCD and a shutdown switch at this time.
The LCD takes just 4 wires – 5V, GND, SDA and SCL (I2C and power, Pi’s GPIO pins #2, 6, 3, 5 respectively). The unfortunate thing is that the R-Pi’s logic is 3.3V, however this display’s power voltage requirement and logic is 5V. Raspberry Pi, I2C LCD screen and Safe Power Down buttonI tried to power it from Pi’s 3.3V pin hoping that it has some built in tolerance, however the display would not work then. Therefore I powered the screen from Pi’s 5V pin with a bit of scare that I might damage the Pi’s GPIO port, however this seems to work fine. It looks like the device accepts 3.3V logic, just needs to be powered by 5V to operate. I guess it should be OK as long as I am not sending the input to R-Pi in the 5V level. Since LCD is an output device, this is not the case. The temporary connection I made previously suffered from poor contact and I often had voltage drops that caused information loss on the display, even with the 5V power connected to the device. With the new connector things look much better and the display is finally reliable.
Connections diagram.
The code.
I found very useful information here.
It presents the driver in Python for LCD display that is in turn driven by PCF8574 expander chip, which is basically an I2C hardware driver for the LCD display.
It is easy to implement and start programming your LCD screen in Python right away (assuming you already installed and configured your GPIO libraries).
The actual driver code listed below, lcddriver.py was taken from above web site at the time I made the project:
import smbus
from time import *
# General i2c device class so that other devices can be added easily
class i2c_device:
def __init__(self, addr, port):
   self.addr = addr
   self.bus = smbus.SMBus(port)
def write(self, byte):
   self.bus.write_byte(self.addr, byte)
def read(self):
   return self.bus.read_byte(self.addr)
def read_nbytes_data(self, data, n): # For sequential reads > 1 byte
   return self.bus.read_i2c_block_data(self.addr, data, n)
class lcd:
   #initializes objects and lcd
   ”’
   Reverse Codes:
   0: lower 4 bits of expander are commands bits
   1: top 4 bits of expander are commands bits AND P0-4 P1-5 P2-6
   2: top 4 bits of expander are commands bits AND P0-6 P1-5 P2-4
   ”’
   def __init__(self, addr, port, reverse=0):
      self.reverse = reverse
      self.lcd_device = i2c_device(addr, port)
      if self.reverse:
         self.lcd_device.write(0x30)
         self.lcd_strobe()
         sleep(0.0005)
         self.lcd_strobe()
         sleep(0.0005)
         self.lcd_strobe()
         sleep(0.0005)
         self.lcd_device.write(0x20)
         self.lcd_strobe()
         sleep(0.0005)
      else:
         self.lcd_device.write(0x03)
         self.lcd_strobe()
         sleep(0.0005)
         self.lcd_strobe()
         sleep(0.0005)
         self.lcd_strobe()
         sleep(0.0005)
         self.lcd_device.write(0x02)
         self.lcd_strobe()
         sleep(0.0005)
      self.lcd_write(0x28)
      self.lcd_write(0x08)
      self.lcd_write(0x01)
      self.lcd_write(0x06)
      self.lcd_write(0x0C)
      self.lcd_write(0x0F)
   # clocks EN to latch command
   def lcd_strobe(self):
      if self.reverse == 1:
         self.lcd_device.write((self.lcd_device.read() | 0x04))
         self.lcd_device.write((self.lcd_device.read() & 0xFB))
      if self.reverse == 2:
         self.lcd_device.write((self.lcd_device.read() | 0x01))
         self.lcd_device.write((self.lcd_device.read() & 0xFE))
      else:
         self.lcd_device.write((self.lcd_device.read() | 0x10))
         self.lcd_device.write((self.lcd_device.read() & 0xEF))
   # write a command to lcd
   def lcd_write(self, cmd):
      if self.reverse:
         self.lcd_device.write((cmd >> 4)<<4)
         self.lcd_strobe()
         self.lcd_device.write((cmd & 0x0F)<<4)
         self.lcd_strobe()
         self.lcd_device.write(0x0)
      else:
         self.lcd_device.write((cmd >> 4))
         self.lcd_strobe()
         self.lcd_device.write((cmd & 0x0F))
         self.lcd_strobe()
         self.lcd_device.write(0x0)
   # write a character to lcd (or character rom)
   def lcd_write_char(self, charvalue):
      if self.reverse == 1:
         self.lcd_device.write((0x01 | (charvalue >> 4)<<4))
         self.lcd_strobe()
         self.lcd_device.write((0x01 | (charvalue & 0x0F)<<4))
         self.lcd_strobe()
         self.lcd_device.write(0x0)
      if self.reverse == 2:
         self.lcd_device.write((0x04 | (charvalue >> 4)<<4))
         self.lcd_strobe()
         self.lcd_device.write((0x04 | (charvalue & 0x0F)<<4))
         self.lcd_strobe()
         self.lcd_device.write(0x0)
      else:
         self.lcd_device.write((0x40 | (charvalue >> 4)))
         self.lcd_strobe()
         self.lcd_device.write((0x40 | (charvalue & 0x0F)))
         self.lcd_strobe()
         self.lcd_device.write(0x0)
   # put char function
   def lcd_putc(self, char):
      self.lcd_write_char(ord(char))
   # put string function
   def lcd_puts(self, string, line):
      if line == 1:
         self.lcd_write(0x80)
      if line == 2:
         self.lcd_write(0xC0)
      if line == 3:
         self.lcd_write(0x94)
      if line == 4:
         self.lcd_write(0xD4)
      for char in string:
         self.lcd_putc(char)
   # clear lcd and set to home
   def lcd_clear(self):
      self.lcd_write(0x1)
      self.lcd_write(0x2)
   # add custom characters (0 – 7)
   def lcd_load_custon_chars(self, fontdata):
      self.lcd_device.bus.write(0x40);
      for char in fontdata:
         for line in char:
            self.lcd_write_char(line)Raspberry Pi, I2C LCD screen and Safe Power Down button schematic
Example of use, the script that displays welcome banner, hello.py:
import lcddriver
from time import *
lcd = lcddriver.lcd()
lcd.lcd_clear()
lcd.lcd_display_string(“*——————*”,1);
lcd.lcd_display_string(“|System is running.|”,2)
lcd.lcd_display_string(“*——————*”,3);
I modified few start-up and shutdown handling scripts to run the scripts that display information on the LCD screen. This way I have neat messages that you can see on the pictures when the system is booted up and ready to use and also when I press the shutdown button, I get the information displayed about the shutdown progress. Since there is only one display and there are multiple scripts or programs that would like to write data to it, the proper way to do it would be to create some sort of a server that would take the requests from clients and relay them to the LCD screen. For now however I write them directly to the LCD screen since this was meant as a demo and proof of operation.

 

For more detail: Raspberry Pi, I2C LCD screen and Safe Power Down button


© 2015 Powered By Engineering Projects Team, Raspberry Pi Projects

Scroll to top