GPIO输入输出

GPIO输入输出
Li-OhhGPIO输入输出理论
一 GPIO在系统结构的位置:
可以看到GPIOA GPIOB GPIOC GPIOD GPIOE GPIOF GPIOG基本所有的GPIO都在APB2(高速外设总线2)上,因为APB2为高速、对性能要求高的外设设计最大频率为72MHz而APB1(高速外设总线1)为低速、低功耗外设设计最大频率为36Mhz,因为GPIO外设是常用外设且需要传输速度更高所以都会在APB2上,而我们学习的单片机芯片为STM32F103C8T6所以只有四个GPIO外设分别是GPIOA GPIOB GPIOC GPIOD
二 GPIO模式(8种模式):
输出模式:
- 推挽输出 (可出书引脚电平,高电平接VDD,低电平接VSS)
- 开漏输出 (可输出引脚电平 高电平为高阻态,低电平接VSS)
- 复用推挽 (由片上外设控制,高电平接VDD,低电平接VSS)
- 复用开漏 (由片上外设控制,高电平为高阻态,低电平接VSS)
输入模式:
- 浮空输入 (可读取引脚电平,若引脚悬空,则电平不确定)
- 上拉输入 (可读取引脚电平,内部连接上拉电阻,悬空时默认高电平)
- 下拉输入 (可读取引脚电平,内部连接下拉电阻,悬空时默认低电平)
- 模拟输入 (GPIO无效,引脚直接接入内部ADC)
详细的8种输出模式内容与解释都在我下面的思维导图PDF中,可在PDF中查看
三 LED与蜂鸣器简介
LED:发光二极管,正向通电点亮,反向通电不亮
有源蜂鸣器:内部自带振荡源,将正负极接上直流电压即可持续发声,频率固定
无源蜂鸣器:内部不带振荡源,需要控制器提供振荡脉冲才可发声,调整提供振荡脉冲的频率,可发出不同频率的声音
硬件电路(左面是LED灯 右面是蜂鸣器)
四 按键与传感器简介
按键:常见的输入设备,按下导通,松手断开
按键抖动:由于按键内部使用的是机械式弹簧片来进行通断的,所以在按下和松手的瞬间会伴随有一连串的抖动
传感器模块:传感器元件(光敏电阻/热敏电阻/红外接收管等)的电阻会随外界模拟量的变化而变化,通过与定值电阻分压即可得到模拟电压输出,再通过电压比较器进行二值化即可得到数字电压输出
硬件电路(左面四个是按键 右面是传感器)
五 总结
1. GPIO 硬件结构综述
在 STM32 中,GPIO 挂载在 APB2(高速外设总线)上。理解标准库配置前,必须先看懂其内部等效电路。
- 输入路径: 信号经过保护二极管 -> 上/下拉电阻 -> 施密特触发器 -> 输入数据寄存器(IDR)。
- 输出路径: 输出数据寄存器(ODR)-> 控制电路 -> P-MOS/N-MOS 管 -> 外部引脚。
2. 标准库中的 8 种工作模式
标准库通过枚举类型 GPIOMode_TypeDef 定义了 8 种模式:
| 模式名称 (GPIOMode_TypeDef) | 对应电路状态 | 应用场景 |
|---|---|---|
| GPIO_Mode_AIN | 模拟输入 | ADC 采集、低功耗模式 |
| GPIO_Mode_IN_FLOATING | 浮空输入 | 读取外部驱动好的信号(如 UART RX) |
| GPIO_Mode_IPD | 下拉输入 | 检测高电平触发的按键 |
| GPIO_Mode_IPU | 上拉输入 | 检测低电平触发的按键(最常用) |
| GPIO_Mode_Out_OD | 开漏输出 | I2C 通信、电平转换(5V/3.3V 互连) |
| GPIO_Mode_Out_PP | 推挽输出 | 驱动 LED、普通数字开关信号 |
| GPIO_Mode_AF_OD | 复用开漏 | I2C 总线的 SCL/SDA 引脚 |
| GPIO_Mode_AF_PP | 复用推挽 | SPI、PWM、UART TX 引脚 |
3. 标准库开发“四部曲”(核心逻辑)
在标准库中,初始化一个 GPIO 的代码逻辑非常固定:
第一步:开启时钟 (RCC)
STM32 为了省电,所有外设时钟默认关闭。GPIO 挂在 APB2 总线上。
C
1 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); |
第二步:定义初始化结构体
C
1 | GPIO_InitTypeDef GPIO_InitStructure; |
第三步:配置结构体成员
- GPIO_Pin: 选择引脚(
GPIO_Pin_0~GPIO_Pin_15或GPIO_Pin_All)。 - GPIO_Mode: 选择上述 8 种模式之一。
- GPIO_Speed: 选择输出速度(
10MHz,2MHz,50MHz)。注:仅输出模式有效。
第四步:调用初始化函数
C
1 | GPIO_Init(GPIOA, &GPIO_InitStructure); |
4. 常用操作函数对比
标准库提供了非常直观的位操作函数:
- 输出高电平:
GPIO_SetBits(GPIOA, GPIO_Pin_5); - 输出低电平:
GPIO_ResetBits(GPIOA, GPIO_Pin_5); - 写入特定值:
GPIO_WriteBit(GPIOA, GPIO_Pin_5, Bit_SET / Bit_RESET); - 读取输入值:
uint8_t val = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5); - 读取输出回显:
GPIO_ReadOutputDataBit()(读取 ODR 寄存器,判断当前输出状态)。
5. 进阶:BSRR 寄存器与原子操作
为什么标准库里有 GPIO_SetBits 这种函数,而不是直接修改 ODR 寄存器?
- ODR (Output Data Register): 读-改-写操作。如果在修改 ODR 时发生中断,可能会导致逻辑错误。
- BSRR (Bit Set/Reset Register): 原子操作。往 BSRR 的高 16 位写 1 是清零,低 16 位写 1 是置位。它不需要读取寄存器,直接硬件级触发,既快又安全。
6. 实战避坑:标准库开发的“三大坑”
- 忘记使能 RCC 时钟: 90% 的新手程序不跑都是因为这一行代码没写。
- 引脚复用与重映射: 如果你想用 PB3 作为普通 GPIO,但它是 JTAG 引脚,必须先开启
AFIO时钟并进行引脚禁用重映射(GPIO_PinRemapConfig)。 - 输入模式下设置 Speed: 虽然写了不报错,但逻辑上没有意义,浪费代码空间。












