-
-
Save DenisFromHR/cc863375a6e19dce359d to your computer and use it in GitHub Desktop.
# requires RPi_I2C_driver.py | |
import RPi_I2C_driver | |
from time import * | |
mylcd = RPi_I2C_driver.lcd() | |
# test 2 | |
mylcd.lcd_display_string("RPi I2C test", 1) | |
mylcd.lcd_display_string(" Custom chars", 2) | |
sleep(2) # 2 sec delay | |
mylcd.lcd_clear() | |
# let's define a custom icon, consisting of 6 individual characters | |
# 3 chars in the first row and 3 chars in the second row | |
fontdata1 = [ | |
# Char 0 - Upper-left | |
[ 0x00, 0x00, 0x03, 0x04, 0x08, 0x19, 0x11, 0x10 ], | |
# Char 1 - Upper-middle | |
[ 0x00, 0x1F, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00 ], | |
# Char 2 - Upper-right | |
[ 0x00, 0x00, 0x18, 0x04, 0x02, 0x13, 0x11, 0x01 ], | |
# Char 3 - Lower-left | |
[ 0x12, 0x13, 0x1b, 0x09, 0x04, 0x03, 0x00, 0x00 ], | |
# Char 4 - Lower-middle | |
[ 0x00, 0x11, 0x1f, 0x1f, 0x0e, 0x00, 0x1F, 0x00 ], | |
# Char 5 - Lower-right | |
[ 0x09, 0x19, 0x1b, 0x12, 0x04, 0x18, 0x00, 0x00 ], | |
# Char 6 - my test | |
[ 0x1f,0x0,0x4,0xe,0x0,0x1f,0x1f,0x1f], | |
] | |
# Load logo chars (fontdata1) | |
mylcd.lcd_load_custom_chars(fontdata1) | |
# Write first three chars to row 1 directly | |
mylcd.lcd_write(0x80) | |
mylcd.lcd_write_char(0) | |
mylcd.lcd_write_char(1) | |
mylcd.lcd_write_char(2) | |
# Write next three chars to row 2 directly | |
mylcd.lcd_write(0xC0) | |
mylcd.lcd_write_char(3) | |
mylcd.lcd_write_char(4) | |
mylcd.lcd_write_char(5) | |
sleep(2) | |
mylcd.lcd_clear() | |
mylcd.lcd_display_string_pos("Testing",1,1) # row 1, column 1 | |
sleep(1) | |
mylcd.lcd_display_string_pos("Testing",2,3) # row 2, column 3 | |
sleep(1) | |
mylcd.lcd_clear() | |
# Now let's define some more custom characters | |
fontdata2 = [ | |
# Char 0 - left arrow | |
[ 0x1,0x3,0x7,0xf,0xf,0x7,0x3,0x1 ], | |
# Char 1 - left one bar | |
[ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 ], | |
# Char 2 - left two bars | |
[ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 ], | |
# Char 3 - left 3 bars | |
[ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c ], | |
# Char 4 - left 4 bars | |
[ 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e ], | |
# Char 5 - left start | |
[ 0x0,0x1,0x3,0x7,0xf,0x1f,0x1f,0x1f ], | |
# Char 6 - | |
# [ ], | |
] | |
# Load logo chars from the second set | |
mylcd.lcd_load_custom_chars(fontdata2) | |
block = chr(255) # block character, built-in | |
# display two blocks in columns 5 and 6 (i.e. AFTER pos. 4) in row 1 | |
# first draw two blocks on 5th column (cols 5 and 6), starts from 0 | |
mylcd.lcd_display_string_pos(block * 2,1,4) | |
# | |
pauza = 0.2 # define duration of sleep(x) | |
# | |
# now draw cust. chars starting from col. 7 (pos. 6) | |
pos = 6 | |
mylcd.lcd_display_string_pos(unichr(1),1,6) | |
sleep(pauza) | |
mylcd.lcd_display_string_pos(unichr(2),1,pos) | |
sleep(pauza) | |
mylcd.lcd_display_string_pos(unichr(3),1,pos) | |
sleep(pauza) | |
mylcd.lcd_display_string_pos(unichr(4),1,pos) | |
sleep(pauza) | |
mylcd.lcd_display_string_pos(block,1,pos) | |
sleep(pauza) | |
# and another one, same as above, 1 char-space to the right | |
pos = pos +1 # increase column by one | |
mylcd.lcd_display_string_pos(unichr(1),1,pos) | |
sleep(pauza) | |
mylcd.lcd_display_string_pos(unichr(2),1,pos) | |
sleep(pauza) | |
mylcd.lcd_display_string_pos(unichr(3),1,pos) | |
sleep(pauza) | |
mylcd.lcd_display_string_pos(unichr(4),1,pos) | |
sleep(pauza) | |
mylcd.lcd_display_string_pos(block,1,pos) | |
sleep(pauza) | |
# | |
# now again load first set of custom chars - smiley | |
mylcd.lcd_load_custom_chars(fontdata1) | |
mylcd.lcd_display_string_pos(unichr(0),1,9) | |
mylcd.lcd_display_string_pos(unichr(1),1,10) | |
mylcd.lcd_display_string_pos(unichr(2),1,11) | |
mylcd.lcd_display_string_pos(unichr(3),2,9) | |
mylcd.lcd_display_string_pos(unichr(4),2,10) | |
mylcd.lcd_display_string_pos(unichr(5),2,11) | |
sleep(2) | |
mylcd.lcd_clear() | |
sleep(1) | |
mylcd.backlight(0) |
# -*- coding: utf-8 -*- | |
""" | |
Compiled, mashed and generally mutilated 2014-2015 by Denis Pleic | |
Made available under GNU GENERAL PUBLIC LICENSE | |
# Modified Python I2C library for Raspberry Pi | |
# as found on http://www.recantha.co.uk/blog/?p=4849 | |
# Joined existing 'i2c_lib.py' and 'lcddriver.py' into a single library | |
# added bits and pieces from various sources | |
# By DenisFromHR (Denis Pleic) | |
# 2015-02-10, ver 0.1 | |
""" | |
# | |
# | |
import smbus | |
from time import * | |
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) | |
# 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 | |
# flags for backlight control | |
LCD_BACKLIGHT = 0x08 | |
LCD_NOBACKLIGHT = 0x00 | |
En = 0b00000100 # Enable bit | |
Rw = 0b00000010 # Read/Write bit | |
Rs = 0b00000001 # Register select bit | |
class lcd: | |
#initializes objects and lcd | |
def __init__(self): | |
self.lcd_device = i2c_device(ADDRESS) | |
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 | LCD_BACKLIGHT) | |
sleep(.0005) | |
self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT)) | |
sleep(.0001) | |
def lcd_write_four_bits(self, data): | |
self.lcd_device.write_cmd(data | LCD_BACKLIGHT) | |
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)) | |
# write a character to lcd (or character rom) 0x09: backlight | RS=DR< | |
# works! | |
def lcd_write_char(self, charvalue, mode=1): | |
self.lcd_write_four_bits(mode | (charvalue & 0xF0)) | |
self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0)) | |
# put string function | |
def lcd_display_string(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_write(ord(char), Rs) | |
# clear lcd and set to home | |
def lcd_clear(self): | |
self.lcd_write(LCD_CLEARDISPLAY) | |
self.lcd_write(LCD_RETURNHOME) | |
# define backlight on/off (lcd.backlight(1); off= lcd.backlight(0) | |
def backlight(self, state): # for state, 1 = on, 0 = off | |
if state == 1: | |
self.lcd_device.write_cmd(LCD_BACKLIGHT) | |
elif state == 0: | |
self.lcd_device.write_cmd(LCD_NOBACKLIGHT) | |
# add custom characters (0 - 7) | |
def lcd_load_custom_chars(self, fontdata): | |
self.lcd_write(0x40); | |
for char in fontdata: | |
for line in char: | |
self.lcd_write_char(line) | |
# define precise positioning (addition from the forum) | |
def lcd_display_string_pos(self, string, line, pos): | |
if line == 1: | |
pos_new = pos | |
elif line == 2: | |
pos_new = 0x40 + pos | |
elif line == 3: | |
pos_new = 0x14 + pos | |
elif line == 4: | |
pos_new = 0x54 + pos | |
self.lcd_write(0x80 + pos_new) | |
for char in string: | |
self.lcd_write(ord(char), Rs) |
Hi Dennis,
Here Ger from Holland.
Can you tell me if you already made a scroll option.
Your scripts are very nice.
Thanks for an answer
Greetings Ger
Hi Dennis,
I'm using your library in my outdoor spa project. It works like a charm!
Thx.
Thanks for the code Dennis. Here's what I'm using for text scrolling in case it helps anyone:
async def display(lcd, display_queue):
ln1, ln2 = "", ""
ln1_i, ln2_i = 0, 0
while True:
if not display_queue.empty():
ln1, ln2 = await display_queue.get()
ln1_i, ln2_i = 0, 0
lcd.lcd_clear()
else:
ln1_i = 0 if len(ln1) <= 16 else (ln1_i + 1) % (len(ln1) - NUM_COLS + 1)
ln2_i = 0 if len(ln2) <= 16 else (ln2_i + 1) % (len(ln2) - NUM_COLS + 1)
lcd.lcd_display_string(ln1[ln1_i:ln1_i+NUM_COLS], 1)
lcd.lcd_display_string(ln2[ln2_i:ln2_i+NUM_COLS], 2)
await asyncio.sleep(0.5)
where display_queue is an asyncio.Queue.
To display something, call await display_queue.put(("Loooooooooooooooooonng", "Teeeeeeeeeeeeeeeeeeext"))
Hi Dennis,
Thank you for your work on this. I attempted to make this work in the 8-bit mode but have not been able to.
116 self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_8BITMODE)
How can the following write statements be condensed into 1 line instead of the two in 8 bit mode.
def lcd_write_char(self, charvalue, mode=1):
self.lcd_write_four_bits(mode | (charvalue & 0xF0))
self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0))
def lcd_write(self, cmd, mode=0):
self.lcd_write_four_bits(mode | (cmd & 0xF0))
self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))
I tried this but it gives strange results even though the binary output is correct for this command:
def lcd_write(self, cmd, mode=0):
self.lcd_write_four_bits(mode | (cmd & 0xFF))
Thanks, I'm new to this stuff, TIL about potentiometer from your comment