补充篇:引脚是一片电路——推挽、开漏与施密特
咱们在前几篇把软件这一头走完了:地址、时钟、配置、翻转,一直都是站在代码这边看寄存器的。但有几个问题咱们一路用着,却始终没拆到底:CNF=00 凭什么叫"推挽"?咱们的浮空输入的"浮",到底浮在哪?还有 04 篇的那次翻车:模式没配成输出,BSRR 写了,输出驱动器却跟咱们装聋,这又是为什么?这一篇咱们就下到电路层,把这几个问题拆开了看。您把它当补充篇看,跳过去也不影响主线的连贯。不过干嵌入式这一行,想少栽跟头的话,电路的直觉迟早要补,咱们不如趁热把它补上。
GPIO 的本体不是"软件",它是一片真实的电路。咱们写的每一行代码,干的都只是在"下令"。真正执行命令的,是引脚里的那几十个晶体管。咱们往 GPIOC->CRH = ... 里拧动四位,拧的是电路的挡位。
引脚的解剖图
咱们把一个 GPIO 引脚扒开看,里面有这么几样东西(RM0008 第 9 章的框图翻译版,RM0008 就是 ST 的 STM32F1 参考手册,01 篇咱们翻过的):
咱们从外往里看。最外圈的是一对保护二极管,把引脚电压牢牢地钳在 VDD+0.3V 和 VSS-0.3V 之间。而静电和浪涌一来,头一个碰到的就是它们。咱们再往里走,是一对约 40kΩ 的弱上下拉电阻,接还是不接由软件说了算。更里面的输入路径上站着施密特触发器,负责把引脚上的连续电压判成 0 或 1。输出路径的那一头,站的就是输出驱动器,也就是两只 MOS 管组成的跷跷板。输入和输出其实并联在同一个引脚上,哪条路上岗由 CNF/MODE 四位说了算。
输出侧:上下两管的跷跷板
CNF=00(推挽)的时候,咱们把输出驱动器画成两个状态对照:导通的管子描了色,电流的方向也标在了引脚上:
咱们看 ODR 写 1 的样子:上管导通、下管关断,引脚就被"推"到了接近 3.3V。这里说的"推"(push),指的就是电流从 VDD 出发、经上管流向外部负载的路径。ODR 写 0 的时候,方向就整个反了过来:上管关断、下管导通,电流从外部经引脚被"挽"(pull)回了 VSS,引脚也就压到了接近 0V。而任意时刻都有一只管子在主动驱动,推挽这个名字说的就是这件事。而且从两个方向看下来,它都是低阻抗的输出:电平确定、边沿也陡峭,几十欧姆的导通电阻对上负载,开关自然就干脆利落了。
驱动能力这边是有硬指标的:F103 普通引脚单脚绝对最大 25mA(数据手册电气特性),日常点灯用掉的几毫安,那是绰绰有余的。但 PC13 偏偏不是普通引脚,咱们把它留到本篇后半再说:它有 3mA 的上限。
开漏:只有下管的电路
咱们再看 CNF=01(开漏),它把上管直接撤了:
写 0 的时候,导通的是下管,引脚被拉到了地,电流的通路还在。写 1 呢?下管关断,然后就没有然后了:上管不存在,引脚与 VDD 之间的通路没了,它就浮空了(高阻态)。而想输出"高",您得靠外接上拉电阻,把引脚慢慢地拽上去。拽得有多快、平时又漏了多少电流,都由它说了算:想快就选小,想省电就得选大的,结果两头不能全占。
那要开漏干嘛?咱们看三个正经场景。头一个登场的就是 I2C 总线。它的协议要求多台设备共用一根线,而且人人都能拉低,偏偏谁也不许主动推高。为什么?两台设备的推挽输出顶在一起,结果就是短路。开漏配了外部上拉,天生就守得住协议的要求(第五站 I2C 见真章)。线与也算一个:多个开漏输出共用的上拉只有一根,任何一家拉低了,整条线也就成了低,"与"逻辑不用门电路就做出来了。还有电平转换:上拉接的是 5V,输出的"高"就是 5V,3.3V 的芯片就能跟 5V 的老设备握手(前提是引脚 5V 容忍)。
咱们拿开漏去点 LED,是要吃苦头的:输出"高"时引脚浮空,LED 阳极的电压没了着落,灯要么不亮,要么亮得很勉强。看起来代码全都是对的,灯就是不理咱们。所以点灯咱们选推挽,开漏的用场在总线那边。
输入侧:施密特与上下拉
轮到咱们看输入路径。头一个问题:引脚上的连续电压,怎么变成 IDR 里的 0 和 1?中间站着施密特触发器,它的判定带着迟滞:电压爬过了高阈值、才算 1。跌过了低阈值、才算 0。而卡在两个阈值中间,就保持刚才的判断。为什么要留中间这一段?因为真实信号都带着噪声。要是只有一个 2.0V 的门槛,慢信号晃到 2.0V 附近的时候,输出就跟着抖成了一串毛刺。有了迟滞带,小噪声再怎么折腾,也改不动输出的判断。按键的抖动、长线的感应,头一个替您挡着的就是它。
阈值的具体数值归数据手册的电气特性表管,引脚的类型不同、数值也不同,咱们用的时候去查就好,背就不用了。
第二个问题:悬着的引脚,读出来的是什么?不确定。这就是"浮空"(CNF=01 且不接上下拉)的本义:引脚电平由环境电磁场、手指静电、临近走线的互相推搡决定,您拿万用表量它、读数乱跳。复位的默认值 0x44444444 让所有脚浮空输入,咱们拿到的,就是"最中性"的出厂态:自己不驱动电平,外面来什么信号都照单全收。
咱们要是想要一个确定的默认电平,那就要轮到上下拉电阻出场了:CNF=10 的时候,ODR 的对应位写 1 接通上拉、引脚默认高。而写 0 接通下拉、默认低。您没看错:F1 的输入上下拉选择就藏在 ODR 里,这是 F1 独一份的怪设计(F4 起才挪进专门的 PUPDR)。
这对电阻的阻值约 40kΩ,弱得恰到好处:按键按下的时候,它被接地直接短路,引脚被稳稳地拉低。而松手以后,它又够把引脚拽回默认的电平。按键检测的标准姿势(引脚配上拉、按键接地、读下降沿),下一站咱们就靠它吃饭。
回到 Blue Pill:低电平点亮的电路计算
最后咱们把这盏灯的电路算清楚。Blue Pill 的板载 LED,接法是"灌电流"式的:
LED 的正极经限流电阻挂 3.3V,负极接的是 PC13。PC13 输出低的时候(下管导通),从 3.3V 出发的电流经电阻、LED 流进引脚,而后经下管入地,灯也就亮了。"灌"说的就是这个方向,电流灌进了引脚。PC13 输出高的时候,两端都是 3.3V 的量级、没有压差、没有电流,灯也就灭了。"低电平点亮"的全部机关就在这里:决定谁亮的,是 LED 的接法,而不是软件的逻辑。换成"源电流"式的接法(LED 从引脚流向地),点亮的就成了高电平。两种板子其实都常见,咱们把原理图看明白了再写极性。
再看限流电阻这边:LED 的正向压降约 2V(红光典型),电阻上分到的就是 3.3 - 2.0 = 1.3V。咱们按 Blue Pill 常见的几 kΩ 阻值算,算出来的电流在零点几到一毫安级,现代 LED 这个量级就够亮了。那电阻要是没了?LED 的压降被钳在 2V 左右,剩下的 1.3V 全压在引脚的 MOS 管上,电流大小由管子的导通电阻决定,轻松地冲破 25mA。结果是 LED 命短、管子发热、皆大不欢喜。所以限流电阻不是可有可无的装饰,缺了它,真要出事的。
PC13 的脾气,咱们也得交代。它和 PC14/15 的供电来自备份域:RTC 实时时钟、侵入检测、LSE 低速外部晶振这些断电后还得活的机能,靠的都是这个域。代价是三个脚都被卡得更严:输出模式被限在了 2MHz,电流 3mA 就封了顶(数据手册 DS5319 的电气特性里,写得明明白白的)。咱们配 MODE=10(2MHz)正好顶格:PC13 最高就到 2MHz,配 50MHz 属于写了个寂寞。好在点一毫安级的 LED,3mA 也够咱们用了。
模式表回收
现在咱们回头看 04 篇的组合表,每一行的背后,其实都是一片具体的电路:
| 组合 | 电路里发生的事 |
|---|---|
| 模拟输入 | 施密特触发器断开(省电防干扰),信号直通 ADC |
| 浮空输入 | 只有施密特站岗,引脚电平随缘 |
| 上拉/下拉输入 | 40kΩ 弱电阻给引脚一个默认电平,等外部来翻转 |
| 推挽输出 | 上下两管交替主动驱动,双向低阻抗 |
| 开漏输出 | 只剩下管,高电平外包给外部上拉 |
| 复用 | 输出驱动器的方向盘交给片上外设(USART/SPI/TIM) |
04 篇的那次翻车,现在咱们拿到电路层的解释了。配置留在了浮空输入,意味着输出驱动器根本没上岗:两只 MOS 管对 ODR 的号令装聋,咱们把 BSRR 写得再勤,引脚偏偏纹丝不动。ODR 就算写进去了,也没有输出路径可走(04 篇 Renode 里 BSRR 照写、ODR 的读数纹丝不动,就是这层电路没上岗的样子)。软件的视角说"配置没生效",电路视角看到的是:负责执行的电路压根没接上。
而从下一篇起,咱们开始爬抽象的楼梯了:C 宏怎么把今天这些地址和位包起来,又包出了哪些暗伤。带着电路的这层底子上楼,看什么都是透明的。
您来动手
- 您拿 Blue Pill 原理图(网上搜 "Blue Pill schematic"),找到 PC13 的支路,确认 LED 方向和限流电阻阻值,算出点亮电流。
- 您把
register_led的 CRH 配置改成开漏(CNF=01:(0x6u << 20)),烧进 Renode,看看 ODR 翻转是否照旧,再想想换到实际板子上,LED 会怎样。 - 请您查数据手册 DS5319 的 GPIO 电气特性表,找到普通引脚和 PC13-15 的电流限额原文,核对本文的 25mA/3mA。
- 您再想一个问题:如果把 LED 从"灌电流"改成"源电流"接法(LED 从引脚流向地),代码里哪一行要改?
欸欸!自查一下再走
- 您说说,"推挽"的推和挽,各自对应哪只 MOS 管、电流往哪个方向流?
- 开漏输出为什么"输出不了高电平"?这句话的电路含义,您能讲出来吗?
- 咱们再看施密特:它的迟滞带防的是什么?要是没有它,慢边沿信号会怎样?
- 您再看看 Blue Pill:LED 为什么低电平点亮?限流电阻限的是谁的流?
- PC13 的 3mA/2MHz 限制来自哪个设计决策?咱们
MODE=10的选择为什么刚刚好?