Orange Pi 通過I2C總線連接LCD1602

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沒有顯示,請檢查線路是否有故障,杜邦線容易鬆動導致接觸不良,傳輸數據就會出現問題,含着淚踩過的坑啊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章