大家好,我是老张。上一章咱们聊了模拟电路,教你怎么把传感器信号干净地送进ADC。这章咱们换个方向,聊数字电路。

数字电路听起来比模拟简单——不就是0和1嘛。但做嵌入式开发的,谁没烧过几个芯片?谁没遇到过I²C死活不通、串口乱码、两个模块接一起就不工作的邪门事?很多时候,根子就在数字电路最基础的地方:电平不匹配。

这章老张不讲真值表、不推卡诺图,就围绕嵌入式开发中最容易踩的三个数字电路坑来讲:逻辑电平标准、上拉下拉的本质、开漏与推挽的区别。学完这章,你再画IO口外围电路的时候,心里就有底了。

目录

一、逻辑电平——你以为的0和1,芯片不一定这么想

1.1 一场“通信事故”开场

1.2 TTL、CMOS、LVTTL,到底什么意思?

1.3 用示波器看逻辑电平——别只看万用表

二、上拉与下拉——电路最不起眼的细节,却是通信失败的头号杀手

2.1 GPIO悬空有多可怕?

2.2 I²C的上拉电阻——不只是“拉高”那么简单

2.3 哪些引脚需要上下拉?一张表记清楚

三、开漏输出与推挽输出——一对你必须搞懂的GPIO配置

3.1 推挽输出:能推能拉,力大砖飞

3.2 开漏输出:只能拉低,不能拉高

3.3 什么时候用推挽,什么时候用开漏?

四、总线竞争与电平转换——两个实操避坑指南

4.1 总线竞争,如何防止烧IO?

4.2 3.3V和5V怎么安全互联?四种方案实测

五、本章总结


一、逻辑电平——你以为的0和1,芯片不一定这么想

1.1 一场“通信事故”开场

先说个我早年的糗事。那时候我用一块STM32开发板(3.3V供电)通过串口连一个老旧的5V传感器模块。接线的时候心想,串口嘛,TX接RX,RX接TX,地线一连就完事了。结果通电以后,STM32收到的数据全是乱码,偶尔能识别几个字节,大部分是0xFF。我查波特率、查停止位、查校验位,折腾一下午。最后拿示波器一看,传感器TX出来的高电平稳稳的5V,而STM32的RX引脚耐压手册上写的最大是VDD+0.3V,也就是3.6V。这个5V信号不但超出了识别范围,而且已经在悄悄地通过IO口的保护二极管往VDD灌电流了。幸好那次传感器驱动能力弱,没灌出大问题,但芯片发烫是实实在在的(没烧STM32 IO口完全是人品大爆发)。

这就是典型的电平不匹配。数字电路里的0和1不是数学概念,是实实在在的电压值。不同芯片对这个电压值的定义不一样,你把两个标准不同的器件接一起,不出问题才怪。

1.2 TTL、CMOS、LVTTL,到底什么意思?

嵌入式世界里,常听到TTL电平、CMOS电平、LVTTL这几个词。老张给你用大白话解释清楚:

TTL电平(5V系统):老一代标准,电源5V。

  • 输入低电平最大值VIL_max = 0.8V,也就是说你给0~0.8V,芯片认你是0。

  • 输入高电平最小值VIH_min = 2.0V,给2.0~5V,芯片认你是1。

  • 输出高电平最小值VOH_min = 2.4V(早期器件),输出低电平最大值VOL_max = 0.4V。

看出问题了吗?TTL的输出高电平最低只有2.4V,而输入要求高电平至少2.0V,中间只有0.4V的容差,抗干扰能力差。而且TTL的输入低电平门限0.8V偏低,容易被噪声触发。

CMOS电平(5V系统):现代工艺,电源5V。

  • 输入低电平最大值VIL_max ≈ 1.5V(典型为30% VDD)。

  • 输入高电平最小值VIH_min ≈ 3.5V(典型为70% VDD)。

  • 输出高电平VOH_min ≈ 4.9V,输出低电平VOL_max ≈ 0.1V。

CMOS的输出摆幅接近满电源,比TTL强得多,输入门限也更高,噪声容限大。

