02-GPIO输出
GPIO 基本结构
graph TD
subgraph APB2_BUS
APB2["APB2 (72MHz)"]
end
subgraph GPIO_REG
CRL["CRL (配置低8位)"]
CRH["CRH (配置高8位)"]
IDR["IDR (输入数据)"]
ODR["ODR (输出数据)"]
BSRR["BSRR (位设置/复位)"]
BRR["BRR (位复位)"]
LCKR["LCKR (锁定)"]
end
APB2 --> GPIO_REG
GPIO_REG --> GPIO_PIN
GPIO 位结构
graph LR
subgraph PIN_STRUCT
PAD["I/O Pad"] --> D1["保护二极管\nVDD"]
PAD --> D2["保护二极管\nVSS"]
D1 --> PULL_UP["上拉电阻\n(~40kΩ)"]
D1 --> PULL_DOWN["下拉电阻\n(~40kΩ)"]
PAD --> SCHMITT["施密特触发器"]
SCHMITT --> INPUT_REG["输入数据寄存器<br/>(IDR)"]
OUTPUT_REG["输出数据寄存器<br/>(ODR)"] --> DRIVER["输出驱动器"]
DRIVER --> MUX["复用功能输出"]
MUX --> PAD
OUTPUT_REG --> BIT_SET["位设置/复位<br/>(BSRR)"]
BIT_SET --> DRIVER
end
| 组件 |
作用 |
| 保护二极管 |
钳位电压,防止 VDD+0.3V / VSS-0.3V 烧毁 IO |
| 上拉/下拉电阻 |
约 30kΩ~50kΩ,固定空闲电平 |
| 施密特触发器 |
整形,防抖动,有滞后特性(VT+ ≈ 0.4VDD, VT- ≈ 0.3VDD) |
| 输出驱动器 |
推挽(Push-Pull) 或 开漏(Open-Drain) |
| BSRR |
原子操作,一次写同时设置和复位不同位 |
8种 GPIO 模式
| 模式 |
GPIO_Mode |
结构特点 |
典型用途 |
| 模拟输入 |
GPIO_Mode_AIN |
关闭施密特触发器,不接上/下拉 |
ADC 采样输入 |
| 浮空输入 |
GPIO_Mode_IN_FLOATING |
施密特触发,无上下拉 |
外部信号按键(需外部上拉) |
| 上拉输入 |
GPIO_Mode_IPU |
施密特触发 + 上拉电阻 |
按键(GND导通) |
| 下拉输入 |
GPIO_Mode_IPD |
施密特触发 + 下拉电阻 |
按键(VCC导通) |
| 推挽输出 |
GPIO_Mode_Out_PP |
PMOS+NMOS, 高低电平 |
LED, 蜂鸣器, 总线控制 |
| 开漏输出 |
GPIO_Mode_Out_OD |
仅NMOS, 低=GND, 高=高阻 |
I2C SDA/SCL, 电平转换 |
| 复用推挽 |
GPIO_Mode_AF_PP |
外设驱动推挽输出 |
USART TX, SPI SCK/MOSI |
| 复用开漏 |
GPIO_Mode_AF_OD |
外设驱动开漏输出 |
I2C(STM32做主控) |
输出速度
| 速度宏 |
频率 |
适用场景 |
GPIO_Speed_2MHz |
2MHz |
低频,EMI 最小的通用 IO |
GPIO_Speed_10MHz |
10MHz |
常规通信 |
GPIO_Speed_50MHz |
50MHz |
SPI/高速 PWM |
EMI 随速度增大而增大,不用高频时用 GPIO_Speed_2MHz 即可。
API 表格
RCC 时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO 初始化
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
| GPIO_InitTypeDef 成员 |
取值 |
说明 |
GPIO_Pin |
GPIO_Pin_0 ~ GPIO_Pin_15 |
引脚号,支持 OR 组合 |
GPIO_Speed |
GPIO_Speed_2MHz / 10MHz / 50MHz |
输出速率 |
GPIO_Mode |
见上方 8 种模式 |
IO 工作模式 |
输出控制函数
| 函数 |
原型 |
说明 |
GPIO_SetBits |
GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) |
指定引脚输出高 |
GPIO_ResetBits |
GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) |
指定引脚输出低 |
GPIO_WriteBit |
GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal) |
按 BitVal 输出 |
GPIO_Write |
GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal) |
写整个 ODR |
GPIO_SetBits |
用 BSRR 实现,原子操作 |
推荐使用 |
完整代码示例
LED 流水灯 (PC13~PC10)
#include "stm32f10x.h"
#include "Delay.h"
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 开启 GPIOC 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
// PC13 - PC10 推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_11 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// 初始全部熄灭 (板载 LED 低电平亮)
GPIO_SetBits(GPIOC, GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_11 | GPIO_Pin_10);
Delay_Init();
while (1)
{
GPIO_ResetBits(GPIOC, GPIO_Pin_13); // PC13 亮
Delay_ms(500);
GPIO_SetBits(GPIOC, GPIO_Pin_13);
GPIO_ResetBits(GPIOC, GPIO_Pin_12); // PC12 亮
Delay_ms(500);
GPIO_SetBits(GPIOC, GPIO_Pin_12);
GPIO_ResetBits(GPIOC, GPIO_Pin_11); // PC11 亮
Delay_ms(500);
GPIO_SetBits(GPIOC, GPIO_Pin_11);
GPIO_ResetBits(GPIOC, GPIO_Pin_10); // PC10 亮
Delay_ms(500);
GPIO_SetBits(GPIOC, GPIO_Pin_10);
}
}
蜂鸣器驱动 (PC9)
电路连接:PC9 → NPN (S8050) Base → 集电极接蜂鸣器负极 → 蜂鸣器正极接 3.3V。
#include "stm32f10x.h"
#include "Delay.h"
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_ResetBits(GPIOC, GPIO_Pin_9); // 关闭 (低电平截止)
while (1)
{
// 有源蜂鸣器: 高电平导通发声
GPIO_SetBits(GPIOC, GPIO_Pin_9);
Delay_ms(500);
GPIO_ResetBits(GPIOC, GPIO_Pin_9);
Delay_ms(500);
}
}
常用板载 LED 引脚
| 开发板 |
LED 引脚 |
电平 |
| STM32F103C8T6 蓝色板 |
PC13 |
低电平亮 |
| STM32F103C8T6 红板(Mini) |
PA1 |
高电平亮 |
| STM32F103ZET6 正点原子 |
PD2 (DS0) / PG15 (DS1) |
低电平亮 |
| STM32F103VET6 野火 |
PB5 |
低电平亮 |
常见坑点/注意事项
- 外设时钟必须先开启 — 不开启时钟读写寄存器会 HardFault
- GPIO 速度与 EMI — 不需要高速时用
GPIO_Speed_2MHz,过高速度引入 EMI 且增加功耗
- 开漏输出高阻 —
Out_OD 输出高电平必须加外部上拉电阻,否则读不到高电平
- BSRR vs ODR — 多线程/中断中修改位用 BSRR 是原子操作,ODR 非原子(读-改-写)
GPIO_SetBits 底层用 BSRR — 比 GPIO_WriteBit(用 ODR)更安全
- IO 初始化时默认电平 — 推挽输出初始化后 ODR 复位值 0x0000,引脚默认低电平
- PC13 特殊 — 部分型号 PC13 驱动能力弱,LED 亮度可能不如其他引脚
- BSRR 写入高位 Hi 复位,低位 Lo 置位 —
BSRR[31:16]=BRx 复位, BSRR[15:0]=BSx 置位