推挽输出与开漏输出的本质区别:高电平由谁提供
2026/9/5 5:07:02 网站建设 项目流程

直接说结论:推挽输出和开漏输出最本质的区别,不在"能不能输出高电平",而在"谁来提供高电平"。推挽是芯片自己把引脚怼到VCC,开漏是芯片只负责把引脚拉到GND,高电平全靠外部上拉电阻从外面拉。这俩字之差,导致电流方向、驱动能力、速度、多路连接方式全都不一样。

这篇文章不拽术语,就用最直白的方式把这层窗户纸捅破,顺便把上拉电阻怎么选、OD门为什么能"线与"、51单片机P0口为什么特殊、什么时候开漏反而更好这些连带问题一次讲清。文章最后还有几个我实测踩过的坑,能帮你省不少事。

1. 先从物理结构拆起:两个管子怎么配合出高电平

1.1 推挽输出的内部结构:一个往上推,一个往下拉

推挽输出在英文里叫Push-Pull,翻译过来就是"推-拉"。为什么叫这个名字,看它内部的MOS管接法就明白了。

一个推挽输出引脚,芯片内部其实放了两个MOS管:

  • 上管(P-MOS或者高边管):连接在VCC和引脚之间,导通的时候把引脚往上"推"到VCC。
  • 下管(N-MOS或者低边管):连接在引脚和GND之间,导通的时候把引脚往下"拉"到GND。

这两个管子在工作时是严格互斥的:输出高电平的时候上管导通、下管截止,引脚直接通过一个很小的导通电阻连到VCC;输出低电平的时候下管导通、上管截止,引脚直接通到GND。

整个电路写出来就是这样:

VCC | [P-MOS] <- 上管,导通时引脚被拉到VCC | PIN ---- 输出 | [N-MOS] <- 下管,导通时引脚被拉到GND | GND

说白了这就是一个单刀双掷开关:要么接VCC,要么接GND,没有第三种状态。所以推挽输出天然就有极强的驱动能力——不管输出高还是低,引脚后面都跟着一个电源。

1.2 开漏输出的内部结构:只有一个"漏",另一头全是空气

开漏输出(Open-Drain)内部就简单多了,只有一个N-MOS管,它接在引脚和GND之间:

PIN ---- 输出 | [N-MOS] <- 导通时引脚被拉到GND | GND

注意,开漏输出的引脚没有内部上拉管,输出端直接就是MOS管的漏极,这就是"漏"字的来源。它只有两种状态:

  • 输出低电平:N-MOS导通,引脚被拉到GND。
  • 输出高电平:N-MOS截止,引脚既不接VCC也不接GND,处于高阻态(High-Z)

问题来了:引脚悬空的时候电压是多少?理论上是不确定的,实际测量可能是0.5V,可能是2V,还可能乱跳。所以开漏输出想输出高电平,必须在外部人为地加一个上拉电阻,连到VCC或者其他电压域。这跟推挽输出的"接到VCC"完全是两码事——推挽是芯片自己接,开漏是你在外面接。

1.3 把原理翻译成人话

用一个最容易理解的类比:推挽输出像家里的双控开关,灯要么接火线要么接零线,永远有明确的状态;开漏输出像你只装了一个地线开关,想亮灯还得自己从别处拉一根火线过来。

所以"单片机怎么输出高电平"这个问题,正确答案是:

  • 推挽输出:芯片内部帮你把VCC接上了,你不需要做任何事,引脚就能输出高电平。
  • 开漏输出:芯片本身没给你接VCC,你需要自己在上拉电阻的另一端接上VCC,高电平才会出现。

这个差别,就是整篇文章所有后续讨论的基础。

2. "高阻态"到底是个什么东西——开漏的灵魂

2.1 高阻不是0V也不是1,而是"插头拔了"

很多入门的朋友一听到"高阻态"就懵。其实高阻态最形象的比喻是:插头从插座里拔出来了

推挽输出永远是"插着的",要么插在VCC上,要么插在GND上。而开漏输出在输出"高电平"这个动作发生的瞬间,它实际上是把插头拔掉了,什么也不接。这时候引脚上的电压由谁决定?由外部电路决定——你外接的上拉电阻把它拉到高电平,高电平就出现了。

这个"拔掉"的状态极其关键,因为它是开漏输出一系列神奇能力的根源。

