前言
文章以STM32F103ZET6芯片为例来介绍
一、宏观认识
1. GPIO是什么
GPIO 是 General Purpose Input/Output 的简写,字面含义就是 "通用输入 / 输出" 。
是一个 MCU 内部,用来做输入输出 的控制器电路。

2. GPIO在哪里
GPIO属于MCU中的一个片上外设!!

3. 理解GPIO输入输出
- 输入输出的是什么?
本质就是输入输出高低电平。**为什么要输出?**这些高低电平,在上层语言层解释就是 0/1,在下层硬件外设角度,就会被视为 MCU 控制外设的手段,比如,输出高电平,会被 LED 解释为要求点亮 LED,会被电机解释成为电机正转,会被串口接收方解释为传送 1 等等,输出低电平,则反之。
**为什么要输入?**单片机的核心作用是 "控制 ",控制相关外设,就必须先获取外设相关的数据,比如需要知道开关是否被闭合,传感器是否感受到数据变化,设备是否处于休眠等,然后根据外设状态数据变化,在通过输出,控制外设或者报告给用户等。
所以:输入输出的本质是输入输出高低电平 (手段),达到获取外设信息,控制外设的目的。
4. 理解GPIO通用
- 为什么叫做通用输入输出?
"通用",意思就是一个东西被发明出来,就是未来给 "大家" 用的。英语被发明出来,英国人可以用,美国人可以用,我们中国人也可以用,所以,英语叫做世界 "通用" 语言。
同样的道理,GPIO 是通用输入输出,GPIO 自己可以输入输出高低电平,未来 MCU 内集成了其他外设控制器,而其他外设控制器,也要输出高低电平,来控制外设怎么办?
难道给每一个外设控制器也焊接输入输出高低电平的硬件电路吗?这样做势必会增加复杂度,这样无疑会隐形的增加单片机成本,包括功耗。
所以,GPIO 都已经做了输入输出高低电平了,其他外设控制器你就别凑热闹了,直接用 GPIO 不就好了。所以, GPIO 叫做通用输入输出。
✨"通用",意思就是一个东西被发明出来,就是未来给 "大家" 用的。这里的大家,就是集成在 MCU 中的各种外设控制器或者与用来控制外设的硬件电路。
✨ 我们把其他外设控制器,直接使用 GPIO 硬件电路来进行输入输出的方式,叫做复用 GPIO


5. MCU内部的GPIO

名词说明:
**Pin:**就是引脚的意思
Port:端口的意思,PORT 原意为 "港口",在计算机科学中引申为 "数据交换的入口或出口",现代微控制器(如 STM32)继承了这一概念,将一组 GPIO 引脚称为 "GPIO PORT"(如 GPIOA、GPIOB),因为它们本质上是芯片与外部世界的 "数据交换接口"。
为什么不叫 GPIO Group,而叫做 GPIO Port ?Group 只能体现分组概念,体现不出来数据交换的概念。Port 在计算机领域,就有数据交换的概念成分。
细节:
- 所有的 GPIO 控制器,都是挂接在 APB2 桥设备上的
- 为了管理一个一个的 pin (引脚),MCU 把 pin 划分成为了组,叫做 GPIO Port,STM32F103ZET6 一共 7 组,分别是 GPIOA~GPIOG
- 每一个 GPIOX (X 范围 A‑G ),都管理 0,15 个 Pin
- MCU 管理 GPIO Pin 的方式,是层状的,多叉树型结构
二、IO端口位电路结构

注意:
GPIO 端口位是指 GPIO 端口中单个引脚的控制单元,例如 PA0、PB3 等
每一个 Pin 对应到 MCU 内部,都会存在一套这样的硬件结构
每一个 Pin,都可以独立的进行输入和输出 换句话说
所以,我们搞清楚了一个 Pin 是如何输入输出的,那么其他 Pin 也就会了
1. IO输入路径理解

简化理解:

2. IO输出路径理解

简化输出理解:

