嵌入式 IO 扩展实战:I2C PCF8574 扩展 8 路 IO 的完整指南
👁 9 阅读 · 2026-08-21 · 嵌入式 IO
在嵌入式开发中,MCU 的 GPIO 资源常常捉襟见肘,而 I2C 总线只需两根线即可扩展出 8 路 IO,PCF8574 正是这类器件的经典代表。本文从工作原理、硬件连接、驱动代码到实际踩坑,全面解析如何用 PCF8574 实现 IO 扩展,帮助你在资源受限的嵌入式项目中轻松突破引脚限制。
## 为什么需要 IO 扩展?
嵌入式开发中,MCU 的 GPIO 数量往往受限于封装和成本,尤其是在驱动多个 LED、按键、继电器或读取拨码开关时,引脚资源瞬间告急。I2C 总线仅需 SDA 和 SCL 两根线,即可挂载多个外设,而 PCF8574 作为 I2C 转 8 位准双向 IO 的经典芯片,成为嵌入式 IO 扩展的首选方案。
## PCF8574 核心原理
PCF8574 内部包含一个 I2C 从机接口、一个 8 位准双向 IO 端口(P0~P7)以及一个输出锁存器。其工作模式如下:
- **输出模式**:向器件写入一个字节,该字节被锁存到输出端口,驱动外部负载(如 LED、继电器)。
- **输入模式**:先向器件写入 0xFF(使所有引脚为高电平),然后读取端口,即可获得外部电平状态(如按键按下为低电平)。
- **准双向特性**:每个引脚内部有上拉电阻,输出高电平时可驱动微弱负载,输出低电平时可吸收较大电流(如灌电流驱动 LED)。
**I2C 地址**:PCF8574 的地址由 A0~A2 引脚决定,默认地址为 0x20(若 A0~A2 均接地)。地址格式为 `0100 A2 A1 A0`,因此可挂载 8 个器件,扩展 64 路 IO。
## 硬件连接
以 STM32F103 为例,连接如下:
- **VCC** → 3.3V(或 5V,注意电平匹配)
- **GND** → GND
- **SDA** → PB7(I2C1 数据线)
- **SCL** → PB6(I2C1 时钟线)
- **A0~A2** → GND(地址 0x20)
- **P0~P7** → 外设(如 LED 串联 220Ω 电阻到 VCC,或按键一端接 GND)
注意:若 MCU 为 3.3V,PCF8574 可工作于 2.5~6V,但 I2C 上拉电阻需接至 MCU 的 VCC,防止电平冲突。
## 驱动代码实现(以 STM32 HAL 库为例)
### 1. I2C 初始化
使用 STM32CubeMX 配置 I2C1,速率 100kHz(标准模式),然后生成代码。
### 2. PCF8574 基本读写函数
```c
#include "i2c.h"
#define PCF8574_ADDR 0x20 // 默认地址,注意左移一位为 0x40
// 写 8 位数据到 PCF8574
void PCF8574_Write(uint8_t data) {
HAL_I2C_Master_Transmit(&hi2c1, (PCF8574_ADDR << 1) | 0, &data, 1, 100);
}
// 从 PCF8574 读取 8 位数据
uint8_t PCF8574_Read(void) {
uint8_t data = 0;
HAL_I2C_Master_Receive(&hi2c1, (PCF8574_ADDR << 1) | 1, &data, 1, 100);
return data;
}
// 设置某一位输出高/低电平
void PCF8574_SetPin(uint8_t pin, uint8_t level) {
static uint8_t current = 0xFF; // 保存当前输出状态
if (level) {
current |= (1 << pin);
} else {
current &= ~(1 << pin);
}
PCF8574_Write(current);
}
```
### 3. 应用示例:控制 LED 和读取按键
```c
// 初始化:所有引脚输出高电平(LED 熄灭,因为 LED 接 VCC,低电平点亮)
void PCF8574_Init(void) {
PCF8574_Write(0xFF);
}
// 点亮 P0 上的 LED(低电平有效)
void LED_On(void) {
PCF8574_SetPin(0, 0);
}
// 读取 P4 上的按键(按下为低电平)
uint8_t Key_Read(void) {
uint8_t val = PCF8574_Read();
return (val & (1 << 4)) ? 1 : 0; // 返回 1 表示未按下,0 表示按下
}
// 主循环示例
void main_loop(void) {
PCF8574_Init();
while (1) {
if (Key_Read() == 0) {
LED_On();
} else {
PCF8574_SetPin(0, 1); // 熄灭
}
HAL_Delay(10);
}
}
```
## 注意事项与常见坑
- **地址左移**:HAL 库的 `HAL_I2C_Master_Transmit` 需要 8 位地址,其中最低位为读写位,因此必须将 7 位地址左移一位。例如 0x20 左移后为 0x40(写),0x41(读)。
- **准双向 IO 的输入模式**:读取前必须先写 0xFF,否则引脚可能输出低电平,导致读到的电平不准确。
- **上拉电阻**:PCF8574 内部有弱上拉(约 100μA),但驱动 LED 时建议使用灌电流方式(LED 接 VCC,引脚输出低电平点亮),避免高电平驱动能力不足。
- **电平匹配**:若 MCU 为 5V,PCF8574 可直接供电 5V;若 MCU 为 3.3V,建议 PCF8574 也使用 3.3V,并确保 I2C 上拉电阻接至 3.3V。
- **速度限制**:I2C 标准模式 100kHz 下,切换 IO 的速率有限,不适合高频 PWM 信号,但用于按键、LED 等低速场景绰绰有余。
- **多器件扩展**:通过 A0~A2 可挂载多个 PCF8574,但需确保每个地址唯一,且 I2C 总线长度和电容符合规范。
## 总结
PCF8574 是嵌入式 IO 扩展的经典方案,仅需两根线即可获得 8 路 IO,且代码简单、成本低廉。通过本文的驱动示例,你可以快速集成到自己的项目中。记住关键点:地址左移、输入前写 1、灌电流驱动,即可避免大部分问题。希望这篇指南能帮你轻松突破 IO 瓶颈!