2. I2C接口GPIO扩展芯片详解:PCF8574/PCF8575原理、地址配置与读写时序
好,咱们进入正题。上一章聊了为什么需要GPIO扩展,这一章咱们直接看芯片——PCF8574和PCF8575。这两颗芯片,可以说是I2C GPIO扩展领域的「老兵」了。我入行那会儿,它们就已经在市场上站稳了脚跟,直到现在,很多工业产品和消费电子里依然能看到它们的身影。
说白了,它们干的事很简单:用两根线(I2C总线)换回8个或16个GPIO口。但你别小看这个功能,在引脚紧张的MCU项目里,这简直就是救星。
2.1 PCF8574与PCF8575的核心区别
先看个表格,一目了然:
| 参数 | PCF8574 | PCF8575 |
|---|---|---|
| GPIO数量 | 8位(P0~P7) | 16位(P0~P15) |
| 封装 | SO-16 / DIP-16 | SO-24 / SSOP-24 |
| I2C地址范围 | 0x20 ~ 0x27(3位地址线) | 0x20 ~ 0x27(3位地址线) |
| 最大挂载数量 | 8片 | 8片 |
| 输出驱动能力 | 推挽/开漏,25mA灌电流 | 推挽/开漏,25mA灌电流 |
| 中断输出 | 有(INT引脚) | 有(INT引脚) |
嗯,这里要注意:PCF8574是8位的,PCF8575是16位的。如果你只需要扩展几个按键或者LED,8574就够了。但如果你要驱动一个16x2的字符液晶,或者同时控制一堆继电器,那8575会更合适。
我个人习惯是:能用8574就不上8575。为什么?因为8574的封装更小,布线更简单,而且8位IO在大多数场景下已经够用了。多出来的8个口,很多时候反而是浪费PCB面积。
2.2 地址配置:别让地址冲突坑了你
I2C总线上每个设备必须有唯一的地址。PCF8574/8575的地址由两部分组成:
- 固定部分:高4位,固定为
0100(即0x4) - 可配置部分:低3位,由A0、A1、A2引脚的电平决定
所以完整的地址格式是:0100 A2 A1 A0,范围从 0100 000(0x20)到 0100 111(0x27)。
举个例子:
- A0接GND,A1接GND,A2接GND → 地址 0x20
- A0接VCC,A1接GND,A2接GND → 地址 0x21
- A0接GND,A1接VCC,A2接VCC → 地址 0x26
另外,PCF8574和PCF8575的地址范围完全一样。如果你在一条I2C总线上同时使用这两种芯片,要注意地址不能重复。比如你用了0x20的8574,就不能再用0x20的8575了。
2.3 读写时序:I2C通信的核心
PCF8574/8575的I2C时序其实很简单,但有几个细节容易出错。咱们一个一个说。
2.3.1 写操作(输出)
写操作就是MCU向芯片的IO口输出电平。时序如下:
- 发送起始条件(START)
- 发送设备地址 + 写位(0x40 | 地址 << 1)
- 等待从机应答(ACK)
- 发送数据字节(要输出的IO状态)
- 等待从机应答(ACK)
- 发送停止条件(STOP)
代码示例(基于STM32 HAL库):
// 向PCF8574写入一个字节
// addr: 芯片地址(0x20~0x27)
// data: 要输出的数据,bit0对应P0,bit7对应P7
HAL_StatusTypeDef PCF8574_Write(uint8_t addr, uint8_t data)
{
return HAL_I2C_Master_Transmit(&hi2c1, addr << 1, &data, 1, 100);
}
你看,就这么简单。但有个坑:PCF8574的IO口在复位后默认是高电平。如果你要驱动LED,记得把LED的阴极接IO口,阳极通过电阻接VCC。这样IO输出低电平时LED亮,输出高电平时LED灭。我刚开始做的时候没注意这个,直接把LED阳极接IO口了,结果上电瞬间所有LED都亮了,吓我一跳。
2.3.2 读操作(输入)
读操作稍微复杂一点,因为PCF8574的IO口是准双向的。什么意思?就是说,你要先写一个高电平到某个引脚,然后才能把它当输入用。
时序如下:
- 发送起始条件(START)
- 发送设备地址 + 读位(0x40 | 地址 << 1 | 0x01)
- 等待从机应答(ACK)
- 读取数据字节(从机发送,主机应答)
- 发送非应答(NACK)
- 发送停止条件(STOP)
代码示例:
// 从PCF8574读取一个字节
// addr: 芯片地址(0x20~0x27)
// 返回值: 读取到的IO状态
uint8_t PCF8574_Read(uint8_t addr)
{
uint8_t data = 0;
HAL_I2C_Master_Receive(&hi2c1, (addr << 1) | 0x01, &data, 1, 100);
return data;
}
2.4 中断功能:别让CPU空转
PCF8574/8575有一个INT引脚,当输入引脚状态发生变化时,INT会输出低电平。这个功能在按键检测中特别有用。
你想想看,如果没有中断,你就得不停地轮询IO口,CPU啥也干不了。有了中断,CPU可以安心睡大觉,等按键按下时再被唤醒。
使用中断的步骤:
- 将INT引脚连接到MCU的外部中断引脚
- 配置MCU的外部中断为下降沿触发
- 在中断服务函数中读取PCF8574的IO状态
2.5 实际项目中的选型建议
最后,给几个实际建议:
- 按键扫描:用PCF8574,8个口可以接8个按键,配合中断,效率很高
- LED控制:如果只是控制几个指示灯,8574够用;如果要控制数码管或者点阵,建议上8575
- 多片级联:一条I2C总线上最多挂8片,总共64个IO口(8574)或128个IO口(8575)。但要注意总线电容,距离长了要加I2C中继器
- 电平匹配:PCF8574/8575的工作电压是2.5V~5.5V,但I2C总线电平要和MCU匹配。如果MCU是3.3V,芯片是5V,最好加电平转换
嗯,这一章的内容差不多就这些。PCF8574和PCF8575虽然老,但胜在稳定、便宜、资料多。下一章咱们会实际动手,写一个完整的驱动代码,包括初始化、读写、中断处理,到时候你就知道怎么用了。