Orange Pi 通過I2C總線連接LCD1602
前言
上一節通過Orange Pi gpio 直接控制1602,可以看出來缺點非常明顯:Orange Pi IO 口占用過多
因爲Orange Pi的GPIO口非常有限,所以這一章就來解決這個問題,採用 i2c轉LCD1602的轉接板( PCF85741)來減少Orange Pi 的GPIO佔用
一、硬件及連線:
模塊長這樣子,網上找的圖:
和1602連在一起是這樣子,這個是焊接在一起的,也可以用杜邦線連接起來
有了這貨之後,連接香橙派就只需要兩根數據線就可以了,如果不算電源線的話,加上電源線一共也才四根線,清爽多了
連線也是so easy,下面奉上接線方式(物理接口):
:---PCF85741---: :---Orange Pi---:
GND-------------06 GROUND
VCC-------------04 5V
SDA-------------03 SDA1
SCL-------------05 SDA1
好了,完成上面的接線工作,就可以通電了。
連接電源打開樹莓派,顯示屏就會亮,同時在第一行顯示一排黑方塊。如果看不到黑方塊或黑方塊不明顯,請調節i2c模塊上的可調電阻,直到黑方塊清晰顯示。如果調節可調電阻還看不到方塊,則可能你的連接有問題了,請檢查連接,包括檢查顯示屏的引腳有沒有虛焊。
二、使能I2C
由於我的系統是armbian的,比較方便,如果你裝的是orangepi官網提供的ubuntu,建議你不要折騰了,換回armbian會讓你省很多事。這是我含淚踩過的坑啊,內核都重新編譯過了,心酸
廢話不多說,先看看默認有沒有使能i2c:
ls /dev | grep i2c
什麼都沒有,看來是沒有使能i2c啊
接下來開啓i2c,armbian有一個非常好用的工具,類似樹莓派的raspi-config,它就是armbian-config
sudo armbian-config
忘了截圖了,依次進入:system
>>HardWare
>>[ ]i2c0
,按空格鍵選中i2c0,變成[* ]i2c0
這樣子,
然後選中save,reboot即可
再執行:
ls /dev | grep i2c
打印出 i2c-0 了,說明開啓成功,接下來看一下i2c設備地址:
root@orangepi:~# sudo apt install i2c-tools
root@orangepi:~# i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
可以看到我的i2c設備地址是0x27
這說明 已經成功連接了 LCD1602 。接下來就可以用 Python 控制 LCD1602 顯示信息了。
三、驅動程序:
python驅動i2c需要python-smbus,先安裝一下:
sudo apt-get install python3-smbus
接下來我們熟悉的套路,上代碼,如下:
vim i2c_1602_test.py
#!/usr/bin/python
# coding:utf-8
'''
BIT D7 D6 D5 D4 D3 D2 D1 D0
| | | | | | | |
LCD D7 D6 D5 D4 BackLight En Rw Rs
'''
import time
import smbus
import sys
Bl = 0B00001000 # backlight 0:off 1:on
En = 0B00000100 # Enable bit
Rw = 0B00000010 # Read/Write bit 0:write 1:read
Rs = 0B00000001 # Register select bit 0:cmd 1:data
LCD_WIDTH = 16 # Maximum characters per line
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
debug = 0
#創建一個smbus實例
BUS = smbus.SMBus(0) # 0 代表 /dev/i2c-0, 1 代表 /dev/i2c-1 ,具體看使用的樹莓派那個I2C來決定
LCD_ADDR = 0x27 #sudo i2cdetect -y -a 0
def main():
global debug
if len(sys.argv)>1:
debug = 1
print("turn on debug,welcom!")
else:
debug = 0
init_lcd()
while True:
show_on_lcd(LCD_LINE_1, 0, '1234567890123456')
show_on_lcd(LCD_LINE_2, 0, 'abcdefghijklmnop')
time.sleep(3) # 3 second delay
show_on_lcd(LCD_LINE_1, 0, 'blog.csdn.net')
show_on_lcd(LCD_LINE_2, 0, 'Running_free')
time.sleep(3) # 3 second delay
def send_command(comm):
if debug:
print("****************now send sommand******************")
print("now send command >>>>>>>>>>>>>>>>>",hex(comm),"---",bin(comm))
# Send bit7-4 firstly
buf = comm & 0xF0 | Bl | En
if debug:
print(" high: ",bin(buf)),
# buf |= (Bl | En) # BL = 1, EN = 1, RW = 0, RS = 0
BUS.write_byte(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # EN = 0
if debug:
print(" high_en: ",bin(buf)),
BUS.write_byte(LCD_ADDR ,buf)
# Send bit3-0 secondly
buf = ((comm & 0x0F) << 4)| Bl | En
if debug:
print(" low: ",bin(buf)),
# buf |= (Bl | En) # BL = 1, EN = 1, RW = 0, RS = 0
BUS.write_byte(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # EN = 0
if debug:
print(" low_en: ",bin(buf),"end<<<<<<<<<<<<<<<<<<<<<<")
BUS.write_byte(LCD_ADDR ,buf)
def send_data(data):
if debug:
print("****************now send data******************")
print("now send data --------------",hex(data),"---",bin(data))
# Send bit7-4 firstly
buf = data & 0xF0 | Bl | En | Rs
if debug:
print(" high: ",bin(buf)),
# buf |= (Bl | En | Rs) # BL = 1, EN = 1, RW = 0, RS = 1
BUS.write_byte(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # EN = 0
if debug:
print(" high_en: ",bin(buf)),
BUS.write_byte(LCD_ADDR ,buf)
# Send bit3-0 secondly
buf = ((data & 0x0F) << 4)| Bl | En | Rs
if debug:
print(" low: ",bin(buf)),
# buf |= (Bl | En | Rs) # BL = 1, EN = 1, RW = 0, RS = 1
BUS.write_byte(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # EN = 0
if debug:
print(" low_en: ",bin(buf),"end------------------")
BUS.write_byte(LCD_ADDR ,buf)
def init_lcd():
if debug:
print("****************now init******************")
send_command(0x33) # Must initialize to 8-line mode at first
time.sleep(0.005)
send_command(0x32) # Then initialize to 4-line mode
time.sleep(0.005)
send_command(0x06) # Cursor move direction
time.sleep(0.005)
send_command(0x0C) # Enable display without cursor
time.sleep(0.005)
send_command(0x28) # 2 Lines & 5*7 dots
time.sleep(0.005)
send_command(0x01) # Clear Screen
time.sleep(0.005)
def clear_lcd():
if debug:
print("****************now clear******************")
send_command(0x01) # Clear Screen
def show_on_lcd(line,table,message):
if debug:
print("****************now show on lcd******************")
# Send string to display
message = message.ljust(LCD_WIDTH," ")
send_command(line)
for i in range(LCD_WIDTH):
send_data(ord(message[i]))
if __name__ == '__main__':
try:
main()
#except KeyboardInterrupt:
except:
pass
finally:
clear_lcd()
show_on_lcd(LCD_LINE_1, 0, 'Goodbye!')
BUS.close()
加了debug方便調試,運行python3 i2c_1602_test.py
後面不跟參數不打印debug信息,如果想打印debug信息,只需要後面跟一個參數即可,任何參數都ok,例:python3 i2c_1602_test.py 1
或者 python3 i2c_1602_test.py debug
#僅運行
python3 i2c_1602_test.py
#運行並打印debug信息
python3 i2c_1602_test.py debug
總結
如果1602沒有顯示,請檢查線路是否有故障,杜邦線容易鬆動導致接觸不良,傳輸數據就會出現問題,含着淚踩過的坑啊