2.2 高阻状态下的电压:不是数学题,是物理题

有些人会纠结:既然MOS管截止了,高阻态引脚上的电压到底是几V?

答案取决于漏电流外部电路。如果引脚完全悬空(没有任何外部连接),由于芯片内部的ESD保护二极管、MOS管漏电流的影响,测出来的电压往往是"飘"的,你拿万用表量可能量出1.2V,拿示波器看可能噪声很大。这就是为什么开漏输出绝对不能悬空使用——它必须挂上拉电阻。

如果挂了上拉电阻,那电压就是上拉电阻另一端的电压。这也是开漏输出能做电平转换的原因:你上拉电阻接3.3V,高电平就是3.3V;上拉电阻接5V,高电平就是5V。输出高电平的电压完全由外部决定,芯片自己说了不算

2.3 开漏输出读取输入:一个容易踩的坑

这里我要插一句题外话,因为我见过太多人在这里踩坑。

开漏输出配置的引脚,如果你把它初始化成开漏输出模式,然后直接用GPIO_ReadInputDataBit去读引脚电平,会得到一个非常迷惑的结果。

为什么?因为在开漏输出模式下,输出锁存器里的值决定了N-MOS是否导通,而引脚电平又受到外部上拉电阻的影响。如果你输出0,N-MOS导通,引脚就是0V;你读回来是0,这是对的。但如果你输出1,N-MOS截止,引脚靠上拉电阻拉到高电平,你读回来是1——看起来也对,但这一切的前提是你外接了上拉电阻

如果没接上拉电阻,输出1的时候引脚是悬空的,你读回来的电平就是不确定的。我实测过,有的引脚会读到0,有的会读到1,还有的是个中间值。

更隐蔽的坑是:开漏输出模式下,读引脚之前必须先把输出寄存器置1(让管子截止),否则你根本读不到外部电路给的电平。你想想,如果输出寄存器是0,N-MOS一直导通,引脚被死死拉在地,外部给什么电平都白搭。这个我跟很多工程师确认过,大家都踩过。

3. 推挽和开漏,参数上的硬差距

3.1 一张表看懂核心差异

推挽输出和开漏输出的区别,用表来对照最直观:

对比维度推挽输出(Push-Pull)开漏输出(Open-Drain)
内部结构上管+下管,互斥导通只有下管,无上管
输出高电平电平来源芯片内部VCC外部上拉电阻的VCC
低电平驱动能力强(灌电流大)强(灌电流大)
高电平驱动能力强(拉电流大)差(由上拉电阻决定)
输出高电平时内部状态低阻抗,直接连VCC高阻态,引脚悬空
电压匹配/电平转换不支持(固定VCC)支持(可接任意电压域)
多路并联严禁直接并联可以并联(线与)
速度慢(受上拉电阻影响)
悬空状态不悬空悬空,必须外接上拉

这里我要重点解释两个容易被误解的点。

3.2 都说推挽驱动能力强,但"强"在高电平还是低电平?

很多人以为推挽输出驱动能力强,是高低电平都强。其实严格来说,推挽的高电平和低电平驱动能力都比开漏强,但低电平的"强"是两类输出共有的

  • 推挽输出高电平驱动:内部P-MOS直接接VCC,输出电流可以到几十mA(以STM32为例,GPIO输出电流典型值20mA左右),可以直接点亮LED、驱动小继电器(需要加二极管续流)。
  • 开漏输出高电平驱动:电流全靠外部的上拉电阻提供,电阻阻值越大电流越小。比如你用了10kΩ上拉拉5V,高电平电流只有(5-0.7)/10k≈0.43mA,连一个LED都点亮不了,只能用来传电平信号,不能用来带负载
  • 低电平驱动:两类输出都是N-MOS直接接地,所以灌电流都很强。这一点是大家最容易忽视的——开漏输出虽然"高电平弱",但"低电平一点都不弱"。

这就引出很多实际设计里的骚操作:用开漏输出直接驱动继电器或LED,让它输出低电平来点亮/吸合。比如LED阳极接VCC,阴极接单片机引脚,单片机输出0时LED亮。这种接法在开漏输出下完全没问题,因为低电平驱动能力强啊。

3.3 输出速度为什么开漏更慢,而且和上拉电阻直接相关

开漏输出早期的诟病之一就是速度慢。原因在于:

