Last active
May 11, 2017 07:43
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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