下面这个动画把 GPIO 的两种输出级画成了可交互的电路图:左边是输出级的真实结构(高侧 MOS、低侧 MOS、GPIO 节点、负载和上拉电阻),右边是同一时刻节点电压的跳变波形。切换模式、输入电平和上拉电阻三个开关,就能直观看到「谁在拉高、谁在拉低」到底有什么区别。
如何操作 GPIO 输出模式动画
动画一共有三个控制按钮和一个速度滑块,都在页面顶部:
- 输出模式切换:在 Push-Pull(推挽)与 Open-Drain(开漏)之间切换,电路图、波形和数据结论会整套跟着变。
- 输入电平:在 HIGH 与 LOW 之间翻转,对应软件里写 1 或写 0。
- 上拉电阻:在 ON 与 OFF 之间开关,专门用来看开漏输出释放之后到底发生什么。
- 动画速度:从 0.5× 到 2.0×,慢放可以看清电流路径的走向,快放适合看波形。
画面的读法如下:
- 左上是电路图。橙色是电源轨 VCC 和外部上拉电阻,蓝色高亮的是当前导通的电流路径,灰色是接地回路。元件包括高侧 MOS、低侧 MOS、GPIO 节点、负载 LED、电阻 Rpull-up 以及最左侧的输入信号。
- 右上是波形图。GPIO 节点电压在 VCC、二分之一 VCC 与 0 V 三条网格线之间跳变,橙色的虚线表示上拉电阻的动作轨迹。
- 左下是一句话结论。推挽模式下写着「主动拉高+主动拉低」,开漏模式下写着「只能主动拉低,释放后靠上拉」。
- 右下三个数据格依次是当前节点电压、电流路径的称呼,以及总线并联时的结论(推挽是「不允许硬碰硬」,开漏是「可安全线与」)。
把上拉电阻关掉再切到开漏模式,状态栏会显示「释放 / 浮空」,电压那一格也会变成「未定义」——这就是开漏输出最需要小心的地方。
关于推挽输出与开漏输出
这两个名字都从电路结构上来,而不是从功能上来。
「推」和「拉」说的是两个方向
推挽输出级内部有两个 MOS 管串联在电源和地之间。上面的管子导通时,电流从电源经管子流到引脚,相当于把电平「推」出去;下面的管子导通时,电流从引脚流回地,相当于把电平「拉」下来。两个管子互补工作,所以推挽输出既能主动输出高电平,也能主动输出低电平,不需要任何外部元件帮忙。
正因为能自己抬、自己拽,推挽的驱动能力很强,边沿也干净。它在约 3.3 V 的系统中,高电平时节点电压接近 3.3 V,低电平时接近 0 V,中间的过渡时间很短。
开漏只有一个管子,所以只能拉低
开漏输出级只保留了下面那个 MOS 管。它导通时把引脚拉到地,这是它能主动做的事;它关闭时引脚既没有上管也没有上拉电阻,处于高阻态(浮空),电平由外部电路决定。
这就是「释放」这个说法的由来:写 1 并不是输出高电平,而是把管子关掉、把引脚释放出来。此时如果板子上有一个外部上拉电阻,引脚就会被拉到 VCC;如果没有,引脚就悬空,电平不确定,容易误触发。动画里把上拉关掉后显示「未定义」,模拟的就是这个状态。
带上拉之后,代价是上升沿变慢
开漏释放时,抬升电平的任务交给上拉电阻和线路本身的分布电容,二者构成一个 RC 回路。上升过程按指数曲线走,时间常数约等于电阻值与电容值的乘积。电阻选得越小,上升越快,但静态功耗越大——低电平时电阻上会持续消耗电流,这一点在电池供电的产品里要特别算进去。
下降沿则不受影响,因为开漏管是主动把电平拽到地的,拉低永远比抬高快。这形成一个不太对称的波形:下降沿陡峭,上升沿拖尾。I²C 这类总线对上升时间有明确上限要求,选型时就必须按总线速率反推上拉电阻的阻值。
开漏真正的价值是「线与」
把多个开漏输出直接连到同一根线上,再加上一个共用的上拉电阻,会得到一种很安全的逻辑:任何一个器件拉低,整条线就是低;所有器件都释放,整条线才被上拉成高。这种关系在数字逻辑里叫线与(wired-AND)。
I²C 总线的 SDA 和 SCL 就是这么做的。总线上挂多少个器件都行,器件之间不需要互相避让,因为没人能主动输出高电平去和别人对撞。这根线同时也兼作仲裁用:多个主机同时发数据时,谁先拉低谁就赢得总线。
推挽为什么不能直接并联
推挽输出如果直接并联,两个器件一个推高、一个拉低时,等于在电源和地之间形成了一条低阻通路,电流会不受控地涌过两个管子。轻则功耗飙升、边沿变形,重则烧毁 IO 口。所以推挽输出只能一对一使用,不能共享同一根线。
相比之下,开漏输出在并联时对撞不会发生,代价是速度受限。这就是两种模式的核心取舍:推挽求速度,开漏求共享。
实际选型怎么定
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| 驱动 LED、继电器、蜂鸣器 | 推挽 | 需要强驱动与快速边沿,无需共享总线 |
| I²C、1-Wire 等共享总线 | 开漏 | 天然支持线与,多器件可安全共线 |
| 电平转换的中间级 | 开漏 | 配合上拉可适配不同电压域 |
| 长线传输、抗干扰要求高 | 开漏 | 释放态由上拉决定,不易出现总线冲突 |
| 单片机的普通 IO 复用 | 推挽 | 默认输出能力强,调试最简单 |
一个常见的坑是:驱动 LED 时习惯性用推挽,但把 IO 初始化成开漏却忘了接上拉电阻,结果电平永远上不去。反过来,用在 I²C 引脚上却配成了推挽,总线大概率根本跑不起来。所以切换输出模式时,先确认架上有没有上拉电阻,再决定用哪种模式。