推挽输出切换时,引脚要么立即被强力拉到VCC,要么被强力拉到GND,电平跳变的速度不受外部元件限制。开漏输出切换时,从低到高的过程是:管子截止,外部上拉电阻开始给引脚上的寄生电容充电

这本质上是一个RC充电过程。引脚电容Cload(包括引脚寄生电容、PCB走线电容、负载电容)和上拉电阻Rup组成RC电路,时间常数τ=Rup×Cload。电阻越大,充电越慢,上升沿就越缓。比如上拉电阻10kΩ、负载电容20pF,τ=10k×20pF=200ns,这个上升时间对低速I2C没问题,但对几MHz的通信可能就不够了。

所以如果你用开漏输出做高速通信(比如I2C),在满足功耗前提下选尽量小的上拉电阻——2.2kΩ、1kΩ甚至330Ω都有人用。代价是电阻小,灌电流大,功耗高。这就是工程上一直在做的折中。

4. 为什么开漏输出能"线与"而推挽不能——一个著名的风险

4.1 "线与"实现原理:谁拉低谁负责,大家都能拉

"线与"(Wire-AND)是开漏输出最著名的应用,也是它"多路复用"能力的核心价值。

多个开漏输出的引脚,可以全部接到同一根线上,每个引脚只负责"拉低"这一个动作。因为是开漏结构,引脚在高电平时是高阻态,相当于"断开连接";在低电平时才把线拉低。这样一来,只要任何一个开漏输出为低,整条线就是低;只有所有开漏输出都为高阻态时,线上的电平才由上拉电阻决定为高。

写成逻辑式就是:线电平 = 所有输出的"与"(AND)。这就是"线与"这个名字的由来。

这个特性在总线上极其有用。I2C总线的SDA和SCL线,所有设备(主机、从机)的引脚都是开漏结构,任何一个设备拉低总线,其他设备都会感知到。仲裁、时钟同步、应答信号全部靠"线与"机制来实现。没有这个功能,I2C这种"一主多从"的协议根本没法跑。

4.2 推挽输出直接并联会烧芯片

如果推挽输出直接并联到同一根线上,会出什么事?我们分析一下:

假设两个推挽输出的引脚并联,引脚A输出高电平(内部接VCC),引脚B输出低电平(内部接GND),那么从A的VCC到B的GND之间,直接形成了通路。这条通路上只有两个MOS管的导通电阻(几欧姆到几十欧姆),电流I=(VCC-VGND)/(Ron_A+Ron_B)。3.3V供电、总电阻10Ω来算,电流就是330mA——远超芯片能承受的最大灌电流/拉电流。

结果就是:MOS管发热、电流过大、芯片损坏。轻则长期工作不稳定,重则当场冒烟。所以我一直跟人强调,推挽输出绝对不能直接并联。想并联也行,必须每个输出串一个隔离电阻(比如几百Ω),把短路电流限制在安全范围内——但这样就失去了推挽高速的优势,得不偿失。

4.3 不光单片机里用,集电极开路(OC)也是一回事

实际上开漏输出在更早的数字电路时代就有对应物:集电极开路(Open-Collector,OC)。区别只是实现器件不同,TTL电路里用三极管的集电极开路,CMOS电路里用MOS管的漏极开路。原理一模一样:输出管导通拉低,截止悬空,外部上拉决定高电平。

很多老工程师习惯说"OC门",其实放到CMOS时代就是"OD门"(Open-Drain),一回事。搞懂了开漏,再去读74LS06、74LS07这类OC门芯片的Datasheet,立刻就懂了。

5. 上拉电阻选多大的问题——这可能是你最常碰到的

5.1 决定上拉电阻阻值的四个因素

既然开漏输出必须配上拉电阻,那上拉电阻的大小到底怎么选?我从四个维度拆给你看,理解之后你就能自己算了,不用每次背公式。

  • 电平转换时间(速度):电阻越大,RC充电越慢,上升沿越缓。对高频通信(如I2C的400kHz甚至1MHz),上拉电阻不能太大。I2C规范里给了一个参考:标准模式100kHz建议5kΩ以内,快速模式400kHz建议2kΩ以内。
  • 功耗:电阻越小,当线路被拉低时,流过电阻的电流越大(I=VCC/R),功耗越高。总线长时间处于低电平时尤其明显。
  • 输入高电平阈值:电阻太大时,由于引脚漏电流的存在,实际高电平可能达不到芯片的VIH阈值。极端情况下引脚可能被干扰拉低,导致误判断。
  • 噪声抗扰:上拉电阻越小,线路阻抗越低,抗耦合噪声能力越强。

