Skip to content

Instantly share code, notes, and snippets.

@dentex
Last active May 11, 2017 07:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dentex/c468d1b31dd05c9a3922a302788b8c0d to your computer and use it in GitHub Desktop.
Save dentex/c468d1b31dd05c9a3922a302788b8c0d to your computer and use it in GitHub Desktop.
Phython driver and usage script to run a 20x4 LCD (with a PCF8574 I2C backpack) with Raspbian
#!/usr/bin/python -u
# -*- coding: utf-8 -*-
"""
Copyright 2017 Samuele Rini
Modified from:
https://bitbucket.org/ryanteckltd/16x2-python-i2c-lib/
https://www.raspberrypi.org/forums/viewtopic.php?f=32&t=34261&p=378524
http://www.recantha.co.uk/blog/?p=4849
Released under the MIT License (MIT):
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import smbus
from time import *
# LCD Address
ADDRESS = 0x27
# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit
class i2c_device:
def __init__(self, addr, port=1):
self.addr = addr
self.bus = smbus.SMBus(port)
# Write a single command
def write_cmd(self, cmd):
self.bus.write_byte(self.addr, cmd)
sleep(0.0001)
# Write a command and argument
def write_cmd_arg(self, cmd, data):
self.bus.write_byte_data(self.addr, cmd, data)
sleep(0.0001)
# Write a block of data
def write_block_data(self, cmd, data):
self.bus.write_block_data(self.addr, cmd, data)
sleep(0.0001)
# Read a single byte
def read(self):
return self.bus.read_byte(self.addr)
# Read
def read_data(self, cmd):
return self.bus.read_byte_data(self.addr, cmd)
# Read a block of data
def read_block_data(self, cmd):
return self.bus.read_block_data(self.addr, cmd)
class lcd:
# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00
# initializes objects and lcd
def __init__(self, no_backlight=False):
self.lcd_device = i2c_device(ADDRESS)
if no_backlight:
self.backlight_flag = self.LCD_NOBACKLIGHT
else:
self.backlight_flag = self.LCD_BACKLIGHT
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x02)
self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
sleep(0.2)
# clocks EN to latch command
def lcd_strobe(self, data):
self.lcd_device.write_cmd(data | En | self.backlight_flag)
sleep(.0005)
self.lcd_device.write_cmd(((data & ~En) | self.backlight_flag))
sleep(.0001)
def lcd_write_four_bits(self, data):
self.lcd_device.write_cmd(data | self.backlight_flag)
self.lcd_strobe(data)
# write a command to lcd
def lcd_write(self, cmd, mode=0):
self.lcd_write_four_bits(mode | (cmd & 0xF0))
self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))
# put string function
# def lcd_display_string(self, string, line):
def put(self, string, line):
"""
Puts text on LCD
:param string: text to display
:param line: LCD's line to use
"""
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_write(ord(char), Rs)
def put_scroll(self, string, line, lcd_chars_num=20, lock=None):
"""
Puts scrolling text on LCD (on one only selected line)
:param string: text to display
:param line: LCD's line to use
:param lcd_chars_num: number of characters on every row
:param lock: multiprocessing.Lock() object, to safely write on the LCD from different processes
:return:
"""
scroll_pause = 0.4
self.put(string[:lcd_chars_num], line)
sleep(scroll_pause)
if len(string) > lcd_chars_num:
# while True:
for x in range(3000):
for i in range(0, len(string) - lcd_chars_num + 1):
if lock is not None:
lock.acquire()
self.put(string[i:(i + lcd_chars_num)], line)
if lock is not None:
lock.release()
sleep(scroll_pause)
sleep(scroll_pause * 2)
for i in range(len(string) - lcd_chars_num, -1, -1):
if lock is not None:
lock.acquire()
self.put(string[i:(i + lcd_chars_num)], line)
if lock is not None:
lock.release()
sleep(scroll_pause)
sleep(scroll_pause)
else:
self.put(string, line)
# clear lcd and set to home
def clear(self):
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_RETURNHOME)
def main():
device = lcd()
device.put("------ line 1 ------", 1)
sleep(0.5)
device.put("------ line 2 ------", 2)
sleep(0.5)
device.put("------ line 3 ------", 3)
sleep(0.5)
device.put("------ line 4 ------", 4)
sleep(0.5)
device.clear()
device.put(' ----- ', 1)
device.put(' Clock ', 2)
device.put(' ----- ', 3)
while True:
device.put(strftime('%Y-%m-%d %H:%M:%S', localtime()), 4)
sleep(0.99)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print '...KeyboardInterrupt...'
pass
#!/usr/bin/python -u
# -*- coding: utf-8 -*-
"""
Copyright 2017 Samuele Rini
Released under the MIT License (MIT):
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the 'Software'), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import sys
import getopt
import lcd_driver
import os
def usage():
print 'Usage: ' + os.path.basename(__file__) + ' [OPTION]... ' \
'\n\nOPTIONS:' \
'\n-h, --help Prints this usage note' \
'\n-d, --debug Debug information flag' \
'\n-b, --backlightoff LCD\'s backlight off flag' \
'\n-x <string> LCD\'s 1st row string' \
'\n-y <string> LCD\'s 2nd row string' \
'\n-z <string> LCD\'s 3rd row string' \
'\n-w <string> LCD\'s 4th row string'
def main():
string1 = ''
string2 = ''
string3 = ''
string4 = ''
debug = False
no_backlight = False
try:
opts, args = getopt.getopt(sys.argv[1:], 'hdbx:y:z:w:',
['help', 'debug', 'backlightoff', 'string1=', 'string2=', 'string3=', 'string4='])
except getopt.GetoptError:
print ('Wrong arguments!\n')
usage()
sys.exit(2)
for opt, arg in opts:
if opt == '-h' or opt == '--help':
usage()
sys.exit()
elif opt in ('-d', '--debug'):
debug = True
elif opt in ('-b', '--backlightoff'):
no_backlight = True
elif opt in ('-x', '--string1'):
string1 = arg
elif opt in ('-y', '--string2'):
string2 = arg
elif opt in ('-z', '--string3'):
string3 = arg
elif opt in ('-w', '--string4'):
string4 = arg
if debug:
print ''
print ' **********************'
print '1-> *' + string1 + ' '*(20-len(string1)) + '*'
print '2-> *' + string2 + ' '*(20-len(string2)) + '*'
print '3-> *' + string3 + ' '*(20-len(string3)) + '*'
print '4-> *' + string4 + ' '*(20-len(string4)) + '*'
print ' **********************'
print ''
device = lcd_driver.lcd(no_backlight)
device.put(string1, 1)
device.put(string2, 2)
device.put(string3, 3)
device.put(string4, 4)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment