早在我將舊型電話按鍵盤改做數字鍵盤之前,就覺得直接驅動 3x4 數字鍵盤至少需要用到 7 條 GPIO 接線,這樣太過佔用 GPIO 腳位了,便有了該將之改造成 I²C (Inter-Integrated Circuit) 介面的想法。
I²C 是一種串列通訊匯流排 (bus),使用兩條信號接線-串列資料 (SDA) 與串列時脈 (SCL),便可讓一個主裝置與多個從屬裝置進行雙向通信,週邊更可以在系統仍然在運作的同時加入或移出匯流排。現在的嵌入式系統和微控制器普遍都提供了這個通信介面,它常被應用在簡單且其製造成本較傳輸速度更為要求的週邊裝置上。
尋找到的 MCP23008 是一個具有將串列介面擴充成 8 位元輸入/輸出的 IC,查看了它的 data sheet,直覺應該可以達成目的,便先買了兩顆來試試。
在 Raspberry Pi 的測試
若不能確認 Raspbian 是否已啟用 I²C,可參考 Using the I2C Interface 的說明,該文也列出了稍後即將使用到的 SMBus Functions。
再來要在麵包板上接線-將 Raspberry Pi 與 MCP23008 的 I²C 信號腳位連接,MCP23008 的 GPIO 與數字鍵盤的接腳連接,如以下所示。
RPi MCP23008 3x4 Keypad --- -------- ---------- SCL <---> SCL SDA <---> SDA 3V3 <---> VDD GND <---> VSS GP0 ----> C1 GP1 ----> C2 GP2 ----> C3 GP3 <---- R1 GP4 <---- R2 GP5 <---- R3 GP6 <---- R4
MCP23008 有三個接腳 (A0, A1, A2) 是用來設定從屬裝置在 I²C bus 上的位址 (address),將其皆接在 GND 可得位址為 0x20,事後可用 i2cdetect 指令確認位址是否如預期。另外還有 i2cget 與 i2cset 兩個指令可用來對從屬裝置做讀取與寫入。
pi@raspberrypi ~ $ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
MCP23008 內部有 11 個暫存器做設定與控制用的,以下稱 CCR (Configuration and Control Registers),程式將對這些 CCR 進行讀取或寫入以達成與所連接的裝置通信或控制的目的。
我將這些基本功能編寫成一個 MCP23008 類別以方便讀取或寫入 CCR,基於此再編寫了一個 MyNumPad 類別,使應用程式輕易讀取數字鍵盤的輸入。程式範例如下:
#!/usr/bin/python from mcp23008 import MCP23008 import time class MyNumPad: keys= [['1','2','3'],['4','5','6'],['7','8','9'],['*','0','#']] def __init__(self, address): self.mcp= MCP23008(address) def read(self): self.mcp.writeByte('IODIR', 0b11111000) self.mcp.writeByte('GPIO', 0) self.mcp.writeByte('GPPU', 0b11111111) for i in range(3): self.mcp.writeByte('GPIO', (1 << i) ^ 0b11111111) time.sleep(0.05) v= (self.mcp.readByte('GPIO') | 0b00000111) ^ 0b11111111 for j in range(4): if (v & (0b00001000 << j)) != 0: time.sleep(0.1) return self.keys[j][i] return 0 # test read input from MyNumPad try: npad= MyNumPad(0x20) while True: ch= npad.read() if ch != 0: print ch except KeyboardInterrupt: pass
使用 MCP23008 的小提示
各 GPIO 接腳僅可做內部 PULL-UP 的控制,不像直接使用 Raspberry Pi 的 GPIO 可以控制做 PULL-UP 或 PULL-DOWN,所以程式在掃瞄鍵盤按下時是要判斷電位為 LOW。
另外,RESET 與三個位址接腳不要空接,否則 MC23008 可能會處在不穩定的狀態。
下次,來試試接 16x2 LCD 顯示器模組。
沒有留言:
張貼留言