5.2 一个实际的计算示例

假设你做了个I2C总线,3.3V供电,总线上有3个设备,每个设备引脚电容5pF,PCB走线电容20pF,总负载电容大概35pF。要求最坏情况下上升时间不超过1μs(100kHz I2C的min要求是上升沿<1000ns)。

RC充电到0.9VCC的时间大约是2.2τ,所以τ < 1μs / 2.2 ≈ 454ns。由此 Rup = τ / C = 454ns / 35pF ≈ 13kΩ。这个电阻值看起来挺大的,实际中我通常不会选这么高,而是留出裕量选择4.7kΩ或2.2kΩ。

同时要算功耗:VCC=3.3V,R=2.2kΩ,线路被持续拉低时电流=3.3/2200=1.5mA,这个功耗完全可以接受。反过来如果你用330Ω,电流就是10mA,对电池供电就有点肉疼了。

所以我的经验法则是:

  • 低速通用信号/按键输入:10kΩ。
  • I2C 100kHz:4.7kΩ~10kΩ。
  • I2C 400kHz:2.2kΩ~4.7kΩ。
  • SPI这类高速信号:如果是开漏输出(很少见),直接选330Ω~1kΩ。
  • 驱动LED之类的负载:别抱太大期望,开漏高电平几乎带不动负载,需要另外接三极管或MOS管。

5.3 上拉电阻接到哪个电源电压,就决定了你的高电平是多少

开漏输出最有意思的一个应用场景就是电平转换:你可以把上拉电阻的另一端接到跟芯片不同的电压域,这样开漏输出的高电平就是那个电压域的值。

举个例子,你有个2.8V的传感器芯片要跟5V的单片机通信。传感器的开漏输出引脚不接到自己的VCC,而是通过一个4.7kΩ电阻上拉到5V。传感器输出低时,线被拉低到0V;传感器高阻时,线被5V上拉到5V。这样2.8V传感器就安全地跟5V单片机通信了,不会出现传感器引脚被反向电压打坏的问题。

这是开漏输出在混合电压系统里最经典的使用方式。如果你用推挽输出,两个电压域直接硬怼,轻则逻辑错误,重则烧芯片——因为推挽输出没有"兼容多种电压"这个说法,它输出高电平永远是自己的VCC,高电平可能超出对方允许的范围。

6. 51单片机P0口的"开漏"为什么让人又爱又恨

6.1 P0口内部根本就没接上拉:历史包袱

聊开漏输出,绕不过去的就是51单片机的P0口。很多人学51的时候都听过一句话:"P0口要加上拉电阻才能输出高电平。"但很少有人解释为什么。

原因得从51的祖宗——Intel 8051说起。在8051里,P0口是真正的开漏输出,内部没有上拉电阻。当时的设计意图是:P0可以用于总线扩展,当外部存储器访问时,P0口作为地址/数据复用总线,这时候需要的是快速的灌电流能力和"线与"能力,而不是推挽驱动能力。为了省芯片外部引脚数,Intel直接做成了开漏结构。

放到今天,P0口作为普通IO使用,如果你想让它输出高电平,就必须在外部给每个引脚加一个上拉电阻(常见4.7kΩ或10kΩ)。不加的话,P0输出1时候引脚悬空,电压不确定,接LED可能根本不亮。

6.2 其他三个口的区别你得知道

除了P0口,51单片机还有P1、P2、P3口。这几个口的内部结构跟P0不一样:**P1、P2、P3口内部自带一个上拉电阻**(准双向口,弱上拉)。它们的结构是:输出高电平时,内部上拉电阻把引脚拉高;输出低电平时,内部下拉强驱动把引脚拉低。

所以用P1口点LED,不需要外加电阻也能输出高电平。这个"准双向口"和"开漏口"的差别,是51系统设计里最容易忽略的点。我做51小板子的时候习惯每次画原理图前先确认P0口的上拉电阻有没有放进去,被坑过一次之后就形成了这个肌肉记忆。

6.3 STM32的GPIO模式:开漏和推挽是"配置",不是"硬件"限制

到了STM32这种32位单片机,GPIO的工作模式全都变成了软件可配置的:你可以自由切换推挽输出、开漏输出、浮空输入、上拉输入、下拉输入、模拟输入等等。

每次讲课到这儿我都会强调一点:STM32的开漏输出和51的P0口开漏输出不太一样。STM32的每个GPIO引脚内部其实可以配置一个弱上拉电阻(Pull-Up),你可以在开漏输出模式的同时使能内部上拉电阻,这样就不需要外部电阻了。

但注意:STM32内部上拉的阻值通常比较大(30~50kΩ左右),只能提供极小的拉电流,适合电平传输,不适合驱动负载。如果你要速度快的信号或要带LED,内部上拉远远不够,必须在外部另外加小阻值上拉。

配置上,用STM32标准库/LL库时,推挽和开漏的区别就一行代码:

// 推挽输出 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 开漏输出 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;

虽然切换只是一条配置,但硬件接线完全不同,这个在后面"复用输出"部分我会再详细说。

7. 什么时候必须用开漏,什么时候千万别用——应用场景全梳理

7.1 必须用开漏的地方

I2C总线。I2C协议规范本身就要求SDA和SCL必须是开漏结构,因为总线需要双向通信,且需要多个设备共享同一条线。你用推挽输出做I2C从机,主机拉低总线问你问题,你还是推挽往外打高电平,总线会短路。I2C的开漏上拉电阻选择前面已经讲了,4.7kΩ是万金油,400kHz高速的时候用2.2kΩ。

总线仲裁、多主机系统。多个设备共享一条状态线(比如中断线INT),任何设备都可以拉低这条线上报事件,主机查询时只要看这条线电平。这就是典型的"线与"应用,开漏结构天然合适。

电平转换。传感器输出、外部模块输出是开漏,你把它上拉到合适的电压域,完成电平匹配。这在混合电压系统里太常见了。

驱动需要高电压的外部器件。开漏输出引脚耐压通常可以高于VDD(具体看Datasheet的"OD脚耐压"参数),这意味着你可以用开漏输出去驱动8V甚至12V的外部电路(串电阻限流、或接上拉)。当然,高电压驱动大电流负载还是建议加三极管或MOS管,不要直接用GPIO引脚扛。

按键扫描、矩阵键盘。键盘扫描常配置成开漏输出,可以防止两路输出同时有效造成冲突。同时配合内部上拉读取输入电平,抗干扰性能更稳。

7.2 千万别用开漏的地方

需要高速、强驱动的信号线。比如SPI的MOSI、MISO、SCK,除非你是低速场景,否则不要开漏,直接用推挽。开漏信号的上升沿太慢,高速时波形拉跨。

点亮大多数LED。如果LED阳极接VCC、阴极接GPIO,你倒是可以用开漏输出0来点亮LED——这是可以的,因为低电平驱动强。但如果你的电路是LED阳极接GPIO、阴极接地(源极驱动),那用开漏几乎点不亮,因为高电平电流太小了。

直接驱动继电器、蜂鸣器等感性负载。不是说开漏不行,而是说GPIO输出电流有限,你无论如何都得通过外部驱动器件(三极管、MOS管)来实现,不能靠开漏自身的高电平去驱动。

7.3 一个实用判断口诀

我给你一个简单的判断方法,做设计时照着套:

  • 看协议:协议说了要开漏,那就老实开漏。I2C就是典型。
  • 看电压:两个模块电压域不一样,优先考虑开漏+外部上拉做电平转换。
  • 看是否共享:多个设备共用一根线,用开漏"线与"。
  • 看速度:追求高速,用推挽。
  • 看驱动:要带大电流负载,用推挽高电平(还得看GPIO灌/拉电流上限)。

8. 复用推挽输出 vs 复用开漏输出:功能模式下千万别配错

8.1 "复用"到底复用什么?

聊到STM32的时候,"复用推挽输出"和"复用开漏输出"这两个词出现频率极高。很多人一听"复用"就头大,其实一点都不复杂。

GPIO的"复用功能"指的是:这个引脚不再作为普通GPIO用,而是把它交给片内外设(USART、SPI、I2C、TIM、CAN等)来驱动。比如你配置PA9为USART1_TX,那PA9就不再是你手动用GPIO_WriteBit来控制,而是USART1外设自动控制它的电平。

"复用推挽"和"复用开漏"的区别,就是前面讲的推挽和开漏的区别,只不过控制者从你的代码变成了片内外设。

