资讯动态

推挽输出与开漏输出到底有什么区别?从原理到实测一次讲透

发布时间:2026/9/8 14:48:57 来源:尧图企业网站定制
先问一个很实在的问题你第一次用51单片机点亮LED的时候是不是也疑惑过为什么P0口要外接一排上拉电阻而P1口不用然后到了STM32又发现GPIO配置里有什么推挽输出、开漏输出、浮空输入、上拉输入看数据手册看得头晕。等你实际焊板子调程序又踩过这种坑引脚明明写1了万用表量出来却不是高电平或者两个引脚连在一起一高一低直接冒烟。这些问题的根源全都指向同一个知识点——推挽输出和开漏输出的本质区别。这篇文章我想把这个话题一次讲透。不堆术语把内部结构拆开看用实测波形说话顺便把我这几年在51、STM32、各种传感器模块上调IO口踩过的坑一并交代清楚。无论你是刚学会点灯的新手还是已经能跑FreeRTOS的老手只要你偶尔还会被GPIO的电气特性搞得措手不及这篇都值得花十分钟看完。1. 入坑第一课为什么同一个LED别人接VCC我接GND也能亮在拆推挽和开漏之前必须先解决一个更基础的问题单片机引脚到底是怎么“输出”电平的很多人学IO口的时候只记结论——写1输出高电平写0输出低电平——但从来没想过这个“高电平”“低电平”在引脚内部是怎么变出来的。1.1 从最小系统玩起引脚内部到底藏着什么单片机引脚内部并不是一根导线直通芯片核心而是通过一个“输出驱动器”再连到引脚上的。这个驱动器本质上就是开关电路最常见的实现是MOS管。你可以把引脚内部想象成一个双刀开关面板一个开关负责把引脚接到VCC上去另一个开关负责把引脚接到GND上去。当你写P1_0 1的时候芯片内部的逻辑电路会控制上面那个开关闭合引脚就被接到了VCC外部测量就是高电平。当你写P1_0 0的时候下面那个开关闭合引脚被接到GND外部测量就是低电平。这个模型虽然粗糙但足够解释90%的现象。推挽输出和开漏输出的差异恰恰就出在这两个开关的“存在与否”和“工作方式”上。1.2 灌电流和拉电流工程师口中的“吸”和“灌”在继续之前还要先搞懂两个整天听老师傅挂在嘴边的词拉电流和灌电流。拉电流引脚向外输出电流。比如用引脚直接驱动LED电流从引脚流出经过LED流到GND。这时候引脚是在“拉”着电流往外送叫拉电流source current。灌电流电流从外部流进引脚。比如LED正极接VCC负极接引脚当引脚输出低电平时电流从VCC经过LED流入引脚再通过内部开关流到GND。这时候引脚是在“灌”收电流叫灌电流sink current。不理解这两个概念后面讲推挽和开漏的驱动能力会一头雾水。你可以把引脚想象成一个水龙头拉电流就是水龙头往外放水灌电流就是水龙头当排水口往里吸水。2. 推挽输出既推得动也拉得回的全能选手推挽输出英文叫Push-Pull。名字已经说得很直白一个负责推Push一个负责挽Pull拉。这对应内部的两个开关上桥开关和下桥开关。2.1 内部结构拆解PMOS和NMOS各司其职推挽输出内部有两个MOS管上面是PMOS下面是NMOS。它们两个是互补的——一个导通时另一个必然截止。当引脚输出高电平时PMOS导通NMOS截止引脚直接通过PMOS接到VCC。因为PMOS导通后的导通电阻很小通常只有几十欧姆甚至更低所以引脚电压非常接近VCC驱动能力很强。当引脚输出低电平时PMOS截止NMOS导通引脚通过NMOS接到GND。同样因为NMOS导通电阻小引脚电压非常接近0V。理解这个结构之后推挽输出有两个关键特性就很好理解了第一高电平和低电平都是“主动”驱动的。输出高时是直接连到VCC输出低时是直接连到GND中间不存在“悬空”状态。所以推挽输出的波形上升沿和下降沿都很陡翻转速度快。第二推挽输出不能把多个引脚直接并联。如果两个推挽输出引脚接到同一个节点一个输出高、一个输出低那相当于一个开关把节点接到VCC另一个开关把节点接到GND这俩开关同时闭合结果就是直接短路轻则发热、重则烧引脚。后面我会专门讲这个坑。2.2 为什么推挽很适合驱动LED、蜂鸣器这类负载拿LED举例。假设VCC是5VLED压降2V你想让电流控制在5mA左右。用推挽输出直接驱动计算限流电阻R (5V - 2V) / 0.005A 600Ω实际取一个常见的620Ω或680Ω就行。电流大概在4.4到5mA之间LED亮度合适引脚电流也远低于51单片机的最大灌电流/拉电流能力。这里要提一个很多人忽略的细节51单片机的P1、P2、P3口是“准双向口”内部结构其实更接近“弱上拉强下拉”。也就是说输出高电平时它内部不是像推挽输出那样直接通过低阻抗的PMOS接到VCC而是通过一个阻值较大的上拉电阻接到VCC。这个电阻通常有几十千欧所以驱动能力很弱。你用P1口直接点LED会发现LED比较暗原因就是高电平的驱动电流太小。而P0口更特殊内部连上拉电阻都没有也就是纯粹的开漏结构后面细说。这也是很多教程推荐“LED负极接引脚正极接VCC”的原因让引脚工作在灌电流模式。51单片机的灌电流能力比拉电流强不少实测灌20mA跟玩一样但拉电流可能也就几百微安到毫安级别带不动LED。这个规律在STM32上有所不同STM32推挽输出的拉电流和灌电流能力是对称的都能到25mA左右但51的老架构确实不是这个水平。2.3 推挽也不是万能输出脚对着干会烧我早年做小项目时干过一件事两个单片机的IO口直接用导线连起来做通信没有串任何电阻结果一个输出高一个输出低板子当场冒烟。后来才知道两个推挽输出的引脚直接对接本质上就是上面说的“开关短路”电流可以达到几百毫安甚至安培级。所以推挽输出用得爽但要记住它很“刚”不适合多设备共享一根信号线总线结构电平转换时不方便直接接不同电压的系统更忌讳两个输出互相怼这时候就需要另一个东西登场——开漏输出。3. 开漏输出那个“只能拉低”的尴尬与灵活开漏输出英文Open-Drain。这个名字起得特别形象。漏就是MOS管的漏极Drain。开漏的意思就是这个漏极“开”着的没有接到任何地方。3.1 名字里就藏着答案漏极是开着的开漏输出内部只有一个NMOS管这个管子连接在引脚和GND之间。栅极由内部逻辑控制。输出低电平时NMOS导通引脚被拉到GND输出低电平。输出高电平时NMOS截止引脚什么都不接处于高阻态Hi-Z。没错高阻态。开漏输出本身根本不能主动输出高电平。你写1它只是把内部的NMOS关断引脚悬空在那里。外部如果没有任何其他电路去拉高引脚上的电压就是不确定的可能受漏电流、寄生电容、电磁干扰影响飘来飘去。这就是为什么开漏输出必须外接一个上拉电阻到VCC。只有加上这个电阻当NMOS关断时引脚才会通过电阻被拉到高电平。NMOS导通时引脚被拉到低电平电流经过上拉电阻流进NMOS再到GND。所以开漏输出的高电平本质上不是“推”出来的而是“让”出来的。让内部管子截止再由外部电阻去完成拉高动作。3.2 上拉电阻怎么选阻值大小影响功耗和速度开漏输出最核心的设计决策就是上拉电阻阻值。电阻太大比如100kΩ高电平时电流很小功耗确实低但是引脚本身的寄生电容和外部负载电容充电会很慢导致上升沿很缓波形像一条斜线。在高速通信场景下这会直接导致时序错误。电阻太小比如100Ω上升沿确实陡了但低电平时的灌电流会很大。假设VCC是5V流过100Ω电阻的电流就是5V/100Ω 50mA远超单片机IO口承受能力NMOS也受不了。实际工程经验普通电平输出、低速信号几kHz到几十kHz用10kΩ比较稳妥I2C这种400kHz、1MHz的通信常用2.2kΩ到4.7kΩ高速信号或者总线电容较大的场景1kΩ到2.2kΩ给你个大概的感觉用示波器看1kΩ上拉的I2C时钟线上升沿干净利落换成10kΩ上拉同样的总线上升沿明显变圆滑。低速场景无所谓高速场景就得认真算。上拉电阻的计算公式很好理解R_max t_rise / (0.8473 × C_bus)其中t_rise是允许的最大上升时间C_bus是总线总电容。这个式子来自RC充电曲线的推导0.8473是充到63.2%和10%之间那段的时间系数。实际设计时不用算得这么精确但要清楚电阻越大速度越低。3.3 开漏的高光应用I2C、电平转换、线与开漏输出看起来又弱又麻烦为什么还被广泛应用因为它有两个推挽输出给不了的大招。第一电平转换。一个3.3V的单片机要和一个5V的传感器通信。如果都用推挽输出3.3V输出高电平只有3.3V5V设备可能识别不了5V设备输出高电平5V又可能烧坏3.3V引脚。用开漏就简单了两边都配置成开漏输出外部上拉电阻接到5V。3.3V单片机需要输出高电平时NMOS截止总线被5V上拉拉高5V设备收到高电平。需要输出低电平时NMOS导通总线被拉低两边都收到低电平。完美实现双向电平匹配。第二线与逻辑和多主机总线。因为开漏输出在高电平时是高阻态多个开漏输出可以直接并连到同一条总线上。任何一个设备输出低电平总线就是低电平所有设备都不输出低电平时总线才被上拉到高电平。这就是“线与”Wire-AND逻辑。I2C总线是典型的例子。一条时钟线SCL一条数据线SDA上面可以挂十几个设备大家都不传输数据时所有设备的输出都是高阻态总线靠上拉电阻保持高电平。任何设备要开始通信先把SDA拉低这就是起始条件。这种“谁都别抢谁抢到算谁的”的机制推挽输出想做都做不了。还有一点想特别提醒开漏输出的“线与”特性在51单片机的P0口也能看到。P0口输出高电平靠的就是内部没有上拉多个P0口引脚配合其他IO口可以直接构成矩阵键盘扫描、数码管位选这种电路拉低有效不会打架。4. “最本质的区别”到底是什么主动驱动与被动释放标题问的是“最本质的区别”前面铺垫了这么多现在可以正面回答了。4.1 一句话版本和高电平的“责任归属”推挽输出和开漏输出的本质区别不是“一个能输出高电平一个不能”而是高电平的责任归属不同推挽输出高电平由引脚内部主动驱动PMOS直接把引脚怼到VCC。引脚说“我要高”它就是高谁也别想拦着。开漏输出高电平由外部上拉电阻被动拉高内部只负责“放”或“收”。引脚说“我要高”它只是把内部的NMOS放开真正把电平抬起来的是外面的电阻。一句话总结推挽是主动给电开漏是主动放电、被动给电。这个区别带来的连锁反应就是前面讲的各种工程特性差异我整理成了一张表对比维度推挽输出开漏输出高电平驱动方式内部PMOS主动连接VCC外部上拉电阻被动拉高输出低电平NMOS主动连接GNDNMOS主动连接GND高电平驱动能力很强低阻抗直连很弱取决于上拉电阻上升沿速度很快微秒级甚至纳秒级受RC充电限制可能较慢能否并联多个输出绝对不能会短路可以线与逻辑能否直接电平转换不行电平固定很灵活上拉电阻接目标电平未接上拉电阻时写1正常输出高电平引脚悬空电压不确定典型应用驱动LED、蜂鸣器、继电器经三极管I2C、电平转换、总线共享4.2 用波形说话上升沿的差距一眼看清有一次我在调试一块板子用STM32的PB6做软件I2C配置成了推挽输出结果跟一个从设备怎么都对不上时序。后来查资料才发现标准I2C要求SDA和SCL必须是开漏或集电极开路结构这样多个主机才能工作。我赶紧把GPIO改成开漏输出模式加了个4.7kΩ上拉立刻就好了。后来我用示波器对比了一下两种配置在同一个引脚上的上升沿推挽输出写1之后电平瞬间跳到3.3V上升沿几乎看不到过程示波器上是一条垂直线。开漏输出加4.7kΩ上拉写1之后电平先有一个短暂的低电平保持然后呈RC充电曲线缓慢爬升大约几个微秒后到达3.3V。别小看这个上升沿差异。如果总线上挂着多个设备每个设备输入引脚都有寄生电容加上PCB走线电容总共可能几百皮法甚至几纳法。上拉电阻一大的话上升沿就会拖得很长导致信号还没稳定就被采样了通信就出错。这也是为什么硬件工程师总强调“高速信号上拉电阻别用太大”。电平能不能准时到比电平最终到没到往往更重要。4.3 什么场景用推挽什么场景用开漏根据我的经验选型逻辑其实很清晰需要驱动大负载、想快速翻转、对电平有明确要求且不共享引脚——选推挽。比如驱动LED加限流电阻驱动无源蜂鸣器经三极管驱动MOS管栅极普通LED流水灯、数码管段选多设备共享总线、需要电平转换、要做线与逻辑——选开漏。比如I2C的SDA和SCL1-Wire总线如DS18B20多个按键共享一个中断引脚线与3.3V MCU和5V外设通信但是现实世界往往不是非黑即白。比如STM32的I2C引脚硬件上就是开漏结构需要外加上拉。很多人第一次用STM32的硬件I2C会发现怎么都调不通因为忘了外接上拉电阻。而51单片机的P0口虽然内部是真的开漏但你在做并行总线扩展时必须外接上拉才能输出高电平否则片选、数据线全都不工作。另外一个容易被忽视的场景如果开漏输出控制的是LED那LED的接法要注意。因为高电平是上拉电阻拉上去的电流很小如果你把LED接在引脚和GND之间想用高电平点亮那LED会很暗甚至不亮。正确做法是把LED接在VCC和引脚之间让引脚拉低时LED才亮。很多人第一次用开漏输出驱动LED都栽在这个接法上。5. 拿万用表和示波器做一次实测眼见为实讲了这么多理论和模型最后还是要动手验证一遍。我把当年调板的两个实验完整记录下来你可以照着做。5.1 实验一不加上拉电阻的开漏输出测出来是什么拿一个51单片机最小系统板用P0.0引脚写程序让P0.0输出高电平。注意P0口内部没有任何上拉电阻这是51特殊的地方。同时拿一个P1.0做对照P1.0内部有上拉。把万用表打到直流电压档红表笔接引脚黑表笔接GND测P1.0显示接近5V稳定纹波几乎没有。测P0.0显示的数值会在0V到3V之间飘忽不定有时候甚至测出1.2V左右。如果你用手碰一下引脚读数还会变化。这就是高阻态的典型表现。引脚没有主动驱动也没有上拉电阻给它一个确定的电平。你看到的漂移其实是周围电磁环境和万用表内阻共同作用的结果。然后我在P0.0外部接一个10kΩ电阻到VCC再测读数变成了接近5V稳定了。这证明高电平确实是上拉电阻“拉”出来的。5.2 实验二上拉电阻从小到大波形变化全过程后来我用STM32重新做了一次实验配置成开漏输出模式用信号发生器驱动一个方波频率100kHz分别换上1kΩ、4.7kΩ、10kΩ、47kΩ的上拉电阻示波器观察上升沿1kΩ上升沿大约50ns基本可以接受但低电平灌电流约3.3mA功耗稍大 4.7kΩ上升沿约150ns日常I2C完全够用 10kΩ上升沿约300ns低速可以高速就危险了 47kΩ上升沿超过1.5μs波形特别圆滑只能用在几十kHz以下的场景这个实验很好地说明了为什么I2C标准规范里会给出上拉电阻的取值范围就是要在功耗和速度之间找平衡。如果你的总线上挂了很多设备电容增大同样的上拉电阻上升沿会明显变慢这时要么减小电阻要么降低通信速率。5.3 记录几个容易踩的坑实测过程中有几个现象你们八成也会遇到第一万用表测出来“高电平”只有1V多不一定是引脚坏了可能是开漏没加上拉也可能是驱动能力不够被外部负载拉低了。第二开漏输出写0时外部上拉电阻上的电流全部流过NMOS如果上拉电阻选得太小长时间低电平引脚会发热。我见过有人用100Ω上拉跑I2C结果晶振旁边那颗芯片摸上去烫手。第三STC单片机和很多国产MCU的IO口有“准双向口”模式这个模式和开漏略有不同准双向口内部有一个弱上拉写1时能勉强拉高但驱动能力很弱。很多人测准双向口输出的高电平发现带个LED就被拉低到2V以下就是这个原因。不要和纯开漏混为一谈。6. 分享几个我自己调板子时的实用心法写到最后把我这几年实际调GPIO的经验集中整理一下有些是常规教程不会写但实际项目经常用到的。6.1 三板斧排查法遇到IO口电平不对我一般按这个顺序排查第一确认模式配置。STM32要查GPIO初始化结构体是GPIO_Mode_Out_PP推挽还是GPIO_Mode_Out_OD开漏。51单片机要看是哪个口P0要外加上拉。第二确认外部电路。开漏输出查上拉电阻有没有焊、阻值对不对推挽输出查有没有跟其他推挽输出引脚短接或者是不是驱动了太重负载。第三用万用表测引脚对GND的电阻。如果发现近似0Ω大概率是内部或外部短路。如果发现几百欧可能是有负载或者拉电流过大。这套流程看起来简单但真的能解决80%的IO问题。6.2 从51换到STM32之后的一些认知升级很多从51转到STM32的人会有一个不适应51的P1口直接写1就能输出高电平但到了STM32为什么有的引脚上电后是高电平有的不是因为STM32的GPIO模式太多了复位后默认是浮空输入引脚既不是高也不是低外部不接上下拉的话电压不定。这时候你要主动选择“推挽输出”并且确认引脚有没有被复用成其他外设。比如PA9、PA10默认可能是USART1的TX、RX你非要拿来做普通GPIO推挽输出就必须先重映射或者关闭复用功能否则你写1引脚状态还是被外设控制测出来死活不对。还有一种情况STM32的某些引脚是开漏复用比如I2C的SCL、SDA你在初始化时配置成GPIO_Mode_AF_OD复用开漏。如果配成了GPIO_Mode_AF_PP复用推挽连I2C设备的时候也可能能工作但会破坏多主机兼容性而且万一总线上另一个设备拉低你这边的推挽还在使劲拉高就会出现大电流。标准库的例程一般不会写错但自己从零配置时容易忽略。6.3 给新手的建议先看懂芯片手册再抄例程我见过太多人一开始就照着教程抄代码能点亮LED就以为自己会了。等到自己画板子、选芯片、接传感器一遇到开漏和推挽的选择就抓瞎。如果你真想在硬件这条路上走远一点建议你把芯片手册里GPIO那一章的“输出驱动能力”“最大灌电流/拉电流”“开漏/推挽结构图”翻出来看几遍。STC的和STM32的手册都写得很清楚配上内部结构图比任何博客都直观。看到一个引脚先问三个问题这个引脚复用功能是什么我现在要它输出高电平还是低电平如果我选开漏上拉电阻接了吗什么阻值这三个问题想清楚就不会再犯“P0口忘记加上拉”“I2C速度上不去”“两个推挽脚互怼烧板子”这类经典错误。说实话推挽和开漏的知识点单独拎出来每一个都不难难的是在真实的电路里快速判断用哪一种。我自己也是被烧过、被漂移过的电平坑过几次之后才真正把这两个概念内化成直觉。希望这篇文章能帮你少走这些弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价