最近打算接駁幾個顯示器,顯示一些資料
但單單是一個 8x8點陣顯示器 便要用 16支引腳,引腳使用量非常多
因此尋找一些類似使用 I2C 或 SPI 不需要太多引腳便可以模擬多位元的 擴展器
但單單是一個 8x8點陣顯示器 便要用 16支引腳,引腳使用量非常多
因此尋找一些類似使用 I2C 或 SPI 不需要太多引腳便可以模擬多位元的 擴展器
MCP23017 與 在下之前介紹的 PCF8574 都是一種 I2C 的 擴展器
而且 MCP23017 是 16位元 擴展器,比 PCF8574 多8位元
由於 I2C 只需要 2支引腳 便可以讓 Slave 裝置運作,如果成本相約的話, MCP23017 擴充效果會更好
因此在下簡單比較 PCF8574* 及 MCP23017
而且 MCP23017 是 16位元 擴展器,比 PCF8574 多8位元
由於 I2C 只需要 2支引腳 便可以讓 Slave 裝置運作,如果成本相約的話, MCP23017 擴充效果會更好
因此在下簡單比較 PCF8574* 及 MCP23017
PCF8574* 外觀
PCF8574 及 PCF8574A 的正面
PCF8574 或 PCF8574A 的背面
PCF8574* 引腳
PCF8574* 具有 雙列直插封裝 (Dual In-line Package (DIP)) ,共有 16支引腳
| 後 | 引腳16 | 引腳15 | 引腳14 | 引腳13 | 引腳12 | 引腳11 | 引腳10 | 引腳9 | 
|---|---|---|---|---|---|---|---|---|
| 後 | 引腳1 | 引腳2 | 引腳3 | 引腳4 | 引腳5 | 引腳6 | 引腳7 | 引腳8 | 
| 用途 | VCC | SDA | SCL | INT | D7 | D6 | D5 | D4 | 
| A0 | A1 | A2 | D0 | D1 | D2 | D3 | GND | 
| 編號 | 描述 | 方向 | 用途 | 
|---|---|---|---|
| 1 | A0 | 輸入 | 第0位地址 | 
| 2 | A1 | 輸入 | 第1位地址 | 
| 3 | A2 | 輸入 | 第2位地址 | 
| 4 | D0 | 輸入/輸出 | 第0位元資料 | 
| 5 | D1 | 輸入/輸出 | 第1位元資料 | 
| 6 | D2 | 輸入/輸出 | 第2位元資料 | 
| 7 | D3 | 輸入/輸出 | 第3位元資料 | 
| 8 | GND | 接地 | |
| 9 | DB4 | 輸入/輸出 | 第4位元資料 | 
| 10 | DB5 | 輸入/輸出 | 第5位元資料 | 
| 11 | DB6 | 輸入/輸出 | 第6位元資料 | 
| 12 | DB7 | 輸入/輸出 | 第7位元資料 | 
| 13 | INT | 輸入 | 中斷訊號 | 
| 14 | SCL | 輸入 | 序列時脈 | 
| 15 | SDA | 輸入 | 序列資料 | 
| 16 | VCC | 電源 (接受 1.8V 至 5.5V) | 
PCF8574* 地址
PCF8574 及 PCF8574A 的地址範圍並不相同
| 類型 | 地址 | 讀/寫 | ||||||
|---|---|---|---|---|---|---|---|---|
| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |
| PCF8574 | 0 | 1 | 0 | 0 | # | # | # | * | 
| PCF8574A | 0 | 1 | 1 | 1 | # | # | # | * | 
| PCF8574地址 | 讀/寫 | 十六進制地址 | |||||||
|---|---|---|---|---|---|---|---|---|---|
| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 寫 | 讀 | 
| 0 | 1 | 0 | 0 | 0 | 0 | 0 | * | 0x40 | 0x41 | 
| 0 | 1 | 0 | 0 | 0 | 0 | 1 | * | 0x42 | 0x43 | 
| 0 | 1 | 0 | 0 | 0 | 1 | 0 | * | 0x44 | 0x45 | 
| 0 | 1 | 0 | 0 | 0 | 1 | 1 | * | 0x46 | 0x47 | 
| 0 | 1 | 0 | 0 | 1 | 0 | 0 | * | 0x48 | 0x49 | 
| 0 | 1 | 0 | 0 | 1 | 0 | 1 | * | 0x4A | 0x4B | 
| 0 | 1 | 0 | 0 | 1 | 1 | 0 | * | 0x4C | 0x4D | 
| 0 | 1 | 0 | 0 | 1 | 1 | 1 | * | 0x4E | 0x4F | 
| PCF8574A地址 | 讀/寫 | 十六進制地址 | |||||||
|---|---|---|---|---|---|---|---|---|---|
| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 寫 | 讀 | 
| 0 | 1 | 1 | 1 | 0 | 0 | 0 | * | 0x70 | 0x71 | 
| 0 | 1 | 1 | 1 | 0 | 0 | 1 | * | 0x72 | 0x73 | 
| 0 | 1 | 1 | 1 | 0 | 1 | 0 | * | 0x74 | 0x75 | 
| 0 | 1 | 1 | 1 | 0 | 1 | 1 | * | 0x76 | 0x77 | 
| 0 | 1 | 1 | 1 | 1 | 0 | 0 | * | 0x78 | 0x79 | 
| 0 | 1 | 1 | 1 | 1 | 0 | 1 | * | 0x7A | 0x7B | 
| 0 | 1 | 1 | 1 | 1 | 1 | 0 | * | 0x7C | 0x7D | 
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | * | 0x7E | 0x7F | 
PCF8574* 電路
電路原型
使用 PCF8574 及 PCF8574A 來測試電路
測試效果
即使只顯示 1格 LED 都很暗,如果 64格 LED 全亮著接近沒有光度
即使只顯示 1格 LED 都很暗,如果 64格 LED 全亮著接近沒有光度
在下使用 Arduino 預設的 Wire.h 函式庫測試
#include <Wire.h>
byte anodeAddress = 0x20;
byte cathodeAddress = 0x38;
void set(byte address, byte data) {
    Wire.beginTransmission(address);
    Wire.write(data);
    Wire.endTransmission();
}
void setup() {
    Wire.begin();
}
void loop() {
    for (byte r = 0; r < 8; r++) {
        // anodes
        set(cathodeAddress, ~0x00);
        set(anodeAddress, 1 << r);
        for (byte c = 0; c < 8; c++) {
            // cathodes
            set(cathodeAddress, ~(1 << c));
            delay(100);
        }
    }
}閣下可能會發現 Wire.h 設定地址分別是 0x20 及 0x38 並不是 PCF8574 及 PCF8574A 的範圍
原因是 Wire.h 設定地址時,並不理會讀寫的位元
即是如果要指定 0x40 的地址時,會向右偏移 1位元,所以 0x40 >> 1 即是 0x20
同樣,如果要指定 0x70 的地址時,會向右偏移 1位元,所以 0x70 >> 1 即是 0x38
原因是 Wire.h 設定地址時,並不理會讀寫的位元
即是如果要指定 0x40 的地址時,會向右偏移 1位元,所以 0x40 >> 1 即是 0x20
同樣,如果要指定 0x70 的地址時,會向右偏移 1位元,所以 0x70 >> 1 即是 0x38
MCP23017 外觀
MCP23017 的正面
MCP23017 的背面
MCP23017 引腳
MCP23017 同樣具有 雙列直插封裝 (Dual In-line Package (DIP)) ,共有 28支引腳,數量與 ATmega328P* 相同
| 後 | 引腳28 | 引腳27 | 引腳26 | 引腳25 | 引腳24 | 引腳23 | 引腳22 | 引腳21 | 引腳20 | 引腳19 | 引腳18 | 引腳17 | 引腳16 | 引腳15 | 
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 後 | 引腳1 | 引腳2 | 引腳3 | 引腳4 | 引腳5 | 引腳6 | 引腳7 | 引腳8 | 引腳9 | 引腳10 | 引腳11 | 引腳12 | 引腳13 | 引腳14 | 
| 用途 | DA7 | DA6 | DA5 | DA4 | DA3 | DA2 | DA1 | DA0 | INTA | INTB | RST | A2 | A1 | A0 | 
| DB0 | DB1 | DB2 | DB3 | DB4 | DB5 | DB6 | DB7 | VCC | GND | NC0 | SCL | SDA | NC1 | 
| 編號 | 描述 | 方向 | 用途 | 
|---|---|---|---|
| 1 | DB0 | 輸入/輸出 | Port B 第0位元資料 | 
| 2 | DB1 | 輸入/輸出 | Port B 第1位元資料 | 
| 3 | DB2 | 輸入/輸出 | Port B 第2位元資料 | 
| 4 | DB3 | 輸入/輸出 | Port B 第3位元資料 | 
| 5 | DB4 | 輸入/輸出 | Port B 第4位元資料 | 
| 6 | DB5 | 輸入/輸出 | Port B 第5位元資料 | 
| 7 | DB6 | 輸入/輸出 | Port B 第6位元資料 | 
| 8 | DB7 | 輸入/輸出 | Port B 第7位元資料 | 
| 9 | VCC | 電源 (接受 1.8V 至 5.5V) | |
| 10 | GND | 接地 | |
| 11 | NC0 | 無效 | |
| 12 | SCL | 輸入 | 序列時脈 | 
| 13 | SDA | 輸入 | 序列資料 | 
| 14 | NC1 | 無效 | |
| 15 | A0 | 輸入 | 第0位地址 | 
| 16 | A1 | 輸入 | 第1位地址 | 
| 17 | A2 | 輸入 | 第2位地址 | 
| 18 | RST | 輸入 | 高電位時重設,低電位時運作 | 
| 19 | INTB | 輸出 | 中斷 Port B 訊號 | 
| 20 | INTA | 輸出 | 中斷 Port A 訊號 | 
| 21 | DA0 | 輸入/輸出 | Port A 第0位元資料 | 
| 22 | DA1 | 輸入/輸出 | Port A 第1位元資料 | 
| 23 | DA2 | 輸入/輸出 | Port A 第2位元資料 | 
| 24 | DA3 | 輸入/輸出 | Port A 第3位元資料 | 
| 25 | DA4 | 輸入/輸出 | Port A 第4位元資料 | 
| 26 | DA5 | 輸入/輸出 | Port A 第5位元資料 | 
| 27 | DA6 | 輸入/輸出 | Port A 第6位元資料 | 
| 28 | DA7 | 輸入/輸出 | Port A 第7位元資料 | 
MCP23017 地址
MCP23017地址 與 PCF8574地址 相同,地址範圍為 0x20 至 0x27
MCP23017 暫存器
MCP23017 暫存器 共有 11個指令,區分 Port A 及 Port B 即是總共 22個指令
| 指令 | 用途 | 
|---|---|
| IODIR | 輸入輸出方向暫存器 (Input/Output Direction Register) 控制 Port 的方向,高電位為輸入,低電位為輸出 例如:0x03 表示第7至第2引腳為輸出,第1至第0引腳為輸入  | 
| IPOL | 輸入極性暫存器 (Input Polarity Register) 當 Port 的設定為輸入時,改變輸入的極性為相反訊號,即是高電位改變為低電位,反之亦然 例如:0xC0 表示第7至第6引腳極性會反轉,第5至第0引腳極性為正常  | 
| GPINTEN | 通用目的輸入輸出中斷啟動暫存器 (General Purpose Input/Output Interrupt Enable Register) 指定 Port 引腳為中斷,高電位為啟動,低電位為取消 例如:0x0F 表示第7至第4引腳為取消,第3至第0引腳為啟動 啟動 Interrupt on Change 的引腳,必須設定 DEFVAL 及 INTCON 功能  | 
| DEFVAL | 預設值暫存器 (Default Value Register) 設定 Port 引腳的預設值 當引腳的狀態與引腳的預設值為相反時,中斷操作  | 
| INTCON | 中斷控制暫存器 (Interrupt Control Register) 設定 Port 引腳的比較狀態 高電位為與 DEFVAL 比較,低電位為與 Port 引腳上次電位比較  | 
| IOCON | 輸入輸出設置暫存器 (Input/Output Configuration Register)
  | 
