自製 I²C 介面接線:Raspberry Pi 與 LCD1602 |
現在市面上販售的模組許多是並列介面(某些會加裝 I²C 介面,價格稍高一些),如同前文所考量的,我希望使用 I²C 介面而讓出 GPIO 信號接腳以做其他的外部感測或控制等用途,所以就自己來為並列介面的模組客製一個 I²C 介面吧~
當然,我也可以省事地直接買一片有 I²C 介面的模組用就好,但自己客製有動手做的趣味,有需要時也有能力來為其他組件修改介面。
若輸入關鍵字 LCD1602 在網路上搜尋,會發現有許多不同廠商供應類似模組的規格資料。儘管有許多廠商製造,但它們的組成結構與規格內容幾乎完全一樣。模組主要由一個液晶控制晶片與一片液晶面板加上驅動電路所組成。液晶面板可顯示上下 2 列文字,每列各 16 個字符,而採用的液晶控制晶片多與 HD44780 相容,模組有 16 個信號接腳供 MCU/MPU 用來控制與傳輸資料,資料傳輸介面可被程式化使用 8 位元或 4 位元。
LCD1602 模組接腳描述 |
接線
此次,同上回做 3x4 數字按鍵時一樣,使用 MCP23008 做為 I²C 介面 I/O 擴充元件,因為只有 8 位元的 I/O 可用,所以規劃採用 LCD1602 模組的 4 位元資料介面。同樣以 Raspberry Pi 做使用範例,將各部件腳位接線完成,以下僅將 Raspberry Pi, MCP23008, 與 LCD1602 之間的主要信號接線列出,其他詳見本文頂端的接線圖所示。
RPi MCP23008 LCD1602 -------- -------- -------- #5 (SCL) <--> #1 (SCL) #3 (SDA) <--> #2 (SDA) #10(GP0) <--> #11(D4) #11(GP1) <--> #12(D5) #12(GP2) <--> #13(D6) #13(GP3) <--> #14(D7) #14(GP4) <--> #5 (R/W) #15(GP5) <--> #4 (RS) #17(GP7) <--> #6 (E)
程式
參閱 HD44780 的資料表得知該模組通電後初始會被重設為 8 位元資料介面,MCU/MPU 需要對其指令暫存器寫入功能指令變更為 4 位元資料介面,此外程式也可能必須重設顯示、游標或閃爍等功能。下圖為可用的指令集:
LCD1602 指令集 |
在規劃程式寫入指令/資料暫存器前,可先參閱模組或控制晶片的時序資料以了解信號交換的協定。我以 python 撰寫程式,無法精準地控制信號位準高低時間,但時序要符合該協定的要求,資料才能正確的寫入。
4 位元資料介面傳輸時序圖例 |
完成的程式碼:
#!/usr/bin/python from mcp23008 import MCP23008 import time class LCD1602: PIN_RS= 0b00100000 PIN_RW= 0b00010000 PIN_E= 0b10000000 def __init__(self, address): self.mcp= MCP23008(address) def setE(self, byte): byte = byte | 0b10000000 self.mcp.writeByte('GPIO', byte) time.sleep(0.0005) byte = byte & 0b01111111 self.mcp.writeByte('GPIO', byte) time.sleep(0.0005) def write(self, data): self.mcp.writeByte('GPIO', data) self.setE(data) def write4bits(self, rs, data): self.byte= data >> 4 if rs: self.byte= self.byte | self.PIN_RS self.mcp.writeByte('GPIO', self.byte) self.setE(self.byte) self.byte = data & 0b00001111 if rs: self.byte= self.byte | self.PIN_RS self.mcp.writeByte('GPIO', self.byte) self.setE(self.byte) def setCursor(self, row, col): if row == 0: self.write4bits(0, 0x80 + col) elif row == 1: self.write4bits(0, 0xc0 + col) def display(self, strMsg): for c in strMsg: self.write4bits(1, ord(c)) def init(self): self.mcp.writeByte('IODIR', 0b00000000) self.mcp.writeByte('GPPU', 0b11111111) self.mcp.writeByte('GPIO', 0b01111111) time.sleep(0.05) self.write(0b00000011) time.sleep(0.001) self.write(0b00000011) time.sleep(0.001) self.write(0b00000011) time.sleep(0.001) self.write(0b00000010) time.sleep(0.001) self.write4bits(0, 0b00101000) time.sleep(0.001) self.write4bits(0, 0b00001111) time.sleep(0.001) self.write4bits(0, 0b00000001) time.sleep(0.001) self.write4bits(0, 0b00000110) time.sleep(0.001) # test the LCD1602 module... lcd= LCD1602(0x20) lcd.init() lcd.display("Hello, LCD1602!") lcd.setCursor(1, 0) lcd.display("from S.H. Lee ")
完成、測試,有圖為證
沒有留言:
張貼留言