## 为什么需要 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 瓶颈!