LVTTL/LVCMOS电平(3.3V系统):现在嵌入式MCU的主流,电源3.3V。

  • 输入低电平最大值VIL_max ≈ 0.8V。

  • 输入高电平最小值VIH_min ≈ 2.0V。

  • 输出高电平VOH_min ≈ 2.4V~3.0V(不同芯片有差异)。

看到这里你该明白了:3.3V的MCU输出高电平最低可能只有2.4V,而5V CMOS器件要求高电平至少3.5V。如果你用3.3V的GPIO直接驱动5V的CMOS输入脚,对方可能压根不认你这个“高电平”。反过来,5V CMOS输出高电平接近5V,直接怼到3.3V的MCU引脚上,虽然高电平能认,但电压已经超过了MCU引脚的耐压上限,有烧毁风险。这就是为什么需要电平转换。

1.3 用示波器看逻辑电平——别只看万用表

万用表量电压是平均值,看不出信号质量。数字信号要判断好坏,必须上示波器。关键是看眼图——把波形叠在一起,看高电平稳不稳、低电平干不干净、上升沿抖不抖。如果高电平上有很多毛刺,或者幅度勉强够到VIH_min门限,数据就可能偶尔出错,而且这种偶发错误极难复现。

另外留意地弹现象:当多路输出同时从高翻低时,瞬间大电流涌入地线,芯片内部地电位被短暂抬高。这个抬高的电压会吃掉低电平的噪声容限,可能导致其他信号被误判为高。走线粗、去耦好,能压住地弹。

二、上拉与下拉——电路最不起眼的细节,却是通信失败的头号杀手

2.1 GPIO悬空有多可怕?

很多新手配置按键输入时这么干:GPIO设成输入模式,一头接按键,另一头接地。按下去接地,松开悬空。代码一跑,发现按键没按下时也在随机触发,用示波器看引脚电平,像心电图一样上上下下。

这个现象叫引脚悬空。当一个CMOS输入引脚什么都不接时,它的输入阻抗极高(几十MΩ以上),对电场极其敏感。你用手靠近它,工频感应就能让电平乱翻。程序读到的是随机值,按键自然就“发疯”了。

解决办法就是上拉或下拉电阻。在引脚和VDD之间接一个电阻(上拉),没按键时引脚被拉到确定的高电平。接在引脚和GND之间就是下拉。电阻值一般选4.7kΩ~10kΩ,太小费电,太大抗干扰能力差。

2.2 I²C的上拉电阻——不只是“拉高”那么简单

I²C总线的SCL和SDA两根线必须接上拉电阻,这是常识。但你知道为什么吗?而且阻值怎么选?

I²C的器件只能把总线拉到低电平,释放总线后,要靠上拉电阻把总线拉回高电平。如果不上拉,总线永远是低,通信根本不启动。

上拉电阻不能随便选。太大会怎样?总线从低拉回高的时候,是上拉电阻给总线寄生电容充电。电阻越大,RC时间常数越大,上升沿就越慢。I²C标准规定,在快速模式(400kHz)下,上升时间不能超过300ns。总线电容一般估算几十pF,用10kΩ上拉的话,RC时间常数就几百纳秒了,上升沿可能超规格,导致数据采样出错。

太小也不行。I²C器件把总线拉低时,会流过电流VDD/R_pullup。3.3V/1kΩ=3.3mA,单个器件可能撑得住,但多个器件同时拉低加上长线缆,驱动能力不够的话低电平就拉不实。我一般用3.3kΩ~4.7kΩ,兼顾上升速度和驱动能力。在低功耗设备上可能拉到10kΩ,前提是速度不快。

还有个容易被忽略的点:上升沿慢会导致从机误触发。如果上升沿像爬坡一样缓慢通过逻辑门限区,干扰稍大就可能产生毛刺,被从机当作额外的时钟脉冲,导致总线挂死。所以上拉阻值一定要根据实际总线电容来算,不要无脑上10kΩ。

2.3 哪些引脚需要上下拉?一张表记清楚