| GPPU | 通用目的輸入輸出上拉電阻暫存器 (General Purpose Input/Output Pull-Up Resistor Register) 當 Port引腳 設定為 輸入時,可以啟動 100KΩ 的上拉電阻 高電位 為 啟動上拉電阻,低電位 為 取消上拉電阻  | 
| INTF | 中斷標示暫存器 (Interrupt Flag Register) 反映 Port引腳 的中斷條件 高電位 為 引起中斷,低電位 為 未指定中斷條件  | 
| INTCAP | 中斷擷取暫存器 (Interrupt Captured Register) 反映中斷擷取的邏輯電位  | 
| GPIO | 通用目的輸入輸出暫存器 (General Purpose Input/Output Register) 當 Port引腳 為輸入時,啟動內部上拉電阻連接 當 Port引腳 為輸出時,便會透過 Port引腳 輸出電位訊號  | 
| OLAT | 輸出鎖存暫存器 (Output Latch Register) 反映輸出鎖存的邏輯電位  | 
眾多指令中,唯一 IOCON 不需要區分 Port A 及 Port B
雖然有很多指令,但在下最常用主要只是 IODIR 及 GPIO
雖然有很多指令,但在下最常用主要只是 IODIR 及 GPIO
8位元模式
8位元模式 使用第4位元區分,低電位 為 Port A ,高電位 為 Port B
| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | Port A | Port B | 指令 | 
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | # | 0 | 0 | 0 | 0 | 0x00 | 0x10 | IODIR | 
| 0 | 0 | 0 | # | 0 | 0 | 0 | 1 | 0x01 | 0x11 | IPOL | 
| 0 | 0 | 0 | # | 0 | 0 | 1 | 0 | 0x02 | 0x12 | GPINTEN | 
| 0 | 0 | 0 | # | 0 | 0 | 1 | 1 | 0x03 | 0x13 | DEFVAL | 
| 0 | 0 | 0 | # | 0 | 1 | 0 | 0 | 0x04 | 0x14 | INTCON | 
| 0 | 0 | 0 | # | 0 | 1 | 0 | 1 | 0x05 | 0x15 | IOCON | 
| 0 | 0 | 0 | # | 0 | 1 | 1 | 0 | 0x06 | 0x16 | GPPU | 
| 0 | 0 | 0 | # | 0 | 1 | 1 | 1 | 0x07 | 0x17 | INTF | 
| 0 | 0 | 0 | # | 1 | 0 | 0 | 0 | 0x08 | 0x18 | INTCAP | 
| 0 | 0 | 0 | # | 1 | 0 | 0 | 1 | 0x09 | 0x19 | GPIO | 
| 0 | 0 | 0 | # | 1 | 0 | 1 | 0 | 0x0A | 0x1A | OLAT | 
16位元模式
16位元模式 使用第0位元區分,低電位 為 Port A ,高電位 為 Port B
| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | Port A | Port B | 指令 | 
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | # | 0x00 | 0x01 | IODIR | 
| 0 | 0 | 0 | 0 | 0 | 0 | 1 | # | 0x02 | 0x03 | IPOL | 
| 0 | 0 | 0 | 0 | 0 | 1 | 0 | # | 0x04 | 0x05 | GPINTEN | 
| 0 | 0 | 0 | 0 | 0 | 1 | 1 | # | 0x06 | 0x07 | DEFVAL | 
| 0 | 0 | 0 | 0 | 1 | 0 | 0 | # | 0x08 | 0x09 | INTCON | 
| 0 | 0 | 0 | 0 | 1 | 0 | 1 | # | 0x0A | 0x0B | IOCON | 
| 0 | 0 | 0 | 0 | 1 | 1 | 0 | # | 0x0C | 0x0D | GPPU | 
| 0 | 0 | 0 | 0 | 1 | 1 | 1 | # | 0x0E | 0x0F | INTF | 
| 0 | 0 | 0 | 1 | 0 | 0 | 0 | # | 0x10 | 0x11 | INTCAP | 
| 0 | 0 | 0 | 1 | 0 | 0 | 1 | # | 0x12 | 0x13 | GPIO | 
| 0 | 0 | 0 | 1 | 0 | 1 | 0 | # | 0x14 | 0x15 | OLAT | 
MCP23017 電路
電路原型
使用 MCP23017 來測試電路
測試效果
光度非常充足,即使 64格 LED 全亮著都有合理的光度
光度非常充足,即使 64格 LED 全亮著都有合理的光度
測試程式碼
#include <Wire.h>
byte address = 0x20;
void set(byte address, byte reg, byte data) {
    Wire.beginTransmission(address);
    Wire.write(reg);
    Wire.write(data);
    Wire.endTransmission();
}
void setup() {
    Wire.begin();
    set(address, 0x00, 0x00);
    set(address, 0x01, 0x00);
}
 