8.2 USART、SPI、I2C各该用哪个?

  • USART_TX:一般用复用推挽输出。因为USART是单端点对点通信,发送数据需要较强的驱动能力和较快的电平切换速度,推挽最合适。
  • USART_RX:这里是输入,所以配置成浮空输入或上拉输入即可,不是输出。
  • SPI_MOSI/SCK:推挽输出,理由同上。
  • I2C_SDA/SCL必须配置为复用开漏输出,同时使能内部上拉(或外部上拉)。因为I2C协议本质是线与结构,只有开漏才能保证多个设备通信不打架。
  • 定时器PWM输出:如果只是输出PWM到LED灯、舵机,用复用推挽;如果需要让PWM输出能够被多个设备共享(罕见),才考虑复用开漏。

最常见的新手错误是:I2C配置时用了推挽输出,结果通信不稳定,波形异常,查了半天才发现模式配错了。我在调试的时候习惯先用示波器抓信号,看到SCL/SDA线上有"台阶"一样的畸形波形,第一反应就是检查是不是GPIO模式配错了。

8.3 复用开漏时常犯的配置错误

讲一个我见过的典型错误案例:某工程师用STM32的I2C1驱动一个传感器,初始化代码里把SCL/SDA配成了复用推挽,而且没有使能上拉。结果现象是:传感器应答正常,但数据读取总是随机出错。用示波器看,SCL信号下降沿有回勾,SDA信号上升沿极慢。

排查过程:

  1. 换外部上拉4.7kΩ到3.3V,波形改善了一些但仍有问题。
  2. 检查I2C时序参数,计算上升沿时间,发现超过400kHz模式的限值。
  3. 回过头查GPIO配置,发现是复用推挽输出,而且内部上拉没开。

改成复用开漏输出、使能内部上拉后,波形立刻变得干净利落,问题解决。

这个案例说明了两点:第一,I2C必须开漏;第二,内部上拉和外部上拉可以共存,为了信号质量,很多设计干脆外部上拉+内部上拉一起用。

9. 实操笔记:上拉电阻的焊接、选型和调试经验

9.1 上拉电阻的封装和布局经验

开漏输出一定配外部上拉的情况下,PCB布局上注意几点:

  • 电阻尽量靠近接收端。原理上说,上拉电阻应该靠近"读取电平"那一端,这样能够更快地为寄生电容充电,减少噪声。
  • 走线不要过长过细。开漏输出的高电平本身就依赖外部上拉,走线越长,寄生电容越大,上升沿越差。
  • I2C总线走线要"星型"还是"菊花链"?实践中,菊花链比星型更不容易产生反射。星型连接会造成多条分支的电容并联,信号完整性差。我布线时一般让SDA/SCL顺序穿过每个设备的引脚,而不是从一点分叉。

9.2 手把手算一次I2C上拉电阻该怎么选

假设你有个传感器模块,I2C通信速率400kHz(Fast Mode),总线总电容估计为50pF(两条线分别算)。I2C规范要求Fast Mode下最大上升时间不超过300ns。

τ_max = 300ns / 2.2 ≈ 136ns

所需的最大上拉电阻:Rup_max = 136ns / 50pF = 2.72kΩ

再算最小上拉电阻:受到低电平灌电流限制,如果I2C引脚最大灌电流是3mA(需要看芯片手册,STM32一般是20mA),而低电平最大值VOL=0.4V,所以Rup_min = (VCC - VOL) / IOL_max = (3.3 - 0.4) / 0.003 ≈ 967Ω。

所以这个设计里,上拉电阻可以选择1kΩ~2.7kΩ之间,我一般取1.5kΩ或者2.2kΩ。还要注意总线总线上挂太多设备时,电容会更大,上拉要相应减小。如果总线电容达到100pF,那2.2kΩ的上升时间已经到484ns,超标了,只能选1kΩ。

9.3 万用表和示波器怎么判断引脚是不是开漏没配好

调试的时候,判断GPIO是不是开漏输出其实很简单:

  1. 用万用表测引脚对地电压——推挽输出高电平时电压=VCC,开漏输出未接上拉时电压会很低或有轻微漂移。
  2. 用示波器看波形——推挽输出的前后沿都很陡,开漏输出的上升沿明显更缓,而且上拉电阻越大越明显。
  3. 给引脚一个外部信号源拉低/拉高,读回来的电平是否符合预期——这个测试可以判断引脚是否真的是开漏结构。

