前言
回顾前面三篇博客,我们已经接触过几种 GPIO 模式:
| 博客 | 用到的 GPIO 模式 |
|---|---|
| STM32再出发 | 推挽输出(驱动 LED) |
| 三色LED流水灯 | 推挽输出(三个 LED) |
| 按键输入 | 上拉输入(KEY2 内部上拉)+ 浮空输入+外部上拉(KEY1 板载上拉) |
除了上述几种模式,GPIO还有其他的输入输出模式。这篇文章就是对于GPIO八大模式的总结和梳理,顺便把前几篇博客里实际用到的 GPIO 模式串联起来分析一下。
GPIO 内部结构速览
在拆解 8 种模式之前,先认识一下 GPIO 引脚内部的核心组件。
关键元件
| 元件 | 作用 |
|---|---|
| 保护二极管 | 钳位电压:引脚电压 > VDD 时电流引入 VDD,< VSS 时引入 VSS,防止高压损坏芯片 |
| 施密特触发器(TTL肖密特触发器) | 将模拟电压转换为干净的数字电平,具备滞回特性,有效抗噪声 |
| 上拉/下拉电阻 | 输入模式下决定悬空引脚的电平状态,约 40kΩ,可软件配置 |
| P-MOS | 输出驱动器的上管,导通时将引脚接到 VDD(输出高电平) |
| N-MOS | 输出驱动器的下管,导通时将引脚接到 VSS(输出低电平) |
| 输出寄存器 | 锁存 CPU 要输出的电平值 |
| 输入寄存器 | 锁存引脚上当前的电平值 |
GPIO 内部的工作模式,本质上就是控制这些开关元件的通断组合。不同的通断组合 = 不同的工作模式。
输入模式(4种)
输入模式的核心:数据从引脚 → 内部总线(CPU 读取)。
1. 浮空输入
内部状态: 上下拉电阻均断开,施密特触发器导通。
引脚状态: 完全由外部电路决定。如果引脚什么都不接,电平是不确定的——可能是高、可能是低、甚至可能是中间电平。
在 CubeMX 中: 选 GPIO_Input → Pull 选 No pull
实际例子: 按键输入博客里的 KEY1(PB12) 用的就是”浮空输入 + 外部上拉电阻”。板子上已经焊了一个上拉电阻把 PB12 拉到 VDD,所以引脚悬空时是确定的——高电平。按下按键接地,读到低电平。
2. 上拉输入
内部状态: 内部上拉电阻(约 40kΩ)接通到 VDD,施密特触发器导通。
引脚状态: 悬空时默认高电平。外部驱动为低电平时,可以读到低电平。
在 CubeMX 中: 选 GPIO_Input → Pull 选 Pull-up
实际例子: 按键输入博客里的 KEY2(PB13) 用的就是内部上拉。这个引脚板子上没有配外部上拉电阻,所以在 CubeMX 中配置 Pull-up,让芯片内部的电阻来负责拉高。功能和 KEY1 一样,只是上拉电阻的位置不同——一个在芯片外面,一个在芯片里面。
3. 下拉输入
内部状态: 内部下拉电阻(约 40kΩ)接通到 VSS,施密特触发器导通。
引脚状态: 悬空时默认低电平。外部驱动为高电平时,可以读到高电平。
在 CubeMX 中: 选 GPIO_Input → Pull 选 Pull-down
和上拉输入的关系: 上拉和下拉是对称的——上拉是电阻接到 VDD(默认高),下拉是电阻接到 VSS(默认低)。
4. 模拟输入
内部状态: 施密特触发器关闭(数字输入路径断开),引脚直接连接到 ADC 模块的模拟开关。
引脚状态: 不读高低电平,读电压模拟量。
在 CubeMX 中: 引脚功能选 ADC_INx(比如 ADC1_IN0),或直接选 GPIO_Analog
用途: ADC 采样。比如读取电位器电压、温度传感器输出等。后续学到 ADC 时会用到。
输出模式(4种)
输出模式的核心:数据从内部总线 → 引脚(CPU 写值出去),同时也可以回读引脚当前电平。
5. 推挽输出
内部状态: 输出寄存器控制 P-MOS 和 N-MOS 交替导通:
| 输出 | P-MOS | N-MOS | 引脚电平 |
|---|---|---|---|
| 1 | 导通 | 断开 | VDD(高电平) |
| 0 | 断开 | 导通 | VSS(低电平) |
在 CubeMX 中: GPIO_Output → Output Mode 选 Push-Pull
特点: 驱动能力强,高电平和低电平都能主动输出。这是最常用的输出模式。
实际例子: 前两篇博客所有的 LED 点灯代码全都是推挽输出。翻开 CubeMX 配置能看到:
1 | PA7 Output Mode: Push-Pull |
LED 需要足够的电流才能亮,推挽输出的驱动能力正好满足需求。
下面是推挽输出控制I/O口,输出高电平和低电平的电流流通图(假设I/O口连接一个小灯,小灯另一端连接GND)
6. 开漏输出
内部状态: P-MOS 始终断开(不工作),只有 N-MOS 受控:
| 输出 | P-MOS | N-MOS | 引脚电平 |
|---|---|---|---|
| 1 | 断开 | 断开 | 高阻态(引脚浮空) |
| 0 | 断开 | 导通 | VSS(低电平) |
在 CubeMX 中: GPIO_Output → Output Mode 选 Open-Drain
关键区别: 推挽能主动输出高电平,开漏不行。开漏输出高电平时引脚处于高阻态——必须靠外部上拉电阻才能拉高到想要的电压。
下面是开漏输出控制I/O口,输出高电平和低电平的电流流通图(假设I/O口连接一个小灯,小灯另一端连接来自外部的5V而非GND)
注意:此时需要使用5V容忍的I/O口,不能用普通的,否则会使上方的保护二极管长期导通,将5V引入电源中,造成损坏。
推挽输出 vs 开漏输出 对比
| 推挽输出 | 开漏输出 | |
|---|---|---|
| 高电平 | P-MOS 激活 N-MOS 断开,3.3V | P-MOS 断开 N-MOS 断开,由外部电路决定 |
| 低电平 | P-MOS 断开 N-MOS 激活,0V | P-MOS 断开 N-MOS 激活,0V |
| 优点 | 可以直接输出 3.3V | 配合外部电路更加灵活 |
| 缺点 | 只能输出 3.3V | 高电平实际是高阻态,无法输出电流 |
为什么需要开漏输出?两个经典场景:
场景一:电平转换
如果芯片是 3.3V 的,但想驱动一个 5V 的器件——开漏输出 + 外部上拉到 5V 就能实现。推挽输出去接的话,3.3V 的高电平可能不被识别为高电平。
场景二:I2C 通信的”线与”
多个器件共享一根数据线(SDA),任何一个器件都可以把总线拉低。如果其中一个输出高电平,另一个同时输出低电平,用推挽输出的话两个 MOS 管会”打架”(短路风险)。开漏输出+上拉电阻天然支持这种”谁都可以拉低”的结构。
7. 复用推挽输出
内部状态: 和推挽输出电路完全一样,只不过控制 P-MOS/N-MOS 的信号不再是输出寄存器,而是片上外设(USART、SPI、定时器等)。
在 CubeMX 中: 配置外设时自动设置(比如把 PA9 配成 USART1_TX,CubeMX 自动设为复用推挽)
实际例子: 以后配串口时,CubeMX 的提示里多半就是这个。
8. 复用开漏输出
内部状态: 和开漏输出电路完全一样,只不过控制 N-MOS 的信号来自片上外设。
在 CubeMX 中: 配置外设时自动设置(比如把 PB6 配成 I2C1_SCL,CubeMX 自动设为复用开漏)
实际例子: I2C 通信。如果使用硬件 I2C 外设(而不是软件模拟),SCL 和 SDA 引脚会被配置为复用开漏输出。
下面两张图为普通的输出和复用的输出的电流流经图
为什么没有”复用输入”模式?
留意到一个问题:输出模式有普通和复用两种,但输入模式只有 4 种,没有”复用输入”这个分类。
原因是输入模式下,普通输入和复用功能共用同一路信号——都通过施密特触发器,送到输入寄存器,同时也送给片上外设。
所以无论引脚工作在什么模式下(只要不是模拟输入),外设都能读到引脚的值。不需要额外的”复用输入”模式。
有例外:ADC 的模拟输入走的是独立路径(不走施密特触发器),所以模拟输入被划为独立的输入模式。
八大模式速查表
| 编号 | 模式 | 方向 | 核心特点 | 典型用途 |
|---|---|---|---|---|
| 1 | 浮空输入 | 输入 | 上下拉全关,电平完全由外部决定 | 外部已有上下拉电阻的按键 |
| 2 | 上拉输入 | 输入 | 内部接 VDD,默认高电平 | 无外部上拉的按键 |
| 3 | 下拉输入 | 输入 | 内部接 VSS,默认低电平 | 默认需为低电平的输入 |
| 4 | 模拟输入 | 输入 | 绕开施密特触发器,直通 ADC | ADC 采样 |
| 5 | 推挽输出 | 输出 | P/N-MOS 交替,可主动输出高低 | 驱动 LED、普通数字信号 |
| 6 | 开漏输出 | 输出 | 只有 N-MOS,高阻态需外部上拉 | I2C、电平转换 |
| 7 | 复用推挽 | 输出 | 信号源改由外设控制 | 串口 TX、PWM、SPI |
| 8 | 复用开漏 | 输出 | 外设控制 + 开漏特性 | 硬件 I2C |
从前面三篇博客回看 GPIO 配置
第一篇:STM32再出发 — PA7 推挽输出
1 | // CubeMX 配置:PA7 → GPIO_Output, Push-Pull, No pull, Low speed |
LED 是纯数字负载,只需要开关两个状态就够。推挽输出的高电平驱动电流足以点亮 LED。
第二篇:三色LED流水灯 — 三个推挽输出
1 | PB0 → Push-Pull (LED_RED) |
三个 LED 都一样,推挽输出 + 状态机控制亮灭组合。没有特殊情况需要特殊模式。
第三篇:按键输入 — KEY1 浮空输入,KEY2 上拉输入
1 | // KEY1(PB12):浮空输入,板载外部上拉 → 按下读低电平 |
这里就体现了两种输入模式的选择差异——外部已有上拉电阻的用浮空输入,没有的就用内部上拉。 同一个功能(按键检测),因为硬件设计不同,选择的 GPIO 模式也不同。
进阶:一些值得思考的问题
1. 推挽输出能同时输出高和低吗?
不能。 P-MOS 和 N-MOS 是交替工作的,不可能同时导通。如果两者不小心同时导通了(称为”穿通”),VDD 和 VSS 直接短路,电流瞬间增大,芯片会发热甚至烧毁。幸好 CubeMX 和 HAL 库会处理好这些,不需要我们操心。
2. 开漏输出为什么不内置上拉电阻?
因为上拉电阻的值需要根据应用场景决定。I2C 总线通常用 4.7kΩ,高速时会用 1.5kΩ,低功耗场合会用到 10kΩ。ST 不知道你的应用场景,所以把选择权留给了用户。
3. GPIO 速度(Speed)选 Low 还是 High?
与 GPIO 模式无关但值得注意。在 CubeMX 配置里有个 Maximum output speed 选项:
| 速度等级 | 适用场景 |
|---|---|
| Low (2MHz) | LED、按键、普通 GPIO 信号 |
| Medium (10MHz) | 串口、中等频率信号 |
| High (50MHz) | SPI、高速通信 |
速度越高,功耗越大、电磁干扰越强。所以对于 LED 这种低速应用,选 Low 就够了,没必要开 High。前两篇博客里选的 Low 是正确的选择。
总结
学完这 8 种模式再回头看 CubeMX 的引脚配置界面,选项就不再是零散的下拉菜单了——每个选项对应的是内部某条电路的开关状态:
- 选
Input还是Output→ 决定输入驱动还是输出驱动接入引脚 - 选
Pull-up/No pull/Pull-down→ 决定内部上拉/下拉电阻是否接通 - 选
Push-Pull/Open-Drain→ 决定 P-MOS 是否参与工作 - 选
GPIO/Alternate→ 决定控制信号来自寄存器还是外设
理解了内部电路的结构,CubeMX 配置就不再是”乱填的”,而是——我知道我配置了什么,也知道为什么这么配。
学完这 8 种模式之后,下一步就可以学习中断(EXTI)了——当按键不需要靠 while 循环轮询,而是按下时 CPU 主动响应,就是中断的用武之地。这也是按键输入博客末尾提到的”进阶思路”。
参考资源
- keysking STM32 教程(B站) — 第5集 GPIO 内部那些事
- 波特律动文档站
- 上一篇:STM32按键输入控制小灯亮灭
- STM32 再出发:工具链搭建
- STM32 参考手册 RM0008(STM32F10xxx 参考手册) — GPIO 相关章节