void loop() {
    for (byte r = 0; r < 8; r++) {
        // anodes
        set(address, 0x13, ~0x00);
        set(address, 0x12, 1 << r);
        for (byte c = 0; c < 8; c++) {
            // cathodes
            set(address, 0x13, ~(1 << c));
            delay(100);
        }
    }
}總結
2粒 PCF8574* 理論上與 1粒 MCP23017 同樣提供 16位元 輸入輸出
但 PCF8574* 比較佔據空間,共有32支引腳,亦需要較多線路接駁,還要保存兩組控制地址
不過 PCF8574* 成本則比較少,而且 PCF8574 很多模組板或測試板,使用上亦比較方便
而且 PCF8574* 的訊號及操作比較簡單
但 PCF8574* 比較佔據空間,共有32支引腳,亦需要較多線路接駁,還要保存兩組控制地址
不過 PCF8574* 成本則比較少,而且 PCF8574 很多模組板或測試板,使用上亦比較方便
而且 PCF8574* 的訊號及操作比較簡單
MCP23017 最高速度為 1.7Mhz ,而 PCF8574* 只有 100Khz ,快 17倍
而且只需要 8個地址,便可以擴展至 128位元,較少地址亦可以減少電路數量
另外還可以保持電壓穩定,對於控制輸出顯示等電子裝置效果更好
如果正式作為擴展器使用,在下建議使用 MCP23017
而且只需要 8個地址,便可以擴展至 128位元,較少地址亦可以減少電路數量
另外還可以保持電壓穩定,對於控制輸出顯示等電子裝置效果更好
如果正式作為擴展器使用,在下建議使用 MCP23017
沒有留言 :
張貼留言