9.4 内部上拉和外部上拉能不能同时用?

可以,而且很多场合就是这么干的。内部上拉(通常几十kΩ)可以保证引脚在空闲时有个确定的电平,避免浮空;外部上拉(几kΩ)负责保证信号速度。

但内部上拉+外部上拉并行时,等效电阻 = R内 × R外 / (R内 + R外),略小于外部上拉阻值。实际算上升时间按等效电阻算。同时,内部上拉+外部上拉同时用的缺点是,低电平时灌电流更大了,功耗略增。但一般都不明显,放心用。

10. 避坑清单:我踩过的那些开漏/推挽的坑

10.1 开漏输出没加上拉电阻,高电平"不存在"

这是最最最常见的问题。用开漏输出点LED,LED接在引脚和GND之间,结果死活不亮。检查半天发现,LED阳极接的是开漏引脚,但没加上拉电阻,输出1时引脚高阻,LED两端没有电压差,自然不亮。

正确接法是:LED阳极接VCC(或者接上拉到VCC),阴极接GPIO,输出0点亮。或者,开漏引脚通过一个电阻上拉到VCC,LED阳极接GPIO引脚。

10.2 开漏输出读取"自己输出的电平"会读错

前面讲过,开漏输出模式读引脚电平前,必须先保证输出寄存器是1(管子截止),才能读到外部电平。万一你写了0,引脚被死死拉低,外部上拉再强也没用。这个坑在写模拟I2C时序时极其容易踩。

10.3 推挽输出并联——绝对禁止

任何情况下都不要把两个推挽输出引脚直接短接在一起使用。输出高和输出低的两个推挽引脚一旦短路,电流直接灌穿芯片。有些人想通过"一个引脚输出高一个输出低"来制造某个电平,纯粹是作死。必须用开漏+线与,或者加隔离电阻。

10.4 "复用推挽"配置下I2C通信失败

这是我前面专门举过例子的坑。凡是I2C总线,必须用复用开漏输出模式。不少人把PCF8574这类I2C芯片的SCL/SDA配成了推挽,导致总线冲突。最典型的现象是——写操作能通,但一旦两个设备同时应答,总线电平就乱了。

10.5 上拉电阻选的太大,导致I2C高速时波形上升沿不合格

很多人图省事一律用10kΩ上拉,结果I2C跑到400kHz时,总线波形严重“圆角”,时序检测不过关。我调试时的做法是:先用2.2kΩ跑400kHz,如果发现上升沿还是有点慢,再降到1kΩ。当然具体还要看总线电容。记住一个原则:在功耗允许的范围内,上拉电阻能小尽量小

10.6 开漏输出做电平转换时,忘了检查耐压

开漏输出引脚虽然耐压通常比普通推挽高,但也不是无限耐压。比如某单片机的GPIO最大耐压是5.5V,你上拉到12V,照样烧引脚。设计时必须看Datasheet里的“Absolute Maximum Ratings”,确认引脚的耐压值。

10.7 开漏输出驱动MOS管的栅极,栅极电荷太大导致开关慢

有的朋友拿开漏输出直接驱动MOS管栅极,想实现电平转换/开关控制。开漏输出高电平时是上拉电阻,而MOS管栅极有结电容,上拉电阻给栅极充电很慢,导致MOS管开关迟缓、发热。更合理的方案是:用推挽输出直接驱动,或者用专门的栅极驱动芯片;如果只能用开漏输出,就选小一点的上拉电阻(但功耗和速度的trade-off你自己衡量)。

11. 几个实用的实验操作,帮你建立直觉

11.1 实验一:同一块板,推挽/开漏各点一次LED

拿一块STM32F103C8T6最小系统板做实验。PA0接LED阳极(LED阴极串一个220Ω电阻后接GND),PA1接LED阳极(同样串220Ω电阻)。

  • PA0配置为推挽输出,烧录程序让它输出高电平:LED正常点亮。
  • PA1配置为开漏输出,烧录程序让它输出高电平:LED几乎不亮,但如果你在PA1外部加一个4.7kΩ电阻上拉到3.3V,LED又能亮了,但是亮度仍然比推挽弱。

这个实验最直观地说明了"高电平的来源"差别:推挽自己给力,开漏完全指望外部。

