ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

推挽输出和开漏输出区别详解:单片机高电平驱动与上拉电阻实战

推挽输出和开漏输出区别详解:单片机高电平驱动与上拉电阻实战 单片机怎么输出高电平这个问题看起来特别基础但我发现后台私信里问的人真不少尤其是刚接触单片机的朋友经常被“推挽输出”和“开漏输出”这两个词绕晕。有的人照着网上的代码把IO口配成了开漏结果LED死活不亮换回推挽一下就亮了也有的人在I2C总线上用了推挽输出结果通信时好时坏甚至感觉芯片发烫。这些现象背后其实就是同一件事没搞懂这两种输出模式最本质的区别。这篇文章我把这些年调电路的经验摊开讲从内部结构到上拉电阻计算再到实际选型一次说清楚。1. 单片机怎么输出高电平先掌握电压和电流的基础1.1 高电平不是代码写出来的是引脚驱动电路决定的很多初学者以为代码里写一句“P1^1 1;”或者“HAL_GPIO_WritePin(...)”引脚上就“有”高电平了。这句话对但没说到点子上。实际上写到GPIO数据寄存器里的那个“1”只是告诉芯片内部的引脚驱动电路去工作最终引脚上呈现什么电压完全取决于这个驱动电路和外部电路的共同作用。从电气参数的角度看高电平不是一个固定值而是一个电压范围。TTL电平标准里输入高电平门限是2.0V输入低电平是0.8VCMOS电平则是按电源电压比例来的比如3.3V供电时输入高电平通常要大于0.7 × VCC大约2.31V。芯片数据手册里给出的VOH输出高电平最小值和VOL输出低电平最大值才是我们判断“这个引脚能不能被下游识别为高/低电平”的依据。比如某单片机在3.3V供电、输出电流为8mA时VOH保证不低于2.4V那就意味着它带8mA负载时引脚电压至少还有2.4V下游设备识别成高电平完全没问题。这里要提醒一句**空载时引脚输出非常接近VCC不代表带上负载后还是这个电压。**只要负载电流超过了引脚的驱动能力电平就会掉下来。很多“通信不稳定”“LED亮度不对”的问题查到最后一多半是栽在“负载太重”这四个字上。1.2 高电平必须“有电流来源”这是理解推挽和开漏的分水岭继续说下去之前先建立一个特别重要的观念**一个引脚要输出高电平本质上必须有一股电流把引脚“顶”到接近VCC的位置。**这股电流从哪来只有两种来源一种来自芯片内部由输出驱动电路主动提供一种来自芯片外部靠上拉电阻从电源拉过来。推挽输出属于第一种开漏输出属于第二种。这也是它们最本质区别的雏形。举个生活化的例子你往一个游泳池注水可以用水泵芯片内部驱动抽水灌进去也可以靠一根从高处接过来的水管靠重力慢慢流进去外部上拉。水泵能快速把水位顶起来重力水管也能把水位顶起来但速度、力量和可控性完全不是一个级别。下面把两种结构逐一拆开你就能看得很清楚。2. 推挽输出内部结构两个MOS管一推一拉高电平有源驱动2.1 输出高电平时引脚直接被“推”到VCC推挽输出的完整名字叫“推挽式输出”Push-Pull Output内部结构可以简化成两个MOS管串联在VCC和GND之间上面是P-MOS管老工艺里也可能是PNP三极管下面是N-MOS管NPN三极管两个管子的中间连接点就是输出引脚。当你要输出高电平时控制逻辑让上面的P-MOS导通、下面的N-MOS截止引脚通过P-MOS的导通电阻Rds(on)直接连到VCC被“推”到高电平当你要输出低电平时上面的截止、下面的导通引脚被“拉”到GND。正因为这两个管子交替导通一个负责把电平推上去一个负责把电平拉下来所以叫“推挽”。用我之前说的例子类比推挽输出就像一个双向水阀既能往池子里注水也能把池子里的水放干而且两个方向都非常有力气。它输出的高电平是实打实的由芯片内部电源直接供过来电流能力比较强不需要外接任何电阻引脚上就直接是高电平。2.2 推挽输出的优势和那个“天生缺陷”推挽输出的优势用过的都知道驱动能力强灌电流sink和拉电流source都能做到几十毫安级别具体看芯片型号电平切换时一边导通一边截止上升沿和下降沿都很快非常适合高速信号不需要外加上拉电阻省元件、省面积、省成本。但推挽输出有一个非常明显的“天生缺陷”**两个推挽输出引脚不能直接并在一起。**假如引脚A输出高、引脚B输出低而你把它们连到同一根线上那就等于把VCC通过A的P-MOS、再通过B的N-MOS直接短到了GND。这时候电流会瞬间飙升超过引脚允许的最大电流轻则发热、输出失效重则烧毁引脚甚至整颗芯片。这就是为什么推挽输出做不了“线与”Wired-AND逻辑也做不了多机共享一根数据线的场景。另外推挽输出也没法直接做电平转换。3.3V的单片机用推挽输出高电平最高就只能到3.3V不可能自己把自己“抬”到5V。想要3.3V信号控制5V设备这个短板就会暴露出来。3. 开漏输出为什么需要上拉电阻内部结构和选值计算3.1 结构上“上面是空的”所以叫开漏开漏输出Open-Drain Output的内部结构比推挽简单得多只剩下一个N-MOS管漏极直接引到引脚上上面没有P-MOS管处于“悬空”状态——这也是“开漏”漏极开路名称的由来。如果是老式三极管工艺就叫“开集电极”Open-Collector原理完全一样。开漏输出在工作时只做一件事拉低。输出1的控制信号让N-MOS管截止引脚既不连VCC也不连GND处于高阻状态只有输出0时N-MOS管导通引脚被拉到GND。关键点来了**当管子截止、引脚悬空时引脚上的电压是不确定的它既不是高电平也不是低电平物理上叫“浮空”。**你想让这条线呈现高电平就得在外部用一只电阻把引脚接到VCC这个电阻就是常说的“上拉电阻”。所以开漏输出用一句话概括**_它自己永远不会主动输出高电平它只能选择“把线拉低”或者“放手不管”。**高电平是上拉电阻帮忙给的。这也是“开漏输出必须配上拉”的根本原因。3.2 上拉电阻怎么选把计算过程透明地算给你看既然高电平要靠上拉电阻提供那这个电阻的取值就很关键。取值太小和太大都有问题我直接给一个可复用的思路。先看流向芯片内部的电流。当开漏引脚输出低电平时如果上拉电阻太小流过N-MOS管的电流会太大。欧姆定律算一下5V供电、上拉1kΩ输出低电平时电流就是5V/1kΩ 5mA对大多数单片机来说还在承受范围内但如果换成100Ω电流就变成50mA这明显超出一般IO口通常20mA以内的承受能力引脚就会发热甚至损坏。再看下游信号的上升速度。上拉电阻太大高电平的电压是有了但充电流太小线路上的寄生电容充电就慢导致上升沿变缓。I2C协议里如果数据线上的上升沿太慢超过协议规定的最大上升时间通信就会出错。假设总线等效电容是100pF上拉电阻10kΩRC时间常数就是10kΩ × 100pF 1μs。粗略估算从低电平到高电平的上升时间大约需要2.2个时间常数也就是2.2μs。而标准模式I2C对上升时间的要求是不超过1μs也就是说10kΩ加100pF这种组合已经超标了需要把电阻换成4.7kΩ甚至2.2kΩ。所以实际工程里I2C上拉电阻常见值就在1kΩ到10kΩ之间低速、功耗敏感的场合用10kΩ高速场合用1kΩ到4.7kΩ。具体选多少我建议按这个流程走先查芯片手册确认引脚允许的最大灌电流确定电阻下限再根据总线电容和通信速率估算上升时间确定电阻上限最后取一个折中值并留余量。3.3 开漏输出真正厉害的地方I2C、电平转换、线与既然开漏输出自己推不出高电平为什么这么多电路还要用它因为它的应用场景恰恰是推挽输出做不了的。第一个场景是I2C总线。I2C协议要求SDA和SCL都是开漏结构因为总线上可能挂多个设备任何一方都能把线拉低来实现时钟同步和总线仲裁。如果大家都用推挽输出两个设备同时输出相反电平总线就短路了。这在I2C这种多主从架构下是绝对不能接受的。第二个场景是电平转换。开漏输出配合一个“接到另一个高电压电源”的上拉电阻就能把3.3V的MCU信号转成5V电平。比如3.3V的单片机I2C接口接5V的外设可以把开漏引脚的上拉电阻接到5V。引脚低电平时是0V高电平时被上拉到5V下游设备看到的就是标准的5V电平。用推挽输出做不到这一点因为推挽只能输出到自己的供电电压。第三个场景是线与逻辑。多个开漏输出可以直接接在同一个节点上只要任何一个输出低电平整条线就是低电平全都不拉低时线才被上拉到高电平。这种性质在很多按键输入、中断检测、负载检测电路里用得非常普遍是不少硬件设计的底层逻辑。4. 推挽输出和开漏输出最本质的区别一个给电一个放手4.1 一句话讲透本质绕了这么多现在可以正面回答标题里的问题了。**推挽输出和开漏输出最本质的区别就一条推挽输出有主动供给电流的能力能自己把引脚拉到高电平开漏输出没有供给电流的能力只能主动拉低高电平必须靠外部上拉电阻来提供。**推挽是“主动给”开漏是“被动等”。这个区别可以从三个层面理解。第一是电流路径推挽高电平时的电流从芯片内部流过P-MOS到达负载来源在内部开漏高电平时的电流从外部电源流过上拉电阻到达负载来源在外部。第二是电压上限推挽输出的高电平被芯片自己的供电电压锁死开漏输出的高电平理论上可以被上拉到任何不超过引脚耐压的电压是“借来的电平”。第三是控制自由度推挽输出任何时候都在主动驱动总线不适合共享开漏输出可以在“拉低”和“不干预”之间切换天然适合共享线和多设备协作。提示判断一个引脚是不是开漏最简单的方法就是看它输出高电平时是否需要外接上拉电阻。需要就是开漏不需要大概率是推挽或者内部已经集成了上拉。4.2 一张表看清爽推挽和开漏的完整对比我整理了一个对比表建议收藏联调电路时照着看项目推挽输出开漏输出内部结构P-MOS N-MOS 互补只有N-MOS漏极开路高电平来源芯片内部主动提供外部上拉电阻提供低电平主动拉低主动拉低高电平最大电压受芯片供电电压限制取决于上拉电阻接的电源电压驱动电流能力强源和灌都可以灌电流可以拉电流几乎为零是否需要上拉电阻不需要必须外接或启用内部上拉能否线与/共享总线不能直接相并会短路能天然支持线与典型应用LED驱动、MOS管栅极驱动、普通信号I2C、电平转换、多设备中断线主要风险总线冲突大电流、过载发热上升沿慢、低电平灌电流受限这张表里最值得反复看的是“高电平来源”和“能否线与”这两行。只要把这两行理解透了绝大多数应用场景你都能自己判断该选哪种模式。4.3 为什么说51单片机的准双向口是“半个开漏”聊到这儿绕不开很多人的启蒙芯片——51单片机。51单片机的P1、P2、P3口默认模式叫“准双向口”Quasi-Bidirectional它的本质是“内部带弱上拉的类开漏结构”输出低电平时内部下拉管导通输出高电平时引脚通过一个几十千欧到上百千欧的弱上拉电阻接VCC。所以你会发现51的引脚驱动LED时高电平能力很弱点不亮很多教程干脆用低电平点亮LED靠的是“灌电流”能力比“拉电流”强。而写按键扫描程序时如果某个引脚要作为输入你必须先向该引脚写1把它“抬”起来否则读到的永远可能是低电平——这就是准双向口的特性。但要注意51的P0口是真开漏内部没有上拉。做数码管段选之类的高电平输出时必须外接上拉电阻否则输出高电平时引脚是浮空的。很多51初学者第一次做数码管不亮查来查去最后发现是P0口忘了加上拉电阻就是因为这个原因。5. 实际工程选型指南I2C、LED、MOS管和按键扫描怎么配5.1 什么时候必须开漏什么时候坚决推挽根据我的实际经验选型时可以这样快速判断I2C的SDA/SCL、一线制总线比如DS18B20、多设备共享的中断引脚必须用开漏加上拉。这不是技巧问题是协议要求用推挽就是给自己挖坑。驱动LED尤其用高电平点亮、驱动MOS管栅极、驱动蜂鸣器推荐推挽。这些负载要么需要灌电流要么需要足够的拉电流和快速的边沿开漏的弱上拉会拖后腿。做电平转换用开漏加上拉上拉接到目标电压。按键扫描、矩阵键盘优先用准双向口或者推挽写1后再读也可以直接用内部上拉。51的准双向口内部弱上拉经常够用STM32则可以直接配输入上拉模式。4×4键盘需不需要上拉电阻关键就看你用的引脚是什么模式准双向口或开漏需要推挽写1后读也可以不用外部上拉但要注意推挽输出时按键直接接地按下时灌电流会比较大。实际操作中我踩过一次印象很深的坑有一块板子3.3V的MCU要驱动一个5V供电的MOS管驱动芯片我当时图省事把MCU引脚配成推挽输出直接去拉信号线。结果因为电平不匹配驱动芯片根本识别不了3.3V的高电平信号一直处于不确定状态。后来改成开漏输出、上拉到5V问题立刻消失。这种“推挽看起来能行实际被电压差卡死”的情况用多了你就知道电平匹配问题一定要提前想清楚。另外提一句关于LED的LED是单向导通器件反向电压过高会击穿损坏但MCU直接驱动时电平一般不超过5V反而更要紧的是限流电阻。不管推挽还是开漏驱动LED都建议串一个电阻把电流限制在几毫安到十几毫安既保护LED也保护引脚。5.2 “推挽输出会不会烧单片机”一次说清热搜词里有个“STC单片机推挽输出时容易烧吗”这里多说几句。**推挽输出本身不会烧芯片烧芯片的是过流。**如果你把推挽输出引脚直接接到GND或者把两个推挽引脚短接或者用推挽引脚去驱动一个没有限流电阻的LED那电流就会超过芯片允许值芯片才可能损坏。具体到STC单片机它相当一部分型号的IO口推挽能力很强有些引脚输出电流可以到20mA以上整片还有总电流限制。驱动LED时如果不加限流电阻看似暂时能用实际已经在超限运行时间一长就有风险。我的建议是一切电流密集的场合先在数据手册里确认单引脚最大电流和全芯片总电流留出50%以上的余量宁可外加强驱动芯片也不要硬扛。另外如果你在代码里把引脚配置成推挽同时这个引脚又被外部电路强拉成低电平那引脚内部的P-MOS就会持续输出大电流芯片会发烫。这种现象在调试初期特别常见。排查时先量一下引脚电压、再摸一下芯片温度往往比反复改代码更有效率。5.3 不同单片机的配置代码51和STM32都给你先说51单片机以常见的STC系列为例通过PxM1和PxM0两个寄存器控制IO模式。不同型号寄存器名可能有差异以具体数据手册为准// P1口全部配置为推挽输出 P1M1 0x00; P1M0 0xFF; // P1口全部配置为开漏输出 P1M1 0xFF; P1M0 0xFF; // P1口恢复为默认准双向口 P1M1 0x00; P1M0 0x00;这里的规律是00 准双向口01 推挽输出10 高阻输入11 开漏输出。如果只需要配置单个引脚按位计算PxM1和PxM0即可。再说STM32HAL库的配置思路很直接关键是GPIO_InitTypeDef里的Mode字段GPIO_InitTypeDef GPIO_InitStruct {0}; // 推挽输出比如驱动LED GPIO_InitStruct.Pin GPIO_PIN_1; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); // 开漏输出比如I2C的数据线配合外部上拉 GPIO_InitStruct.Pin GPIO_PIN_7; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull GPIO_PULLUP; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, GPIO_InitStruct);这里有个细节STM32内部上拉的拉电流能力有限I2C这类总线最好还是外接上拉内部上拉只适合一些低速、不严格的场合。另外引脚用作PWM输出、串口等复用功能时还要区分复用推挽GPIO_MODE_AF_PP和复用开漏GPIO_MODE_AF_OD。比如I2C的复用引脚必须用AF_OD而PWM输出用AF_PP才能保证驱动能力。这也就是热搜词里“复用推挽输出和推挽输出区别”的来源一个用在复用功能场景一个用在普通GPIO场景内部结构本身没有本质差异。5.4 调试时最常见的五个现象和排查思路最后把这些年帮人排查问题最常见的几个现象列一下你可以对号入座**现象一LED高电平点亮不亮改成低电平点亮却亮了。**多半是引脚高电平驱动能力不足比如51准双向口或者开了漏。要么换推挽要么限制流电阻后改用灌电流接法。**现象二I2C能初始化但通信时好时坏。**很大概率是开漏上拉了但电阻太大或者总线电容太大上升沿太慢。用示波器看SDA和SCL的上升沿超过1μs就要把上拉电阻调小。**现象三两个板子通信低电平正常、高电平电压只有1V多。**检查上拉电阻是不是漏焊或者上拉电源是不是没接对。开漏模式下高电平全靠这颗电阻它出问题整个电平都乱套。**现象四手一碰引脚电平就跳变。**引脚处于高阻或者浮空状态外部有干扰。解决方法是加上拉电阻或者把引脚内部上拉打开让高电平有个明确的“靠山”。**现象五引脚配置成推挽高电平一接负载电压就掉。**负载太重超过了引脚驱动能力。要么减轻负载要么加一个驱动电路比如三极管、MOS管或者缓冲器。6. 一点个人体会说实话推挽和开漏这个知识点刚学单片机的时候我也绕了好一阵。但后来在I2C和电平转换上踩了几次坑回头再看这两个词发现它们其实特别容易理解一个是有源驱动一个是无源上拉。你在做任何引脚选型之前先问自己一句这条线上的高电平谁来给如果答案是芯片自己就用推挽如果答案是需要外部电路帮忙就用开漏。想清楚这一句比背十遍概念都管用。最后再分享一个小技巧调试开漏电路时别急着写代码先用万用表量一下空载引脚电压。没接上拉时浮空引脚电压是乱的接好上拉后空载应该直接就是上拉电源电压。这一步十秒钟能帮你验证硬件到底通没通省下后面大量猜代码的时间。
返回列表