✨结论:
片上外设,其实是 MCU 内部的各种外设控制器,或者控制电路
宏观上,一定要时刻记着,MCU != CPU,MCU 内部是包含了片上外设控制器 + ARM‑CPU 的
GPIO 被设计出来,不是只让 ARM‑CPU 进行 IO 读写数据的,而是让所有片上设备进行 IO 的,这就是为什么 STM32 芯片引脚中,大部分引脚都是 GPIO Pin 的原因,也是我们学习单片机,需要优先学习 GPIO 的原因,因为他为所有片上外设提供 IO 能力
未来我们学习的其他片上外设,不用单独设计 IO 接口电路,直接复用 GPIO 即可,这样可以大大减少 MCU 内部硬件电路设计的复杂度,减少功耗,最终表现在单片机价格上,价格便宜了,应用场景就会更丰富,因为各种智能场景用得起 (当然这只是原因之一,重点在感受生态问题上)。
三、IO端口保护
端口钳位保护

双二极管钳位电路

- 二极管导通压降一般在 0 点几伏 (常见的基本都在 0.6~0.7V 左右)
为了说明该问题,我们假设如下数值:
Vdd = 3.3V,Vss = 0V,二极管导通电压是 0.7V(二极管是一个元器件,自身也存在电阻,自身会承压)


结论:
当 输入电压 >=(Vdd + 保护二极管导通压降)时,上路二极管导通,这时被钳位在 Vdd + 二极管导通压降
当 输入电压 <=(Vss‑保护二极管导通压降)时,下路二极管导通,这时被钳位在 Vss‑二极管导通压降
✨思考:
- 上面的数值具体是多少不重要,**重要的是,**因为有了钳形保护二极管,就可以有效防止不合理电压输入到针脚,进而形成大电流,导致击穿 MCU 内部元器件,本质是一种保护电路!
四、GPIO 工作模式
GPIO 主要负责 MCU 的输入和输出,也就是 I/O 问题,GPIO 的输入、输出拥有多种工作模式:
输出模式
- 通用推挽输出
- 通用开漏输出
- 复用推挽输出
- 复用开漏输出
输入模式
- 浮空输入
- 上拉输入
- 下拉输入
- 模拟输入
先暂时不论这些模式具体含义,后面会逐一讲解,先从宏观层面理解。
✨为什么 GPIO 会有这么多 I‑O 模式?
- GPIO 不止能够由 ARM‑CPU 直接控制输入输出,还可供其余片上外设调用,GPIO 属于共用资源。
- 片上外设种类繁多、使用场景各不相同,因此 GPIO 需要丰富的 I/O 功能适配各类外设。
- 类比键盘:只打游戏只需要 WASD 按键;但是键盘还要用于打字、聊天,因此按键数量很多,适配全部场景。
总结:GPIO 具备多种 I/O 模式,目的是满足各类片上外设、不同使用环境下的引脚需求。
五、输出部分电路
1. 输出部分电路
输出模式下,需要研究 GPIO 端口内部的输出硬件单元。
输出部分包含:输出数据寄存器、复用功能输出选择、输出驱动器、P‑MOS、N‑MOS 管,最外侧为双向保护二极管。

2. 四种输出模式
输出一共四种模式:
- 通用推挽输出
- 通用开漏输出
- 复用推挽输出
- 复用开漏输出
| 推挽 | 开漏 | |
|---|---|---|
| 通用 | 通用推挽输出 | 通用开漏输出 |
| 复用 | 复用推挽输出 | 复用开漏输出 |
- 通用:由 ARM‑CPU 直接操控 GPIO 引脚输出电平。
- 复用:MCU 内部片上外设接管 GPIO 引脚,外设利用引脚完成输入输出。
3. 理解输出电路
3.1 简化输出电路图

输出寄存器为多位,这里简化成单比特方便理解。
复用器
- 作用:在多路输入信号当中选出一路作为有效输出信号。
- 用途:决定引脚控制权归属,是 CPU 直接控制,或是交给片上外设。
输出控制
接收控制电平,驱动后端 MOS 管的栅极,管控 MOS 管通断,转换成具备驱动能力的引脚电平。
3.2 P‑MOS 和 N‑MOS

