尧图精选

推挽输出与开漏输出详解:原理、区别及单片机实战选型

🕒 发布时间:2026/9/7 11:12:18 📁 来源:尧图网络
先问个直击灵魂的问题你在学习单片机的时候是不是已经背住了“推挽输出能输出高电平和低电平开漏输出只能输出低电平想输出高电平得接上拉电阻”这句话但一到实际项目里就懵了尤其是当你想用开漏输出驱动一个LED或者去读一个按键电平的时候会发现“明明配置对了为什么还是不行”。这真的太常见了。作为一个折腾过51、STM32、GD32也踩过无数次“推挽和开漏没分清”的坑的嵌入式工程师我今天就一次性把这两个模式讲透。不跟你绕弯子直接扒到MOS管的内部结构再用实际波形和项目场景告诉你到底怎么选、怎么配、怎么排查问题。这篇文章既适合刚入门的小白也适合那些“会用但说不清原理”的老手看完你会觉得以前很多配置操作其实都是在“背答案”而不是真正理解。1. 从引脚内部结构说起单片机是怎么“输出”电平的1.1 先搞清楚一个基本问题单片机引脚凭什么能输出高电平和低电平很多初学者会想当然地认为单片机的引脚就是一个简单的“电源输出端”好像里面有一根线直接连着3.3V或者GND。实际上没那么简单。引脚的电平变化靠的是芯片内部一颗颗微型的“电子开关”来控制的这些开关在CMOS工艺里就是MOS管。你可以把MOS管理解成一个水龙头给它的“栅极”G施加一定的电压它就会在“源极”S和“漏极”D之间形成一条通路让电流流过去。控制MOS管通断的速度极快每秒可以开关几百万次甚至上亿次单片机正是靠这种高速开关来输出各种电平信号、PWM波形的。CMOS电路里有两类互补的MOS管一类是N-MOS通常是当控制电压为高电平时导通电流能从漏极流向源极也就是“低端导通”另一类是P-MOS与之相反控制电压为低电平时导通电流能从源极流向漏极相当于“高端导通”。理解这两类管子是理解推挽和开漏的基础。1.2 引脚驱动电路的两种经典结构围绕“如何同时具备拉高和拉低能力”这个问题芯片设计人员想出了不同的电路结构于是就有了推挽输出和开漏输出。推挽输出Push-Pull对应英文里的“推”和“挽”两个动作。它在一个引脚内部同时放了两个MOS管上面一个P-MOS负责“推”把电平往上顶到VCC下面一个N-MOS负责“挽”把电平往下拉到GND。两个管子轮流工作一个导通时另一个截止。开漏输出Open-Drain直译过来是“漏极开路”。它只在引脚内部放了一个N-MOS这个N-MOS的源极接到GND漏极直接引出到引脚。也就是说内部只有一个“往下拉”的开关没有任何主动往上推的管子。于是这个引脚天生就只有两种状态要么内部N-MOS导通引脚被拉低到GND要么N-MOS截止引脚就相当于“悬空”了对外呈现高阻态。正因为这样开漏输出才需要外部接一个上拉电阻才能在N-MOS截止时把电平拉高到指定电压。提示如果是“开集输出”Open-Collector那是双极型三极管时代的叫法原理类似只是用的是三极管。现在CMOS单片机里统称开漏输出。2. 推挽输出为什么绝大多数场景下它是“默认首选”2.1 推挽输出到底怎么工作的推挽输出的内部原理可以想象成两个接力运动员。要输出高电平时上面的P-MOS导通直接把引脚连到VCC此时引脚电压接近VCC同时还具备较强的“拉电流”能力也就是电流从引脚往外面流驱动外部负载要输出低电平时下面的N-MOS导通把引脚连到GND引脚电压接近0V同时具备较强的“灌电流”能力也就是外部电流能流进引脚。这个过程中最关键的“为什么推挽输出能输出高电平”的答案就藏在P-MOS上。它可以让引脚主动地、快速地、强驱动地拉高到电源电压。无论是推还是拉都是“主动”行为不需要外部挂任何电阻。我用STM32F103的GPIO输出做个例子配置为推挽输出引脚悬空测量输出高电平时电压是3.3V输出低电平时电压是0V驱动LED、蜂鸣器、继电器加续流和驱动电路的情况下都非常顺畅。尤其是你要驱动多个LED或者需要一定驱动能力时推挽输出的优势很明显。2.2 推挽输出的优势和使用边界推挽输出的优势有三点第一输出电平“界限分明”高就是接近VCC低就是接近GND中间没有模糊区抗干扰能力强。第二因为是主动驱动所以翻转速度可以做得很快适合输出PWM、通信时钟等高频信号。第三输出阻抗低带负载能力强不用额外加上拉电阻电路简洁。那推挽输出有没有坑当然有。第一个坑是推挽输出不能直接“线与”。如果你把两个单片机引脚都配置为推挽输出然后把它们短接在一起一个输出高、一个输出低那就等于直接把芯片的VCC和GND短接了瞬间电流可能非常大轻则信号乱掉重则烧毁IO口。哪怕软件上你保证不会让两个引脚方向冲突但只要一个配置错误风险就很高。第二个坑是推挽输出拉高后对外输出的电平是固定的——内部VCC。但有些场景希望引脚输出高电平时电平能跟外部设备匹配比如外设是5V而单片机是3.3V或者总线上需要多个设备共享一根线。这时候推挽输出就不合适了。所以虽然大多数GPIO都首选推挽但在某些总线和混合电压场景下必须用开漏。3. 开漏输出看似“残缺”却是很多场景的“唯一解”3.1 开漏输出的工作机制只能拉低不能主动拉高开漏输出因为内部只有一个N-MOS所以本质上是“单向下拉”的结构。当内部寄存器的值写0时N-MOS导通引脚被拉低这个时候引脚是真正的低电平当内部寄存器的值写1时N-MOS截止引脚和内部电路完全断开引脚对外呈现高阻态。这个时候如果你直接用万用表去量引脚电压会发现电压是很奇怪的可能是0V可能是几伏也可能在乱跳因为它就是一个悬空节点。你不给它一个确定的外接上拉电阻它自己根本定不下来是“高”还是“低”。这又牵扯出一个重要的点开漏输出不是不能“输出高电平”靠的是外部电路拉高而不是单片机内部拉高。我打个比方推挽输出像是一个“双向开关”既能向左边倒拉低也能向右边倒拉高而开漏输出只有一个“往下拉的按钮”你要让电平变高就得靠外界在上方拴一个弹簧上拉电阻把它拉回高电位。3.2 上拉电阻的取值4.7k还是10k怎么选开漏输出基本都离不开外部上拉电阻这个电阻的取值是有讲究的。从电平角度说上拉电阻一端接电源VCC另一端接到IO引脚。当开漏输出为高阻态时电阻会把引脚电压拉到VCC实现高电平输出。上拉电阻阻值越小拉高能力越强但同时引脚低电平时电阻上的电流越大阻值小灌入电流大功耗越高。上拉电阻阻值越大好处是省电、低电平时电流小但问题是拉高速度变慢因为引脚对地有一定的寄生电容RC充电时间常数为R×C阻值越大从低电平跳到高电平需要的上升时间越长。如果通信速率高上升沿太缓信号可能会因为达不到接收端的阈值而通信错乱。实际选型中低速信号比如按键检测、普通标志位常用10kI2C总线标准模式100kbps常用4.7k左右高速模式400kbps有时会用2.2k或者1k来加快上升沿。板子功耗比较敏感尽量选大一点高速场景选小一点。其实我调试的时候会先挂一个10k电阻看波形如果上升沿太慢再往小了换比如4.7k、2.2k麻烦是麻烦点但比自己拍脑袋稳。3.3 开漏输出的三大经典应用场景为什么结构上“残缺”的开漏输出反而不可或缺因为它解决了三个推挽做不到的问题。场景一I2C总线。I2C协议规定SDA和SCL两条线都必须是开漏结构加上拉电阻原因很简单I2C支持一主多从、多主机仲裁多设备可能同时在总线上拉低信号。如果所有设备都用推挽输出去拉高一旦两个设备一个想拉高一个想拉低就会发生电源短路。而开漏模式下任意设备想发低电平就拉低总线想发高电平就“放手”让上拉电阻去拉高谁也不会跟谁硬碰硬实现自然仲裁。这也叫“线与”逻辑。场景二电平转换。开漏输出加不同电压值的上拉电阻就能实现不同电平之间的转换。比如单片机是3.3V系统外部传感器是5V系统。你把单片机的IO配置为开漏输出上拉电阻接5V电源那么单片机输出低电平时引脚是0V输出高电平NMOS截止时引脚被上拉到5V。这样3.3V单片机就能安全地向5V设备输出信号避免了推挽输出直接输出3.3V驱动5V设备时可能产生的逻辑不匹配问题。场景三多设备共享中断线。比如多个I2C设备都会拉低同一个INT引脚来上报事件这时这根线就必须用开漏/集电极开路结构。任何一个设备都能拉低它没有设备拉低时由外部上拉电阻保持高电平。如果用推挽输出A设备和B设备同时拉高/拉低就会打架信号根本没法用。4. 两者的本质区别以及实际项目里怎么选4.1 最本质的区别有没有“主动拉高”的能力如果要一句话总结推挽和开漏最本质的区别就是推挽输出内部有能主动拉高到VCC的P-MOS管因此既能主动输出高电平又能主动输出低电平而开漏输出内部只有能拉低的N-MOS管输出高电平必须依靠外部上拉电阻。也就是说开漏不能“主动”输出高只能“被动”被拉高。这导致两者在其他方面的一系列连锁差异我给你列个对照表对比项推挽输出开漏输出高电平能力主动拉高到VCC靠外部上拉电阻拉高低电平能力主动拉低到GND主动拉低到GND高电平电压固定等于VCC可随上拉电源变化能不能线与不能会短路可以天然支持驱动能力强可拉可灌拉低能力强拉高取决于上拉电阻典型应用LED、蜂鸣器、PWM、普通信号I2C、电平转换、中断共享线4.2 实际选型什么时候闭眼用推挽什么时候必须开漏现实中我总结了一套“三问法”每次配置引脚前心里过一遍基本不会出错。第一问你的信号是不是挂在总线上可能被多个设备同时驱动如果是例如I2C、1-Wire、共享中断线你没有任何选择余地只能开漏或者外接开漏电路加合适的上拉电阻。第二问输出高电平时目标设备的逻辑电平是否和单片机VCC一致如果一致推挽就行如果不一致特别是跨电压域输出优先开漏加对应电压的上拉电阻。第三问是否需要快速翻转和强驱动如果是要输出PWM波或者去直接驱动LED那推挽输出是首选。尤其是PWM开漏模式下由于上拉电阻和寄生电容的存在上升沿会比推挽慢很多高频PWM下波形会失真驱动负载能力也弱。我见过不少同学在I2C实验时图省事把SCL和SDA配成推挽输出结果短距离单设备通信也能跑但一旦接多个从设备或者通信距离拉长就会随机死机报错。这不是运气问题是结构就错了。4.3 开漏输出使用中最容易犯的错先说我踩过的一个坑开漏输出模式下忘了加上拉电阻然后还拿万用表去量引脚。结果高电平时引脚电压只有0.3V左右因为万用表内阻在某种情况下影响了浮动节点一度以为芯片烧了。后来反应过来不是芯片的问题是引脚悬空了。当时真是又想笑又想骂人。常见错误还有两个。一个是开漏输出的“上拉电压”接错了。比如我要做3.3V到5V的电平转换上拉电阻的电源应该接5V但如果误接了3.3V那输出高电平就还是3.3V达不到5V设备的高电平阈值后面设备一样识别不了。另一个是开漏输出在高速率使用时上拉电阻选太大。比如I2C用10k电阻跑400kbps上升沿明显变慢波形像个梯形甚至直接通信失败。这属于硬件设计问题不是代码问题。排查起来还挺隐蔽。注意开漏输出不是“不能输出高电平”而是“不能主动输出高电平”。这句话建议抄在本子上理解透了比背一堆模式定义有用得多。5. 单片机的IO模式到底怎么配置实操记录与波形对比5.1 51单片机的准双向口其实它是“开漏内部上拉”的混合体如果你是从51单片机入门的会发现一个问题书上说51的P1口是“准双向IO”可以直接输出高电平驱动LED不需要外接上拉电阻但内部结构又不是推挽输出它到底算什么实际上传统的8051单片机IO口内部是一个N-MOS管同时内部集成了一只上拉电阻常见阻值约几十到几百千欧很弱。从结构上看它更像“开漏输出内部弱上拉”的组合。它输出高电平时也是靠内部微弱的上拉电阻拉高的并不是像STM32推挽那样有主动拉高能力的P-MOS管。所以51单片机的IO口高电平驱动能力很弱灌电流能力相对强一些点亮LED常采用“低电平点亮”的接法即LED一端接VCC另一端接IO口IO口输出低电平形成灌电流回路。这个结构带来的还有读引脚的外设“锁存器”问题。用51单片机读外部按键时如果先把引脚输出高电平锁存器写1然后才能读到外部信号。如果引脚输出低电平外部怎么拉也是低。这个特性就来源于它的“准双向”结构。不少初学者在51上用按键时忘了先写1导致读到的永远是0就是这个原因。5.2 STM32等现代单片机按需配置GPIO模式到了STM32GPIO模式就被细分了比如常见的输入浮空、输入上拉、输入下拉、模拟输入、开漏输出、推挽输出、复用开漏、复用推挽等。实际上你配置输出模式时就是明确告诉芯片“我要用推挽还是开漏”。用STM32标准库或HAL库配置推挽输出代码一般是这样的GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin GPIO_PIN_5; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; // 推挽输出 GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, GPIO_InitStruct);而配置开漏输出只是把Mode改成GPIO_MODE_OUTPUT_OD同时如果片内也想用上拉电阻可以设置GPIO_PULLUP。这里要注意STM32部分型号的内部上拉电阻阻值较大一般只能用来维持电平不适合高速通信真正的I2C等总线还是建议外部上拉。我用同一个GPIO分别配置为推挽和开漏外部上拉4.7k用示波器测100kHz方波信号推挽输出的上升沿非常陡峭几乎是垂直的而开漏输出上升沿是一条明显的RC充电曲线从0V到3.3V大概用了微秒级的时间。频率越高这个差距越明显。这个对比基本解释了为什么开漏不适合高速强驱动场景。5.3 实战利用开漏输出实现3.3V单片机与5V外设的电平转换正好趁这篇文章我把一个实际做过的小模块给大家演示一遍。假设单片机是3.3V的STM32要驱动一个5V逻辑电平的LCD模块。引脚接法STM32的PB0配置为开漏输出外部将1k上拉电阻接到5V电源同时PB0接到LCD模块的某个控制引脚。然后写代码HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 引脚高阻靠外部上拉到5V HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 引脚拉低到GND这样当写SET时PB0是高阻态外部上拉把电平拉到5VLCD识别到的是5V高电平写RESET时PB0被拉低到0VLCD识别到低电平。这样完全避免了3.3V引脚直接输出3.3V导致的高电平阈值不足也避免了5V设备反向灌入3.3V芯片引脚的风险。当然这个方法有个前提5V设备和3.3V设备之间的逻辑电平要兼容上拉电阻的选择也要考虑电流。如果你想做双向的电平转换比如I2C总线那就需要MOS管搭建双向转换电路或者直接买电平转换模块这里不展开。5.4 开漏输出调试中的杂症速查表最后分享一个我实际调试开漏电路时总结的速查表很实用排查问题的时候照着看能省不少时间现象可能原因排查方法引脚输出高电平时电压不够没接上拉电阻、上拉电源接错或电阻太大先用万用表量上拉电阻两端电压确认上拉到指定电源信号上升沿很慢上拉电阻阻值过大、总线负载电容大换小电阻如4.7k或1k或用示波器测上升时间和另一个开漏设备短接后通信异常其中一个设备没有真正开漏而是推挽用万用表量设备在不驱动时的引脚状态正常应该是高阻悬空单片机内部上拉代替外部上拉I2C通信不稳内部上拉阻值太大上升沿过慢加外部2.2k~4.7k上拉不要依赖内部上拉开漏输出读取外部信号时读到乱码忘了把引脚配置为输入模式开漏输出模式本质还是输出模式要想读外部信号必须先把GPIO切换成输入模式说实话IO配置这块如果你只记住“推挽输出高电平开漏输出要加上拉”那只是背了一个结论。真正理解了内部的管子结构之后你会突然发现以前很多玄学问题都有了明确答案。比如为什么I2C必须开漏为什么51单片机低电平驱动LED更常见为什么STM32的IO口配置里明明叫“开漏”却也能输出“高”电平。本质上都是同一件事谁在拉高谁在拉低拉得动还是拉不动。我个人在实际调试中的体会是遇到GPIO信号不正常别急着怀疑代码、怀疑芯片先拿示波器看引脚波形再翻到数据手册的GPIO结构框图把内部结构画一遍大多数问题自己就通了。搞单片机的最重要的能力其实就是把“引脚内部看不见的那点事”想明白。希望这篇文章能帮你少走我当年走过的那些弯路。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →