1. 课程导入
GPIO,全称 General-Purpose Input/Output,通用输入输出口。说白了,就是芯片上那些可以编程控制的引脚。你可以让它输出高电平或低电平,也可以读取外部信号是高还是低。
我刚开始做嵌入式那会儿,觉得 GPIO 不就是点个灯、读个按键嘛,有啥好学的?后来踩的坑多了才明白——GPIO 用不好,轻则信号不稳定,重则烧芯片。这一章,咱们就把 GPIO 的底裤扒干净。
1.1 GPIO 工作原理
每个 GPIO 引脚内部,其实是一堆 MOS 管、触发器和控制寄存器。你通过写寄存器,告诉芯片这个引脚是输入还是输出,输出什么电平。
一个典型的 GPIO 模块包含:
- 控制寄存器:配置方向(输入/输出)、模式(推挽/开漏)、上下拉等
- 数据寄存器:存放要输出的值,或读取到的输入值
- 输出驱动器:由 PMOS 和 NMOS 组成的推挽结构,或只有 NMOS 的开漏结构
- 输入缓冲器:通常是施密特触发器,用来整形信号
核心要点:GPIO 的输入输出,本质上是读写寄存器。写 1 输出高电平,写 0 输出低电平。读引脚就是读输入寄存器的值。
1.2 推挽输出与开漏输出
这是 GPIO 最核心的两个输出模式。我见过不少工程师搞混,结果项目翻车。
推挽输出(Push-Pull)
推挽输出内部有两个 MOS 管:上边的 PMOS 负责“推”,下边的 NMOS 负责“挽”。输出高电平时,PMOS 导通,NMOS 截止,引脚被拉到 VDD;输出低电平时,PMOS 截止,NMOS 导通,引脚被拉到 GND。
特点:
- 输出高低电平都很强,驱动能力好
- 不能将多个推挽输出直接连在一起——会打架,一个想拉高,一个想拉低,直接短路
- 适合驱动 LED、蜂鸣器、继电器等
开漏输出(Open-Drain)
开漏输出只有下边的 NMOS 管,上边是空的。输出低电平时,NMOS 导通,引脚拉低;输出高电平时,NMOS 截止,引脚处于高阻态——这时候需要外部上拉电阻把电平拉高。
特点:
- 可以实现“线与”功能:多个开漏输出连在一起,只要有一个输出低,总线就是低
- 可以输出比 VDD 更高的电压(通过外部上拉到其他电压)
- I²C 总线就是典型应用
| 对比项 | 推挽输出 | 开漏输出 |
|---|---|---|
| 内部结构 | PMOS + NMOS | 只有 NMOS |
| 高电平输出 | 强驱动,直接拉到 VDD | 高阻态,需外部上拉 |
| 低电平输出 | 强驱动,直接拉到 GND | 强驱动,直接拉到 GND |
| 多引脚并联 | 不允许 | 允许(线与) |
| 典型应用 | LED、普通信号输出 | I²C、电平转换 |
我的习惯:做 I²C 总线时,一定用开漏输出加外部上拉。曾经有个同事用推挽输出做 I²C,结果两个从机同时应答时直接短路,烧了一个芯片。
1.3 上拉电阻与下拉电阻
上拉电阻把引脚拉到高电平,下拉电阻把引脚拉到低电平。它们的作用是:
- 防止引脚浮空:输入引脚如果不接任何东西,电平是不确定的,容易受干扰
- 提供默认电平:按键按下时拉低,松开时靠上拉回到高电平
- 配合开漏输出:开漏输出高电平时,靠上拉电阻提供高电平
电阻值怎么选?我一般遵循这个原则:
- 4.7kΩ ~ 10kΩ:通用上拉/下拉,适合按键、复位引脚
- 1kΩ ~ 4.7kΩ:强上拉,适合高速信号或长线传输
- 10kΩ ~ 100kΩ:弱上拉,适合低功耗场景
注意:MCU 内部通常有可编程的上拉/下拉电阻,但阻值一般较大(30kΩ~50kΩ),驱动能力有限。需要强上拉时,还是得外接电阻。
1.4 GPIO 电气特性
这部分是硬核知识,也是容易出问题的地方。我见过太多因为电气特性没搞懂导致的故障。
关键参数
| 参数 | 说明 | 典型值(3.3V MCU) |
|---|---|---|
| VOH | 输出高电平的最小值 | ≥ 2.4V(负载下) |
| VOL | 输出低电平的最大值 | ≤ 0.4V(负载下) |
| VIH | 输入高电平的最小值 | ≥ 2.0V |
| VIL | 输入低电平的最大值 | ≤ 0.8V |
| IOL | 输出低电平时的最大灌电流 | 8~20mA(因引脚而异) |
| IOH | 输出高电平时的最大拉电流 | 8~20mA(因引脚而异) |
这里有个坑:VOH 和 VOL 是在特定负载电流下测的。你输出高电平,但接了重负载,电压会被拉低。我曾经用 GPIO 直接驱动一个 5V 继电器,结果电压被拉到 1.8V,继电器吸合不了,还差点烧了引脚。
驱动能力与负载
每个 GPIO 的驱动能力有限,一般不超过 20mA。整个芯片的总电流也有上限,比如 STM32F103 所有 GPIO 的总电流不能超过 150mA。
驱动 LED 时,一定要串限流电阻。计算公式:
R = (V<sub>OH</sub> - V<sub>LED</sub>) / I<sub>LED</sub>
举例:V<sub>OH</sub> = 3.3V,LED 压降 2.0V,电流 10mA
R = (3.3 - 2.0) / 0.01 = 130Ω
实际选 150Ω 或 220Ω
避坑指南:我曾经用 GPIO 直接驱动一个蜂鸣器,没加三极管,结果蜂鸣器声音很小,查了半天发现是驱动电流不够。后来加了个 NPN 三极管做开关,问题解决。
1.5 知识结构总览
下面这张图把 GPIO 的核心知识点串起来了。你对照着看,心里就有谱了。
这张图把 GPIO 的四个核心维度串起来了。你从中心出发,往四个方向看:工作原理是基础,输出模式是配置,上下拉是辅助,电气特性是约束。做项目时,这四个方面都得考虑到。