名词释义
- MOS:Metal‑Oxide‑Semiconductor Field‑Effect Transistor(金属氧化物半导体场效应管),简写 MOSFET,再简写:MOS,这个不用记
- P‑MOS:P‑channel Metal‑Oxide‑Semiconductor(P 沟道金属氧化物半导体),这个不用记
- N‑MOS:N‑channel Metal‑Oxide‑Semiconductor(N 沟道金属氧化物半导体),这个不用记
- P:positive,积极的,正向的
- N:negative,消极的,负面的,反向的
**P‑MOS 和 N‑MOS 是本质是:**本质是一个开关。
MOS 引脚定
- **S:**source,源极,"Source" 意为 "源头",指这里是载流子(电子或空穴)的来源
- **D:**Drain,漏极,"Drain" 意为 "漏出",指载流子最终从这里流出器件,D 当做 Destination 看貌似也行,但是 Destination 是目的地的意思,MOS 管往往不是目的地,而是一个电流路过的器件,所以官方 Drain 更好一些。
- **G:**Gate,栅极,Gate 就是门的意思,预示着开关的开启和关闭由它控制

导通特性
- P‑MOS:电流方向 S → D
- N‑MOS:电流方向 D → S
- P‑MOS 适合传输高电平;N‑MOS 适合传输低电平。
- 栅极电平改变开关的开启、关闭。
- 被控制电流方向从 Source 流向 Drain,就是 P‑型 MOS 管
- 被控制电流方向从 Drain 流向 Source,就是 N‑型 MOS 管
- positive,积极的,正向的,所以符合 S‑>D,顺势而为
- negative,消极的,负面的,反向的,所以符合 D‑>S,逆行行舟
- 但是,无论是从 S‑>D,还是从 D‑>S,电路必须是导通的,上面的图,默认都是没有导通的

那么对于 P‑MOS 和 N‑MOS 管,如何导通呢?给 G 极施加一个小电流,就可以导通。
P‑MOS 导通过程

- **施加电压的过程,就是一个闭合开关的过程,**施加力的方向,和红色箭头方向一致,这个就是 positive,积极的,正向的,也是顺势而为的,所以叫做 P‑MOS 管。
N‑MOS 导通过程

**施加电压的过程,就是一个闭合开关的过程,**施加力的方向,和红色箭头方向相反,与之对抗,这个就是 negative,消极的,负面的,反向的,对抗趋势,逆流而上,所以叫做 N‑MOS 管。
✨结论:P‑MOS 和 N‑MOS 的本质是什么?
是一个开关为什么要有 P‑MOS 和 N‑MOS?
通过小电压,通过控制开关的手段,达到控制大电流的目的

✨注意:
GPIO 输出电路图中,上方是 P‑MOS,下方是 N‑MOS
两者 D 极相接,P‑MOS S 极接 VDD (3.3V),N‑MOS S 极接地 (GND)
3.3 再次简化输出电路图

六、通用推挽输出(Push‑Pull Output)
**核心思想:**交替闭合或者开启 P‑MOS 和 N‑MOS
前期基础知识点
- P‑MOS 和 N‑MOS 的本质是什么?
是一个开关- 为什么要有 P‑MOS 和 N‑MOS?
通过小电压,通过控制开关的手段,达到控制大电流的目的注意:
- GPIO 输出电路图中,上方是 P‑MOS , 下方是 N‑MOS
- 两者 D 极相接, P‑MOS S 极接 VDD (3.3V), N‑MOS S 极接地 ( GND , 当成 0V 就可以)
1. 输出高电平
输出数据寄存器写 1,闭合 P‑MOS,断开 N‑MOS,输出高电平


2. 输出低电平
输出数据寄存器写 0,断开 P‑MOS,闭合 N‑MOS,输出低电平


通用推挽输出的名称来源于该电路的工作原理
- 使用一对互补的晶体管(通常是 CMOS 工艺的 P‑MOS 和 N‑MOS 管)来输出高电平 (提供电流,"推") 或 输出低电平**(吸收 / 拉取电流,"挽")。**
- 本质是交替闭合断开,P‑MOS 和 N‑MOS 开关,让外部引脚接入 VDD 或者接地,进而对外呈现出高电压和低电压,然后因为电路通路,形成有输出电流 (推) 和吸收 (挽) 电流的效果