场景接法典型阻值原因
按键输入上拉或下拉10kΩ防止悬空,确定默认电平
I²C总线上拉到VDD3.3kΩ~4.7kΩ提供高电平驱动,控制上升沿
SPI的CS片选上拉10kΩ防止主控复位期间从设备误选中
复位引脚上拉10kΩ确保正常工作时复位脚为高,外部干扰不误复位
悬空不用的IO设为输出低或上拉/下拉10kΩ降低功耗,防止振荡产生EMI
JTAG/SWD调试口上拉或下拉10kΩ防止调试线悬空时目标芯片异常
MOS管栅极下拉10kΩ~100kΩMCU复位期间IO为高阻,栅极不能悬空,否则管子可能半导通烧毁

特别强调MOS管栅极:MCU上电复位期间所有IO默认高阻,如果栅极悬空,稍微一点漏电或电磁感应就可能让MOS管处于半导通状态,大电流长时间流过,管子烧了都不知道怎么死的。加一个下拉电阻保平安,上电时栅极被拉到确定的低电平,管子截止。这个电阻同时在开关速度允许的范围内大一些好,省电。

如果IO数量实在紧张,很多MCU内部有弱上拉/下拉(大约几十kΩ),可以配置使用。但注意内部上下拉比较弱,在干扰严重的场合可能扛不住,建议外部加固。

三、开漏输出与推挽输出——一对你必须搞懂的GPIO配置

3.1 推挽输出:能推能拉,力大砖飞

推挽输出是GPIO最常见的工作模式。内部有一对互补的MOS管:上面一个P管接VDD,下面一个N管接GND。

  • 输出高电平时:P管导通,N管截止,输出被拉到VDD,驱动能力强。

  • 输出低电平时:N管导通,P管截止,输出被拉到GND,同样驱动能力强。

推挽输出的好处是高低电平驱动都强,边沿快,适合高速信号。比如SPI的时钟线、普通LED驱动、继电器控制等等。

但推挽有个致命弱点:绝对不能把两个推挽输出直接接在一起。如果A输出高、B输出低,那就等于VDD通过两个导通管直通到GND——这叫“总线冲突”或者形象点说“撞车”,瞬间电流能把IO口烧掉。所以推挽输出只能用于点对点或者点对多的单向驱动(比如一个主控输出给多个从设备输入)。

3.2 开漏输出:只能拉低,不能拉高

开漏输出的输出端只有下面那个N管,上面没有P管。所以它只能把输出拉到地,不能主动输出高电平。

  • 输出低:N管导通,输出接地。

  • 输出“高”:N管截止,输出变成高阻状态,什么也不驱动。

那高电平怎么来?只能靠外部上拉电阻拉到VDD。

开漏输出的妙处:多个开漏输出可以直接接在一起。因为任何器件只能把线拉到地,不拉的时候就释放,不会出现推挽那种一个拉高一个拉低的“打架”情况。谁拉低谁说了算,这叫“线与”逻辑。I²C总线就是靠这个实现的:主从设备都可以把SDA或SCL拉低,释放后由上拉电阻拉高。还有1-Wire单总线也是同理。

另外,开漏输出还能方便地实现电平转换。MCU是3.3V供电,但我把上拉电阻接到5V,开漏输出释放时总线电压就是5V,轻松驱动5V器件。注意此时输出引脚耐压必须支持5V容忍,比如STM32的FT引脚。

3.3 什么时候用推挽,什么时候用开漏?

场景推荐模式理由
驱动LED、继电器推挽需要强驱动,单向控制
SPI、UART推挽高速单向信号,边沿快
I²C总线开漏多设备共享,需要线与
1-Wire单总线开漏单线双向,线与逻辑
多设备共享中断线开漏多个设备都可以拉低请求中断
需要电平上移开漏+外部上拉到目标电压灵活实现电平转换

一个设计习惯:中断输出引脚尽量用开漏。多个外设的中断线可以直接并在一起接MCU的一个中断输入脚,任何一个外设拉低都能触发中断,MCU再逐个查询是哪个触发的。如果是推挽,不同器件争夺总线会烧东西。

四、总线竞争与电平转换——两个实操避坑指南

4.1 总线竞争,如何防止烧IO?

总线竞争的根源是多个输出同时驱动同一根线。除了前面说的推挽不能并接,还有几种容易踩坑的情况:

SPI的多从机CS引脚:CS是主控输出、从机输入,用推挽没问题,一个主控接多个从机不会撞。但如果有多个主控的可能,就要考虑仲裁了,不过常规嵌入式很少用到多主SPI。

MCU的IO口电平转换时的冲突:做双向电平转换时,有些简单的MOS管方案需要留意方向控制。如果用自动双向电平转换模块(比如TXS0108),内部有加速电路,一般不会出问题。但如果自己用两颗MOS管搭双向转换,上拉电阻和寄生参数没配好,可能会在边沿产生振荡,形成短暂的推挽冲突条件。

程序BUG导致IO方向切换:这是纯软件问题导致的硬件事故。比如本来配置为输入的IO,程序运行时误操作给改成推挽输出高,而外部恰好有器件在拉低这根线——瞬间大电流走起。所以对IO初始化要规范,特别是从低功耗唤醒后要重新确认IO配置状态,尽量不要在运行时动态改变IO方向,尤其是接外部器件的情况。

4.2 3.3V和5V怎么安全互联?四种方案实测

这是嵌入式设计里最经典的问题。我给出四种经实际验证的方案:

方案一:电阻分压(5V→3.3V单向)。最简单的降压方案,5V输出经两个电阻分压出3.3V进MCU。适用于低速信号,比如UART的TX从5V器件到3.3V MCU的RX。阻值选几kΩ,兼顾功耗和速度。缺点是只能单向降压,不能升压。

方案二:三极管/MOS管电平转换(双向、低成本)。用一个N沟道MOS管(如BSS138)加两个上拉电阻,是最经典的双向电平转换电路,I²C上用得最多。

  • MOS的源极接3.3V侧,漏极接5V侧,栅极固定接3.3V。

  • 当3.3V侧拉低时,MOS管导通,5V侧也被拉低。

  • 当5V侧拉低时,MOS管体二极管导通,把源极拉低,然后MOS管导通,3.3V侧被拉低。

  • 两侧都释放时,各自的上拉电阻把总线拉到各自的VDD。
    这个电路成本几毛钱,非常适合I²C这类双向开漏总线。但注意MOS管的阈值电压必须低于3.3V,BSS138的Vgs(th)典型1.3V,够用。

方案三:专用电平转换芯片(高速、省心)。TI的TXB0104、TXS0108E等,内部有自动方向检测和加速驱动,即插即用,适合SPI等高速信号。就是比MOS管方案贵,但省板面积、省调试时间。注意有些自动转换芯片驱动能力弱,长线缆场合慎用。

方案四:5V容忍引脚直连(最简单)。很多MCU的部分IO是5V容忍的(比如STM32的FT引脚)。5V输出直接连到这些引脚没问题,因为内部保护结构允许5V输入。但3.3V驱动5V输入时,要注意对方的VIH门槛——多数5V CMOS器件的VIH约3.5V,而3.3V MCU输出高电平至少2.4V,可能不够。要查对方数据手册,确认是否能被3.3V逻辑驱动。有些器件VIH低至2.0V就能被3.3V可靠驱动。如果不够,就需要上电平转换。

一个实用技巧:如果只是偶尔有5V到3.3V的单向通信,可以在5V输出端串一个1kΩ电阻再进MCU的3.3V IO。这个电阻与IO口内部的钳位二极管配合,在5V高电平时限制注入电流,只要电流小于IO口内部钳位二极管的承受能力(一般是几mA),就不会损坏芯片。但这个方法需要仔细核算,不能用于量产产品,做实验应急可以。

五、本章总结

这一章咱们把数字电路中最核心的三个实践问题捋了一遍:

  1. 逻辑电平标准:TTL、CMOS、LVTTL的门限电压不同,3.3V和5V混用必须查数据手册做电平转换,不能想当然。

  2. 上拉下拉:悬空的引脚是噪声源,按键、I²C、片选、复位、MOS管栅极都需要确定默认状态。I²C的上拉阻值要算,不能无脑用10kΩ。

  3. 开漏与推挽:推挽驱动强但不能并接,开漏只能拉低但可以线与。I²C、中断共享用开漏,单向驱动用推挽。

硬件设计里有一句话老张很认可:数字电路最麻烦的不是逻辑功能,而是电平匹配和接口保护。逻辑功能靠代码能改,接口烧了就得换芯片。把这一章的内容刻在脑子里,你画的每一根信号线都会更靠谱。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