![]() |
自製 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 位元資料介面傳輸時序圖例 |
完成的程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #!/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 " ) |
完成、測試,有圖為證
沒有留言:
張貼留言