11.2 实验二:开漏输出+上拉电阻做逻辑电平转换

准备一个5V上拉的I2C设备(比如PCF8574模块),把它的SCL/SDA接在STM32的PB6/PB7上,同时PB6/PB7配置为复用开漏输出,外部各接一个4.7kΩ电阻上拉到5V。

用逻辑分析仪观察总线波形,你会看到:STM32输出低电平,总线是0V;STM32输出高电平(高阻),总线是5V。也就是说,3.3V的STM32安全地驱动了5V的总线,没有烧任何引脚。这个实验做一遍,你对"开漏输出做电平转换"的理解就会牢不可破。

11.3 实验三:两条开漏输出并联一个按键

选两个GPIO都配置为开漏输出,外部同时接一个4.7kΩ上拉。正常情况下,两条线独立控制。然后把它们用跳线帽短接。分别让GPIO1输出0、GPIO2输出1,观察公共线上的电平:仍然是0。这就说明了"线与"——只要任何一个输出为低,总线就是低。再把两个都输出1(高阻),公共线被上拉电阻拉到高电平。这就是I2C总线仲裁的基本原理。

12. 面试必问的进阶理解:从波形看本质

最后再从波形角度聊聊推挽和开漏。很多面试官喜欢问"看这张波形图,这是推挽还是开漏",其实看三个特征:

  • 上升沿:推挽输出的上升沿陡峭,几乎垂直;开漏输出的上升沿缓慢,呈RC充电曲线。
  • 下降沿:两类输出的下降沿都陡峭,因为都是N-MOS主动拉低。
  • 高电平值:推挽的高电平=VDD;开漏的高电平=上拉电压源值,可能不是VDD。

如果波形上升沿像"台阶"一样,一级一级地爬上去,大概率是开漏输出悬空、没有上拉电阻,寄生电容在跟你的万用表/示波器探头做斗争。这时候赶紧补上拉电阻,波形立刻正常。

再看一个进阶问题:推挽输出和开漏输出,哪个更省电?答案得分开说:输出高电平时,推挽没有静态功耗(MOS管导通电阻极小,无电流流过),开漏高电平时上拉电阻有电流流过(I=VCC/R),有静态功耗;输出低电平时,推挽和开漏都有电流从外部负载灌入,功耗取决于负载。所以单从"引脚自身功耗"角度,推挽输出在输出高电平时几乎不耗电,这也是推挽低功耗应用受欢迎的原因之一。

但这个"省电"结论要小心:如果总线长期处于低电平状态,开漏输出的上拉电阻几乎不耗电(因为电流走的是MOS管,外部上拉两端电压一样),推挽输出此时却有灌电流(如果有外部负载拉低)。所以具体功耗要结合外部电路算,不能一概而论。

13. 我的个人经验总结

说一千道一万,搞懂推挽和开漏,最核心的抓手就是那一句话:推挽的高电平靠芯片内部,开漏的高电平靠外部上拉。掌握了这个,后面所有的应用场景、选型思路、坑点,都是从这个根上演化出来的。

实际项目里怎么选?我的习惯是:

  1. 默认用推挽输出——大多数普通LED控制、继电器驱动(通过三极管)、数字信号输出,推挽都够用且简单。
  2. 遇到I2C、共享总线、电平转换、总线仲裁,无条件切到开漏——协议要求或者物理结构要求,没得商量。
  3. 开漏必配上拉电阻——能选内部上拉先选内部上拉(节省外部元件),但注意内部上拉阻值大、驱动能力弱,信号速度要求高的场景必须外接小电阻上拉。
  4. 推挽输出绝不直接并联——这是物理红线。
  5. 开漏模式下读引脚前先把输出寄存器写1——这是无数人踩过的坑,包括我自己。

最后再送一个小技巧:如果你手头没有示波器,只有万用表,怎么快速判断一个GPIO被配成了开漏还是推挽?拿个1kΩ电阻一头接3.3V,一头去碰那个引脚。如果引脚输出高电平且内部是推挽,万用表量到电压依然是3.3V左右(推挽内部有强驱动,可以顶住这个外部负载);如果配置成开漏且没上拉,你碰上去之后电压会从3.3V跌落到一个较低值(外部电阻成为分压器)。这个土办法我用了很多年,判断GPIO模式百试百灵。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询