-
Star
(119)
You must be signed in to star a gist -
Fork
(63)
You must be signed in to fork a gist
-
-
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