如果 P‑MOS 和 N‑MOS 都导通会是怎么的情况呢?
注意:
- VDD 就会和 GND (Vss) 接通,这就会导致短路烧毁电路
- 因此 "输出控制" 单元必须保证 2 个 MOS 管不能同时导通
3. 推挽输出过程
- 当 ARM‑CPU 执行用户的代码,用户代码要求向数据寄存器写入 1
- ARM‑CPU 执行用户代码,向数据寄存器写入 1
- 复用器选择信号输入源是数据寄存器
- 输出控制器获取到数字 1,把数字 1 进行解释,给 P‑MOS 管施加电压,N‑MOS 什么都不做
- P‑MOS 感受到电压,导通
- 外部引脚接入 VDD,对外输出高电平
- 写 0 同上
4. MOS 管导通条件(了解)
到这里,我们已经理解了推挽输出,P‑MOS 和 N‑MOS 的作用和基本原理,但是仍旧有一个问题,那就是 G 栅极电压给多大,就能开启开关。这里需要引入新的名词
- 对任意 MOS 管而言 (P‑MOS/N‑MOS), MOS 管导通需要的电压阈值我们定义为 Vth,Voltage Threshold,也叫做阈值电压 ,这个电压一般范围是 0.3V~1.0V
- 源极电压定义为 Vs,栅极电压定义为 Vg
- 对任意 MOS 管而言 (P‑MOS/N‑MOS), **导通条件:**取决于 S 源极和 G 栅极的电压差,是否超过 Vth,和 D 漏极无关
- 对于 P‑MOS 而言,当 Vs‑Vg>Vth 时,MOS 管 SD 导通(饱和),否则 SD 断开(截止)
- 对于 N‑MOS 而言,当 Vg‑Vs>Vth 时,MOS 管 SD 导通(饱和),否则 SD 断开(截止)
- 对于 MOS 而言,开关速度非常高,达到 ns 级
推导出如下结论:
- 对于 P‑MOS,Vs − Vg 电压差超过 Vth,就导通
- 对于 N‑MOS,Vg − Vs 电压差超过 Vth,就导通
5. 最终总结
- 推挽模式下,向输出寄存器写 1/0 的本质:是让输出控制器选择 P‑MOS,还是 N‑MOS,进而输出电压,打开指定 MOS 管。
简易原理概括
- P‑MOS:源极接电源 VDD;栅‑源压差达标之后导通,向引脚推出电流、输出高电平
- N‑MOS:源极接 GND;栅‑源压差达标之后导通,把引脚电流拉入地、输出低电平
- 硬件互锁保证两只 MOS 不会同时导通,规避电源对地短路。
七、通用开漏输出 (Open‑Drain Output)
✨ 开漏输出核心思想: 去掉 P‑MOS,让 P‑MOS 永远都关闭

所以,开漏模式下,我们只考虑

所以,在开漏模式下,MCU 针对特定引脚的输出,都是该引脚对应的 N‑MOS 的漏极输出

✨ 结论:
- 向输出数据寄存器写 1 ,最终表示的是 N‑MOS 断开
- 向输出数据寄存器写 0 ,表示 N‑MOS 管闭合
1. 输出低电平
输出数据寄存器写 0 ,N‑MOS 闭合,输出低电平

2. 输出高阻抗
输出数据寄存器写 1 ,N‑MOS 断开,输出高阻态

✨ 所谓高阻抗,只是一种说法,理解为: MCU 和外部针脚彻底断开,相当于开路了,或者 N‑MOS D 漏极和外部引脚互相悬空了
对于针脚而言,如果内部 MCU 断开了和外部引脚的连接,可以把 MCU 认为成为一个阻值无穷大的设备,我们把这种情况,叫做输出高阻抗。

✨ 结论:
- 开漏模式,输出只能输出低电平和高阻抗,无法输出高电平
3. 开漏模式输出高电平
通过以上原理分析,可以知道:开漏输出电路有输出低电平和开路(高阻)2 个状态。
那如何才能输出高电平呢?
**通过上拉电阻将 I/O 口接通到上拉的电压。**因为 MCU 内部电路已经设计好,所以往往这个所谓的上拉的电压,必须是开发板设计者,在 MCU 外部,根据自己的需求设计的。
✨ 注意:
单片机内部,不是只有 MCU 内部有 VDD 供电,其他 MCU 外部的设备,或者 MCU 内部的其他设备,也可能会有自己的供电电源提供高电压。
这就好比,你家 (单片机) 里有很多家用电器 (外设控制器和外设),不止电视要供电,冰箱洗衣机也要的
那么,在开漏模式下,要输出高电平,就必须在引脚位置设置上拉电阻,来提供高电压了。

