I2C GPIO 扩展器 PCF8574:准双向 IO、读改写与中断输出
更新时间:2026-09-19。前置:I2C 主机设计、GPIO 去抖与中断。MCU 引脚不够时,用一颗 I2C 转 8 路 IO 的扩展器即可加按键、LED、片选;PCF8574 是最常见的一种,但它的端口模型和普通 GPIO 很不一样。
本文要回答的问题
- PCF8574 为什么没有「方向寄存器」,准双向是什么意思?
- 为什么读引脚前必须先写 1,驱动一个输入要注意什么?
- INT 中断脚在什么条件下触发/清除?
- 读-改-写、上电态和强驱动外部信号有哪些坑?
一、芯片与地址
PCF8574/8574A(8 位 I²C 通用并行 I/O):
- 8 个端口 P0~P7,I2C 控制,标准/快速模式(100k/400k)。
- 7 位从机地址由固定前缀 + 3 个地址引脚 A2/A1/A0 决定(8574 与 8574A 前缀不同,共可挂多颗),地址引脚通常直接接 VCC/GND。
- 一个独立的 INT(开漏、低有效) 输出,可接 MCU 外部中断,输入变化时拉低。
- 端口内部有弱上拉(约 100μA 级),上电/复位后默认全为 1(输入态)。
二、核心:准双向端口,不是普通 GPIO
普通 MCU 的 GPIO 有明确方向寄存器(DDR):先配输入/输出,再读写。PCF8574 没有方向寄存器,每个引脚是准双向(quasi-bidirectional)开漏式端口:
- 向某脚写 1:释放强下拉,引脚被内部弱上拉拉高,同时该脚可作为输入被读(高阻+弱上拉)。
- 向某脚写 0:内部强下拉导通,引脚被拉低作输出低。
- 它没有主动输出高电平的强驱动(高电平来自弱上拉/外部上拉),所以:
- 适合直接灌电流点亮 LED(拉低导通)、驱动低有效片选;
- 拉高只能提供很小电流,驱动负载要靠外部上拉。
一句话:写 0 = 强低输出;写 1 = 释放(高电平/输入)。读写协议上,主机发从地址+写时是设置输出值;发从地址+读时是读当前引脚电平。
三、读操作的「先写 1」与读-改-写
要把某脚当输入,必须保证对应输出锁存位是 1(释放强下拉)。如果之前写过 0,内部下拉还导通,读回来永远是 0。因此输入初始化要先写 0xFF(或对应位置 1)。
混合使用(部分位输出、部分位输入)时,改一个输出位要做读-改-写,否则会误伤输入脚:
想只把 P0 拉低、其余保持:
1) 读当前端口(确认输入位状态/当前锁存)
2) value = (current & ~BIT0) // 只改 P0,输入对应位保留 1
3) 写 value
错误做法: 直接写 0x00 → 把所有输入位也强拉低,无法读输入注意 I2C 上「读 PCF8574」读到的是引脚实际电平(不是上次写的锁存值):当某脚写 1 又被外部拉低,读到 0;这正是检测按键的原理(按键把弱上拉拉低)。
四、INT 中断输出
- 当端口配置为输入(相应位写 1)时,任何引脚电平相对上次读操作发生变化都会把 INT 拉低。
- 清除条件:INT 在一次对该芯片的读或写传输(SCL 上升沿/ACK 前后,数据手册定义的时刻)后清除,恢复高电平;之后若再有变化再次拉低。
- 因此典型用法:按键变化触发 INT → MCU 在 ISR 里读一次 PCF8574(既读键值又清除 INT)。
- INT 不锁定具体是哪位变化,要软件读后和上次快照比较找出变化位。
- 由于 INT 在读写时清,如果变化发生在读取与处理之间,可能合并/错过边沿——它是「电平相对上次读」比较,不是边沿锁存;按键仍需去抖(见 GPIO 去抖)。
五、典型用法与系统考虑
- 输出(LED/片选):写 0 拉低;复位后全 1,注意上电默认高,对低有效器件可能要在启动时尽快配置。
- 输入(按键/状态):先全写 1 释放,读端口;用 INT 通知;弱上拉可省外部上拉但速度慢,高速/长走线建议加上拉电阻以加快上升沿。
- 作为从机挂在同一条 I2C 总线,要遵守 I2C 地址、时钟拉伸/仲裁;多个扩展器用 A2/A1/A0 区分。
- 端口电平跟随芯片 VCC(如 3.3V),不能直接承受 5V 输入,跨电平要外部处理(见 ESD/IO)。
六、常见的坑
- 当普通 GPIO 找方向寄存器:PCF8574 没有 DDR,靠写 1/0 释放/强拉。
- 输入前不写 1:该位还被强下拉,读回恒 0。
- 直接写整字节覆盖输入位:改输出时把输入位也写成 0,输入失效;必须读-改-写并保留输入位为 1。
- 指望强高电平驱动:高电平只有弱上拉,带不动负载;拉高驱动需外部上拉,驱动 LED 用灌电流(低有效)。
- 读的是锁存值还是引脚分不清:读到的是引脚实际电平,外部可改变它。
- INT 当边沿锁存:它是「相对上次读的电平变化」标志,读/写即清,不告诉你具体位、可能合并变化,要软件比对+去抖。
- 上电默认全 1 没处理:复位瞬间所有脚为高,对低有效使能的器件可能误动作,要在启动早期配置或加外部默认态。
- INT 开漏忘接上拉:INT 是开漏输出,要上拉电阻,MCU 才能看到高电平。
- 弱上拉导致边沿慢:长走线/大电容下上升沿慢,读入错误或 I2C 外的中断延迟,加外部上拉。
- 5V 信号直连:端口非 5V 容忍时被 5V 灌电/损坏。
- 地址冲突:多颗扩展器 A2/A1/A0 设重,地址冲突(见 I2C 地址规划)。
- 总线挂起未恢复:扩展器在时钟拉伸/异常时若 SDA 被拉低,主机需总线恢复(发时钟脉冲/STOP,见 I2C 主机)。
相关与延伸
I2C 物理与协议见 I2C 主机设计;输入去抖/中断模型见 GPIO 去抖与同步、引脚复用;中断汇聚见 事件路由;电平与保护见 ESD/IO。
总结
PCF8574 是没有方向寄存器的 I2C 8 位 GPIO 扩展器,每个引脚是「写 0 强下拉、写 1 释放并由弱上拉拉高、此时可作输入」的准双向开漏端口,且高电平只有弱驱动、适合灌电流;上电默认全 1,把某脚当输入前必须确保对应位写 1,混合输入输出时改一个输出位要用读-改-写保留输入位,读到的是引脚实际电平而非输出锁存值;开漏 INT 在输入电平相对上次读发生变化时拉低、在任意读写后清除且不标记具体位,软件需读后与快照比对并去抖——把它当带 DDR 的普通 GPIO、输入不先写 1、整字节写覆盖输入位和把 INT 当边沿锁存是四大常见坑。