输入输出模式
输入模式 (Input)
1. GPIO_Mode_AIN (Analog In - 模拟输入)
- 用途: ADC 专用。
- 原理: 此时 GPIO 的数字电路全部断开,引脚直接连到内部的 ADC 模块。
- 类比: Stream 流。不处理数据,直接管道传输。
2. GPIO_Mode_IN_FLOATING (Floating In - 浮空输入)
- 用途: 串口接收 (RX) 或 I2C 数据线。
- 原理: 上下都不接电阻,电压完全由外部电路决定。
- 类比: 没有任何默认值的变量
let a;。
3. GPIO_Mode_IPD (Input Pull-Down - 下拉输入)
- 用途: 外部设备接高电平时用。
- 原理: 内部接个电阻到 GND。
- 类比:
function(a = false)。
4. GPIO_Mode_IPU (Input Pull-Up - 上拉输入)
- 用途: 外部设备接低电平时用(比如按钮)。
- 原理: 内部接个电阻到 3.3V。
- 类比:
function(a = true)。
输出模式 (Output)
输出模式是初学者最容易晕的地方。你只需要把它看作 “控制权” 和 “电路结构” 的排列组合。
组合维度
维度 A:谁来控制引脚?
- 通用 (General): CPU 写代码 (GPIO_SetBits) 控制 → 手动挡。复用 (Alternate
- Function - AF): 片上外设 (串口、I2C、PWM) 自动控制 → 自动挡。
维度 B:电路性格是啥?
- 推挽 (Push-Pull): 强硬 (0/1)。
- 开漏 (Open-Drain): 软弱 (0/悬空)。
1. GPIO_Mode_Out_PP (通用推挽输出) —— 最常用
- 组合: 手动挡 + 强硬。
- 场景: 点灯、继电器、蜂鸣器。CPU 说亮就亮,说灭就灭。
2. GPIO_Mode_Out_OD (通用开漏输出) —— 较少用
- 组合: 手动挡 + 软弱。
- 场景: 软件模拟 I2C。或者是你希望输出 5V(外部接上拉电阻到 5V),但 CPU 只能出 3.3V 时。
3. GPIO_Mode_AF_PP (复用推挽输出) —— 常用
- 组合: 自动挡 + 强硬。
- 场景: 串口发送 (TX)、PWM 输出、SPI。
- 解释: 你把控制权交给了“串口控制器”,它内部也是数字电路,也需要强电平来传输信号,所以是 PP。
4. GPIO_Mode_AF_OD (复用开漏输出)
- 组合: 自动挡 + 软弱。
- 场景: 硬件 I2C。
- 解释: I2C 协议要求总线必须是“开漏”的(防止短路),同时你又想用 STM32 内部的“I2C 硬件控制器”来自动发波形,所以必须选这个模式。
总结图表
| 序号 | 宏定义 | 中 文 名 | 核心逻辑 (谁控制 + 怎么输出) | 典型场景 |
|---|---|---|---|---|
| 1 | AIN | 模拟输入 | 关闭数字功能 | ADC 电压采集 |
| 2 | IN_FLOATING | 浮空输入 | 随波逐流 | 串口 RX / 必须外部有电阻 |
| 3 | IPD | 下拉输入 | 默认为 0 | 按键 (另一端接3.3V) |
| 4 | IPU | 上拉输入 | 默认为 1 | 按键 (另一端接GND) |
| 5 | Out_PP | 通用推挽 | CPU 控制 + 强输出 | LED / 蜂鸣器 / 继电器 |
| 6 | Out_OD | 通用开漏 | CPU 控制 + 弱输出 | 软件模拟 I2C / 电平转换 |
| 7 | AF_PP | 复用推挽 | 外设控制 + 强输出 | PWM / 串口 TX / SPI |
| 8 | AF_OD | 复用开漏 | 外设控制 + 弱输出 | 硬件 I2C |
“避坑指南”
坑1:开漏输出 (OD) 忘了接上拉电阻
- 现象:你写
GPIO_SetBits想输出高电平,结果用万用表一量,电压只有 0.x 伏,或者完全没电压。 - 原因:选了
GPIO_Mode_Out_OD,但外部没接电阻。单片机此时处于“断路”状态,当然没电。 - 解决:改成推挽输出,或者外部加电阻。
坑2:读引脚状态,读错了寄存器
- 场景:你想知道自己刚才让这个引脚输出了什么。
- 错误:去读 IDR (Input Data Register)。
- 虽然大部分时候读 IDR 也能读到输出状态,但如果外部电路短路了(比如你输出高,外部被强行拉低),IDR 读到的是实际电压(低),而不是你想输出的(高)。
- 正确:应该读 ODR (Output Data Register)。
坑3:原子操作 (BSRR vs ODR)
- 场景:你要同时控制 8 个 LED 里的第 3 个。
- 普通写法:
ODR = ODR | 0x04;(读-改-写)。- 风险:如果在“读”和“写”之间发生了中断,中断里修改了其他 LED 的状态,等你回来写入时,会把中断里的修改覆盖掉。
- 高手写法:使用 BSRR (Bit Set/Reset Register)。
- 这是一个“只写”寄存器。写 1 有效,写 0 无效。
BSRR = 0x04;这一句指令直接生效,不需要读回原来的值,完全避免了被中断打断的风险。这就是原子操作。
坑4:速度配置 (GPIO Speed)
- GPIO 初始化结构体里通常有个
GPIO_Speed(2MHz, 10MHz, 50MHz)。 - 误区:所有都选最快的 50MHz!
- 真相:速度越快,信号边沿越陡峭,噪声和电磁干扰 (EMI) 越大,功耗也越高。
- 建议:点个 LED 用 2MHz 足够了;只有 SPI、PWM 这种高速信号才开 50MHz。
总结
- GPIO 没标志位,除非当外部中断用(看 EXTI_PR)。
- 推挽 (Push-Pull) 是大力士,能推能拉,通用首选。
- 开漏 (Open-Drain) 是软脚虾,只能拉低,输出高电平要靠外部电阻(I2C 专用)。
- BSRR 是操作 GPIO 的神器,保证操作不会被中断搞乱。