新增上拉电阻之后:
- 输出数据寄存器写 0,N‑MOS 闭合,输低电平,图略
- 输出数据寄存器写 1,N‑MOS 断开,输出高阻抗,外部引脚在外部上拉电阻的影响 (或者上拉) 下,输出高电平

4. 为什么开漏输出高阻抗之后,引脚就是高电平?

为了方便解释,为上图中的相关电阻进行命名:
- 上拉电阻的阻值是 R_PULL
- 引脚阻值是 R1,其实引脚就是导线,这个 R1 是无限趋近于 0Ω 的,后续我们不需要研究它,这里进行命名只是为了表示方便
- 开路位置电阻命名为 R2 , 阻值无穷大
是时候,引入我们高中学过的知识了,欧姆定律: V = I * R。 因为整个电路通路,从 VDD 到 GND
- 整个电路的电流 I = 3.3V / (R_PULL+ R1 + R2) , 因为 R2 接近于无穷大,所以 I ≈ 0
- 而引脚位置的电压 V 引脚 = 3.3V − 上拉电阻处的承压 = 3.3V − I * R_PULL
- 因为 I≈0,所以 V 引脚 = 3.3V − I * R_PULL = 3.3V − 0 * R_PULL = 3.3V
- 所以,引脚处电压就是 3.3V,那么输出就是高电平
**OK啊,所以我们现在回答了为什么开漏输出高阻抗之后,引脚就是高电平,**可是上面的推断我们真的理解了吗?当然,也不知道具体哪里不清楚,反正就是感觉不透彻。
那么,接下来让我提出并解决一些问题,看看能不能透彻的理解。我们把视角转到这张图:

✨ 奇怪的问题?
真实情况是开路了,开路就没有电流啊,即电流 I=0,根据欧姆定律, V = I * R,那么整个电路结构中,都没有电压,包括引脚处,这点很明显和上面的结论是冲突的啊?
问题出在哪里呢?一块裸的电池,没有接入到任何电路中,其实就是自身开路,正极有电压吗?
答案是当然有!

电压的本质是两端 (正负等) 电势差,开路情况也可能存在
就好像水龙头,不打开,也有水压一样
其实,开漏输出下,高阻抗输出,对应的开路下,引脚处是有电压的。上述问题其实是出在对于欧姆定律的理解有偏差上
欧姆定律可以用来计算整个电路回路的电流, 但是,计算的电压,并不是电路中某个设备 (电阻) 处的电压绝对值,而是这个设备在整个电路中承担的电压差!!
有了上面对欧姆定律的深刻理解,然后我们再回过头看这张图:

**我们就能理解为什么引脚 (就是导线) 处的电压:**V 引脚 = 3.3V − I * R_PULL = 3.3V − 0 * R_PULL = 3.3V
5. 为什么要上拉电阻
开漏输出不仅仅要考虑 N‑MOS 断开输出高阻抗的问题,电路设计上,还要考虑 N‑MOS 闭合接地的情况

如果没有上拉电阻

设置上拉电阻

6. 为什么叫上拉电阻
⭐ 在开漏输出模式并且有外部上拉电阻的情况下:
如果 N‑MOS 管断开,MCU 输出高阻抗,那么引脚输出的就是外部上拉电压 3.3V,输出高电平
如果 N‑MOS 管闭合,外部引脚接地,输出低电平
在开漏模式,MCU 默认只能输出低电平和高阻抗
所以外部接入电阻 + 高电压,在保证电路安全的情况下,就可以成功让开漏模式输出高低电平了,而输出高电平,是被外部电阻 + 高电压拉起来的,我们把这个电阻就叫做上拉电阻。
上拉电阻的阻值一般多少合适? 4.7kΩ~10kΩ,这个不做解释
八、复用推挽输出

理解了通用推挽输出,复用推挽输出自然也就懂了,只不过是从CPU的输出,变成了其他片上外设的输出。
九、复用开漏输出

理解了通用开漏输出,复用开漏输出自然也就懂了,只不过是从CPU的输出,变成了其他片上外设的输出。
