# 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) |
This comment has been minimized.
This comment has been minimized.
Hi is their a way to invert the characters? |
This comment has been minimized.
This comment has been minimized.
Never occured to me, to be honest.... |
This comment has been minimized.
This comment has been minimized.
Another thing which I encountered in Arch Linux on RasPi: you might get the following error message when running the above examples: |
This comment has been minimized.
This comment has been minimized.
Hi Denis, are you able to describe how to add a degree symbol? I've tried chr(176) chr(223) and unichr(176) unichr(223) and can't get it to work. Here's a snippet of my code:
|
This comment has been minimized.
This comment has been minimized.
sturgeo,
(haven't checked it, but should be something like that...) |
This comment has been minimized.
This comment has been minimized.
Hi Denis, i have a weired issue when printing a row as above with temperature as %currenttemp, i get the upper right part of the pumpkin character you've made right after the value... i've already try the recantha library before and had the same issue with a different character any idea on how to get ride of it? |
This comment has been minimized.
This comment has been minimized.
i find my solution |
This comment has been minimized.
This comment has been minimized.
Hi Denis,
this works fine for me, and you can just append the position if needed (and you can even ommit the line which then defaults to 1). Here are your modified files: Greetz, Guen. |
This comment has been minimized.
This comment has been minimized.
Thanks for the libs! I've spend several hours for trying start libs working.. And I fix it with screwdriver.. Fix potentiometer brightness. |
This comment has been minimized.
This comment has been minimized.
Thanks DenisFromHR for your hard time coding for Raspberry Pi I2C LCD HD44780 + PCF8574 backpack! You've done great job! I am using the latest revision from gknauf.. Change it based on my needs. |
This comment has been minimized.
This comment has been minimized.
Thanks @DenisFromHR and @gknauf for your efforts. :) |
This comment has been minimized.
This comment has been minimized.
Hi, thanks for this it looks promising but I can't get it to work... I'm using a 16x2 HD44780 LCD connected to a PCF8574N chip, wired to the RPi 2 via I2C (stand alone chip, not a back pack) wired following this tutorial: http://www.rpiblog.com/2012/07/interfacing-16x2-lcd-with-raspberry-pi.html. My problem is when I run examples.py, the program runs without errors, but nothing displays on the LCD. I have changed the address in the library. Is there anything else I need to change in the library or example program for my specific set up? Any help would really be appreciated! |
This comment has been minimized.
This comment has been minimized.
Hello, first of all, thanks Denis for your job... I'm very sorry for this silly question but I'm not able to install your library in my Raspi. Downloaded the library in my RPi and tried to install using "pip install RPi_I2C_driver.py".... I obtain a bunch of errors and library wont install. |
This comment has been minimized.
This comment has been minimized.
Thanks, Denis. Great implementation. |
This comment has been minimized.
This comment has been minimized.
I could not write on a 16x2 display with SPLC780C chip, apareece only strange characters, any tips ? |
This comment has been minimized.
This comment has been minimized.
I can't get |
This comment has been minimized.
This comment has been minimized.
It works like a charm on my RPi B. Thank you very much! |
This comment has been minimized.
This comment has been minimized.
Can you only have 8 custom characters? I defined 9 but char(0) then displayed the same symbol as char(8) |
This comment has been minimized.
This comment has been minimized.
Never mind - I found the answer http://mil.ufl.edu/4744/docs/lcdmanual/characterset.html |
This comment has been minimized.
This comment has been minimized.
I have following problem:
Does anyone know what is wrong? I copy pasted code. Running i2cdetect 0 says that my i2c is under 0x27 address (so I did not change anything in the script). Do you have any ideas what is wrong? I connected i2c to hd44780 pin by pin (1--1, 2--2, 3--3, 4--4, etc.) |
This comment has been minimized.
This comment has been minimized.
Anybody experiencing strange characters after a certain amount of uptime? Seems to work again when restarting the script, maybe a memory issue? |
This comment has been minimized.
This comment has been minimized.
Yes! me! EDIT: Internet conection seems to be affecting somehow. With either ethernet cable or wifi dongle, it displays the characters of doom after about 30min. Without any conection it will last for about 6 hours. |
This comment has been minimized.
This comment has been minimized.
Looking for help or advice on this. What I am trying to do is have 4 independent scripts, each write to one single line. Script 1 - python - real time date and time with seconds displayed on line 1 - script is always running and updates line one once a second. No lcd_clear() used. So, each one works perfectly on their own. When I have two or more running, it will soon start writing random characters to the screen, mostly on the wrong lines (can be above or below). It can happen nearly instantly or start happening 20 minutes later. I have tried adding the screen clear to one or more of the scripts, but due to other issues (data not being present on the script run), lines won't update again until the next cron run or command. Not ideal, plus I hate the way the lcd_clear() looks when it happens. I am sure it has to do something with two or more scripts trying to access the lcd at nearly the same time. So, any ideas or suggestions to get 4 scripts each writing their own line, to play nice and not corrupt the display? Any thoughts are welcomed. Thanks! |
This comment has been minimized.
This comment has been minimized.
Hey all! I came across this looking for info on how to get my own LCD/I2C combo to work with my rpi 3, and thought it would be beneficial for enough people to make it into a pypi package. Any ideas/contributions/complaints are welcome! |
This comment has been minimized.
This comment has been minimized.
I can't understand what mean: 0x00, 0x00, 0x03, 0x04, 0x08, 0x19, 0x11, 0x10 |
This comment has been minimized.
This comment has been minimized.
Hi, can u help me ? Traceback (most recent call last): where do i defined this 'unichr' ? |
This comment has been minimized.
This comment has been minimized.
@DenisFromHR any idea what these are for?
|
This comment has been minimized.
This comment has been minimized.
Great stuff! I live in Norway, but apparently I have the LCD ROM with the Japanese font set, which makes displaying the nordic characters (æ, ø, å) a real headache, at least when you're dealing with inconsistent ascii-tables and unicode (UTF8) conversions on top of that. However, I made a custom font set with the "missing" norwegian characters, if anyone's interested. Just out of curiousity:
it would be GREAT if I somehow managed to automatically map the character "æ" to (for instance) chr(1), "ø" to chr(2) and so on. And if everything else fails, shouldn't it be possible to do a "char.replace('ø', chr(1))", or something similar in Python? It would make the programming flow SO much easier. Any thoughts? Anyway, here's my (very basic) example code (updated):
Update: Here's how I managed to add the extra Norwegian characters to the font set. I know there are more efficient ways to do this, but I'm still learning Python, and for this purpose it kind of works:
|
This comment has been minimized.
This comment has been minimized.
Good job, Denis! In case anyone is interested, here it is: cheers, Martin |
This comment has been minimized.
This comment has been minimized.
Hi Denis, |
This comment has been minimized.
This comment has been minimized.
I'm trying to use this driver with PCF8574's younger sibling - PCA9554P with a 16x2 lcd display, but it does not work at all. I'm constantly getting a same error:
and
I'm using Raspbian stretch full, downloaded on 9.11.2018. |
This comment has been minimized.
This comment has been minimized.
Is it possible to run multiple LCD's each with a different address? |
This comment has been minimized.
This comment has been minimized.
Thank you for posting this - I was pulling my hair out over the same thing. |
This comment has been minimized.
This comment has been minimized.
Hi Denis |
This comment has been minimized.
This comment has been minimized.
Dear @DenisFromHR Myself and some others use your code to make a contribution to the RPi-Jukebox-RFID project. This project allows to build a simple to use Jukebox like Music Player which is extremely interesting for small Kids. I use these Jukeboxes for my three Kids. Current status is, that I placed a pull request to the RPi-Jukebox-RFID project which can be found under RPi-Jukebox-RFID Pill request #859. Currently the decision is that the code cannot be added to the project as we have a license issue. The RPi-Jukebox-RFID projet uses MIT license, see also RPI-Jukebox-RFID License Page. Your driver is released under GPL. I kindly ask you read the discussion on the pull request page related to the driver scripts/i2c_lcd_driver.py where the license issue is discussed. I hope that you could to a statement, that allows us to use your code in our Jukebox project. Thank you very much for your help regarding this matter. Best regards, |
This comment has been minimized.
This comment has been minimized.
Dear @DenisFromHR ,how can a symbol be updated? For example from this
My code work in while True: for update every second
Complete
But I still don't understand how to change a character along with a string |
This comment has been minimized.
This comment has been minimized.
Thanks, I'm new to this stuff, TIL about potentiometer from your comment |
This comment has been minimized.
This comment has been minimized.
Hi Dennis, Here Ger from Holland. Thanks for an answer Greetings Ger |
This comment has been minimized.
Perhaps someone might find this useful: I took an existing Python I2C LCD library from😄
http://www.recantha.co.uk/blog/?p=4849
and added some stuff to it (from other sources), and joined 2 existing libs to one single library that doesn't need any other libs.... In short, this works on my 16x2 and 20x4 I2C LCDs with Raspberry Pi: I can define new custom characters and show them on screen (as shown in the examples.py above).
If there is interest, I could also add some examples with text scrolling (in the works).
95% of the library is not mine: I just managed to cobble together pieces existing in several other libraries. The advantage is that this works without requiring installation of other libraries or Python modules (RPi.GPIO or others).
In short, works well enough for me as it is now, but I'll probably tinker with this some more: there is always room for improvement
My commerical stuff: http://www.hana-lab.com
Regards,
Denis