通用输入输出 GPIO 模块
基于 STM32F103 · 零基础讲解 GPIO 结构、八种工作模式、标准外设库与 HAL 库点灯。
🎯学习目标
- 了解 GPIO 的基本概念;
- 理解 STM32F103 的 GPIO 内部结构、工作模式和使用特性;
- 理解 GPIO 的输入输出模式;
- 熟悉 GPIO 相关的标准外设库函数和 HAL 库函数;
- 掌握用标准库 / HAL 库实现 LED 灯闪烁。
1GPIO 概述
GPIO(General Purpose Input/Output,通用输入输出)端口内部由一个个寄存器组成:一个引脚对应一个寄存器位,改变寄存器中的数据就能改变外设的工作方式。
GPIO就像单片机的"万能插座"——每个引脚都可以被程序自由配置成输入或输出。
输出模式(单片机→外部):像开关,程序控制引脚输出高电平(3.3V,相当于"开")或低电平(0V,相当于"关"),可以点亮LED、驱动继电器。
输入模式(外部→单片机):像传感器,程序可以读取引脚当前是高电平还是低电平,用来检测按键是否按下、传感器信号等。
一句话:GPIO = 通用输入输出 = 单片机与外部世界交互的"手脚"。输入=感知外界,输出=控制外界。
寄存器就是单片机内部的"小开关面板"——每个位(bit)控制一个功能。
想象一排8个开关:第1个开关控制"LED亮不亮",第2个控制"蜂鸣器响不响"……程序通过拨动这些开关(写寄存器)来控制硬件,通过看开关状态(读寄存器)来获取信息。
怎么操作寄存器?直接给寄存器地址赋值即可。但实际开发中,我们用库函数(如 GPIO_SetBits())来操作,库函数内部就是读写寄存器。就像你用遥控器(库函数)换频道,遥控器内部帮你发送了红外信号(读写寄存器)。
与 51 单片机相比,STM32 拥有更多 I/O 引脚、更强驱动能力、更灵活的控制方式,功能也更强大。
2引脚与内部结构
STM32F103ZET6 引脚分类(144 引脚,六大类)
| 类别 | 引脚举例 |
|---|---|
| 电源引脚 | VDD、VSS、VREF+/-、VDDA、VSSA、VBAT |
| 晶振引脚 | PC14、PC15、OSC_IN、OSC_OUT |
| 复位引脚 | NRST |
| BOOT 引脚 | BOOT0、BOOT1 |
| 程序下载引脚 | PA13、PA14、PA15、PB3、PB4 |
| GPIO 引脚 | 共 7 组(PA~PG),每组 16 个:Px0~Px15 |
大多数引脚还通过复用技术兼具其他专用功能(如串口、ADC、IIC 等)。
3八种工作模式 ⭐(核心考点)
STM32 的 GPIO 共有 8 种工作模式,分为输出和输入两大类。点击卡片翻转查看要点:
📤 输出模式(4 种)
推挽输出
Push-Pull, PP开漏输出
Open-Drain, OD复用推挽
AF Push-Pull复用开漏
AF Open-Drain📥 输入模式(4 种)
上拉输入
IPU下拉输入
IPD浮空输入
Floating模拟输入
Analog推挽输出像双手推拉门:一只手推开门(输出高),一只手关上门(输出低)。主动有力,速度快。
开漏输出像只有一只手关门:只能拉低(关门),输出高电平要靠外面的弹簧(上拉电阻)把门弹开。虽然麻烦,但有个好处:多个设备可以共用一根线(线与),就像多人共用一扇门,谁都能关,但开要靠弹簧。这就是IIC总线的原理。
4GPIO 输出速度
注意:输出速度不是信号速度,而是 I/O 口驱动电路的响应速度。STM32F103 有 3 档:
2 MHz
低速。LED、蜂鸣器等普通外设。功耗低。
10 MHz
中速。一般复用功能。
50 MHz
高速。IIC、SPI 等高速复用输出。
5GPIO 寄存器(每组 7 个)
每组 GPIO 端口(Px)由 7 个寄存器组成,控制该端口 16 个引脚:
| 寄存器 | 作用 |
|---|---|
| CRL / CRH(配置低/高) | 配置每个引脚的模式和速度(低 8 位 / 高 8 位) |
| IDR(输入数据) | 读取引脚输入电平 |
| ODR(输出数据) | 设置引脚输出电平 |
| BSRR(位设置/复位) | 原子地置位/复位引脚(高 16 位复位,低 16 位置位) |
| BRR(位复位) | 原子地复位引脚 |
| LCKR(锁定) | 锁定引脚配置 |
6标准外设库接口函数
源码在 stm32f10x_gpio.c,头文件 stm32f10x_gpio.h 声明了共 18 种库函数。
| 类型 | 常用函数 | 功能 |
|---|---|---|
| 初始化/复位 | GPIO_Init() | 按结构体参数初始化 GPIO |
GPIO_DeInit() | 恢复默认复位值 | |
| 引脚操作 | GPIO_SetBits() | 置位引脚(输出高) |
GPIO_ResetBits() | 复位引脚(输出低) | |
GPIO_WriteBit() | 写指定引脚电平 | |
GPIO_ReadInputDataBit() | 读输入引脚电平 | |
| 外部中断 | GPIO_EXTILineConfig() | 配置端口为中断线输入 |
GPIO_Init() 有两个参数:① 端口 x(A~G);② 指向 GPIO_InitTypeDef 结构体的指针。结构体成员:
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 引脚 0~15 或 All
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 工作模式(推挽输出)
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // 输出速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
7标准库 vs HAL 库
| 对比 | 标准外设库 (StdPeriph) | HAL 库 |
|---|---|---|
| 抽象程度 | 贴近寄存器,效率高 | 高度抽象,跨系列可移植 |
| 初始化 | GPIO_Init() | HAL_GPIO_Init() |
| 写引脚 | GPIO_SetBits()/ResetBits() | HAL_GPIO_WritePin() |
| 翻转 | 读 ODR 取反写回 | HAL_GPIO_TogglePin() |
| 读引脚 | GPIO_ReadInputDataBit() | HAL_GPIO_ReadPin() |
| 配套工具 | 手写 | STM32CubeMX 图形化生成 |
⭐重点例题:LED 闪烁
// ① 使能 GPIOA 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// ② 配置 PA0 推挽输出 2MHz
GPIO_InitTypeDef g;
g.GPIO_Pin=GPIO_Pin_0; g.GPIO_Mode=GPIO_Mode_Out_PP; g.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&g);
// ③ 主循环闪烁
while(1){
GPIO_SetBits(GPIOA,GPIO_Pin_0); delay_ms(500); // 亮
GPIO_ResetBits(GPIOA,GPIO_Pin_0); delay_ms(500); // 灭
}
关键点:① 必须先开时钟(GPIO 挂在 APB2 总线),不开时钟配置无效;② LED 接法决定亮灭逻辑(共阳极时低电平亮)。
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef g={0};
g.Pin=GPIO_PIN_0; g.Mode=GPIO_MODE_OUTPUT_PP; g.Speed=GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA,&g);
while(1){ HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_0); HAL_Delay(500); }
🎯自测(点击展开)
STM32F103 有几组 GPIO?每组几个引脚?
推挽输出和开漏输出有什么区别?
"GPIO 输出速度"指的是什么?
配置 GPIO 前必须先做什么?
📝强化题库
选择题点选即时判分;填空题输入后"检查"或"显示答案"。