GPIO的输入输出
GPIO输入和输出
简介
每个GPI/O端口有两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH),两个32位数据寄存器(GPIOx_IDR和GPIOx_ODR),一个32位置位/复位寄存器(GPIOx_BSRR),一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)
GPIO端口的每个位可以由软件分别配置成多种模式。
输入模式有:输入浮空、输入上拉、输入下拉、模拟输入。
输出模式有: 开漏输出、推挽式输出、推挽式复用功能、开漏复用功能。
每个I/O端口位可以自由编程,然而必须按照32位字访问I/O端口寄存器(不允许半字或字节访问)。GPIOx_BSRR和GPIOx_BRR寄存器允许对任何GPIO寄存器进行读/更改的独立访问;这样,在读和更改访问之间产生IRQ时不会发生危险。
I/O端口位的基本结构

如果把VDD换成VDD_FT,那么这个I/O口式5V的I/O口,否则式3.3V的。VDD_FT 对5伏容忍I/O脚是特殊的,它与VDD不同。
端口位配置及寄存器

| MODE[1:0] | 意义 |
|---|---|
| 00 | 保留 |
| 01 | 最大输出速度为 10MHz |
| 10 | 最大输出速度为 2MHz |
| 11 | 最大输出速度为 50MHz |
端口配置低寄存器(GPIOx_CRL) (x=A..E)

| 位域范围 | 含义说明 |
|---|---|
| 位 31:30 27:26 23:22 19:18 15:14 11:10 7:6 3:2 |
CNFy[1:0]:端口 x 配置位 (y = 0…7)软件通过这些位配置相应的 I/O 端口。 在输入模式 (MODE [1:0]=00): 00:模拟输入模式 01:浮空输入模式 (复位后的状态) 10:上拉 / 下拉输入模式 11:保留 在输出模式 (MODE [1:0]>00): 00:通用推挽输出模式 01:通用开漏输出模式 10:复用功能推挽输出模式 11:复用功能开漏输出模式 |
| 位 29:28 25:24 21:20 17:16 13:12 9:8 5:4 1:0 |
MODEy[1:0]:端口 x 的模式位 (y = 0…7)软件通过这些位配置相应的 I/O 端口。 00:输入模式 (复位后的状态) 01:输出模式,最大速度 10MHz 10:输出模式,最大速度 2MHz 11:输出模式,最大速度 50MHz |
端口配置高寄存器(GPIOx_CRH) (x=A..E)
这个的功能同上,只是这个寄存器配置的式GPIO端口的高八位(8到15).
端口输入数据寄存器(GPIOx_IDR) (x=A..E)

| 位域范围 | 含义说明 |
|---|---|
| 位 31:16 | 保留,始终读为 0。 |
| 位 15:0 | IDRy[15:0]:端口输入数据 (y = 0…15) (Port input data)这些位为只读并只能以字 (16 位) 的形式读出。读出的值为对应 I/O 口的状态。 |
端口输出数据寄存器(GPIOx_ODR) (x=A..E)

| 位域范围 | 含义说明 |
|---|---|
| 位 31:16 | 保留,始终读为 0。 |
| 位 15:0 | ODRy[15:0]:端口输出数据 (y = 0…15) (Port output data)这些位可读可写并只能以字 (16 位) 的形式操作。注:对 GPIOx_BSRR (x = A…E),可以分别地对各个 ODR 位进行独立的设置 / 清除。 |
端口位设置/清除寄存器(GPIOx_BSRR) (x=A..E)

| 位域范围 | 含义说明 |
|---|---|
| 位 31:16 | BRy: 清除端口 x 的位 y (y = 0…15) (Port x Reset bit y) 这些位只能写入并只能以字 (16 位) 的形式操作。 0:对对应的 ODRy 位不产生影响 1:清除对应的 ODRy 位为 0 注:如果同时设置了 BSy 和 BRy 的对应位,BSy 位起作用。 |
| 位 15:0 | BSy: 设置端口 x 的位 y (y = 0…15) (Port x Set bit y) 这些位只能写入并只能以字 (16 位) 的形式操作。 0:对对应的 ODRy 位不产生影响 1:设置对应的 ODRy 位为 1 |
端口位清除寄存器(GPIOx_BRR) (x=A..E)

| 位域范围 | 含义说明 |
|---|---|
| 位 31:16 | 保留。 |
| 位 15:0 | BRy: 清除端口 x 的位 y (y = 0…15) (Port x Reset bit y) 这些位只能写入并只能以字 (16 位) 的形式操作。 0:对对应的 ODRy 位不产生影响 1:清除对应的 ODRy 位为 0 |
这个寄存器(BRR)是专门用于原子清除GPIO 输出位的寄存器,配合 BSRR 寄存器可以实现对 GPIO 引脚的安全、无竞态操作,个人感觉使用BRR寄存器进行位清除,BSRR进行位设置这样会更方便。
输入配置
当I/O端口配置为输入时:
● 输出缓冲器被禁止
● 施密特触发输入被激活
● 根据输入配置(上拉,下拉或浮动)的不同,弱上拉和下拉电阻被连接
● 出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器
● 对输入数据寄存器的读访问可得到I/O状态

输出配置
当I/O端口被配置为输出时:
● 输出缓冲器被激活
─ 开漏模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将端口置于高阻状态(PMOS从不被激活)。
─ 推挽模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将激活P-MOS。
● 施密特触发输入被激活
● 弱上拉和下拉电阻被禁止
● 出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器
● 在开漏模式时,对输入数据寄存器的读访问可得到I/O状态
● 在推挽式模式时,对输出数据寄存器的读访问得到最后一次写的值。

复用功能配置
当I/O端口被配置为复用功能时:
● 在开漏或推挽式配置中,输出缓冲器被打开
● 内置外设的信号驱动输出缓冲器(复用功能输出)
● 施密特触发输入被激活
● 弱上拉和下拉电阻被禁止
● 在每个APB2时钟周期,出现在I/O脚上的数据被采样到输入数据寄存器
● 开漏模式时,读输入数据寄存器时可得到I/O口状态
● 在推挽模式时,读输出数据寄存器时可得到最后一次写的值
一组复用功能I/O寄存器允许用户把一些复用功能重新映象到不同的引脚

模拟输入配置
当I/O端口被配置为模拟输入配置时:
● 输出缓冲器被禁止;
● 禁止施密特触发输入,实现了每个模拟I/O引脚上的零消耗。施密特触发输出值被强置为’0’;
● 弱上拉和下拉电阻被禁止;
● 读取输入数据寄存器时数值为’0’。

标准库的使用
一、STM32 标准库 GPIO 配置核心概念
STM32 标准库把 GPIO 的配置封装成了结构化的函数和宏定义,核心是通过GPIO_InitTypeDef结构体定义引脚参数,再调用GPIO_Init()函数完成配置。
1. 核心结构体:GPIO_InitTypeDef
这是配置 GPIO 的核心结构体,所有引脚参数都通过它设置:
typedef struct
{
uint16_t GPIO_Pin; // 选择要配置的GPIO引脚
GPIOSpeed_TypeDef GPIO_Speed;// 配置输出速度(仅输出模式有效)
GPIOMode_TypeDef GPIO_Mode; // 配置GPIO工作模式(打包了输入/输出/上下拉/开漏推挽)
}GPIO_InitTypeDef;
2. 关键参数
| 枚举类型 | 可选值(常用) | 含义说明 |
|---|---|---|
| GPIO_Pin | GPIO_Pin_0 ~ GPIO_Pin_15 | 指定要配置的引脚 |
| GPIO_Mode | GPIO_Mode_AIN(模拟输入) | 模拟输入模式(对应寄存器 MODE [1:0]=00,CNF [1:0]=00) |
| GPIO_Mode_IN_FLOATING(浮空输入) | 浮空输入模式(对应寄存器 MODE [1:0]=00,CNF [1:0]=01) | |
| GPIO_Mode_IPU(上拉输入) | 上拉输入模式(对应寄存器 MODE [1:0]=00,CNF [1:0]=10) | |
| GPIO_Mode_IPD(下拉输入) | 下拉输入模式(对应寄存器 MODE [1:0]=00,CNF [1:0]=10) | |
| GPIO_Mode_Out_PP(通用推挽输出) | 通用推挽输出(对应寄存器 MODE [1:0]>00,CNF [1:0]=00) | |
| GPIO_Mode_Out_OD(通用开漏输出) | 通用开漏输出(对应寄存器 MODE [1:0]>00,CNF [1:0]=01) | |
| GPIO_Mode_AF_PP(复用推挽输出) | 复用推挽输出(对应寄存器 MODE [1:0]>00,CNF [1:0]=10) | |
| GPIO_Mode_AF_OD(复用开漏输出) | 复用开漏输出(对应寄存器 MODE [1:0]>00,CNF [1:0]=11) | |
| GPIO_Speed | GPIO_Speed_2MHz | 低速(对应寄存器 MODE [1:0]=10) |
| GPIO_Speed_10MHz | 中速(对应寄存器 MODE [1:0]=01) | |
| GPIO_Speed_50MHz | 高速(对应寄存器 MODE [1:0]=11) |
二、标准库 GPIO 配置完整步骤
以 “配置 PA0 为上拉输入、PB0 为推挽输出(50MHz)” 为例,展示完整配置流程:
#include "stm32f10x.h"
void GPIO_Config(void)
{
// 1. 使能GPIO外设时钟(必须!STM32外设默认关闭时钟)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
// 2. 配置PA0:上拉输入模式
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; // 选择PA0引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; // 输入模式下Speed无意义,随便赋值即可
GPIO_Init(GPIOA, &GPIO_InitStruct); // 应用配置到GPIOA
// 3. 配置PB0:推挽输出,50MHz
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; // 选择PB0引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 高速(50MHz)
GPIO_Init(GPIOB, &GPIO_InitStruct); // 应用配置到GPIOB
}
// 主函数测试
int main(void)
{
GPIO_Config(); // 初始化GPIO
while(1)
{
// 读取PA0输入电平
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_SET)
{
GPIO_SetBits(GPIOB, GPIO_Pin_0); // PB0置1(高电平,原子操作)
}
else
{
GPIO_ResetBits(GPIOB, GPIO_Pin_0); // PB0置0(低电平,原子操作)
}
}
}
3. 常用 GPIO 操作函数
| 函数名 | 功能说明 | 示例 |
|---|---|---|
| GPIO_ReadInputDataBit() | 读取单个输入引脚电平 | GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) |
| GPIO_ReadInputData() | 读取整个 GPIO 端口的输入电平(16 位) | GPIO_ReadInputData(GPIOA) |
| GPIO_ReadOutputDataBit() | 读取单个输出引脚电平 | GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0) |
| GPIO_SetBits() | 置位输出引脚(原子操作,对应 BSRR 寄存器) | GPIO_SetBits(GPIOB, GPIO_Pin_0) |
| GPIO_ResetBits() | 复位输出引脚(原子操作,对应 BRR 寄存器) | GPIO_ResetBits(GPIOB, GPIO_Pin_0) |
| GPIO_WriteBit() | 写单个输出引脚电平 | GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_SET) |
| GPIO_Write() | 写整个 GPIO 端口的输出电平(16 位) | GPIO_Write(GPIOB, 0x0001) |
三、配置注意事项
-
时钟使能:STM32 所有外设(包括 GPIO)默认关闭时钟,必须先调用
RCC_APB2PeriphClockCmd()使能对应 GPIO 端口的时钟(F1 系列 GPIO 均在 APB2 总线)。 -
参数匹配:
- 输入模式(AIN/IN_FLOATING/IPU/IPD)下,
GPIO_Speed参数无实际作用,但必须赋值(否则编译警告); - 输出模式(Out_PP/Out_OD/AF_PP/AF_OD)下,
GPIO_Speed决定引脚响应速度,建议高频场景用GPIO_Speed_50MHz;
- 原子操作:优先使用
GPIO_SetBits()/GPIO_ResetBits()(操作 BSRR/BRR 寄存器),而非直接修改 ODR,避免 “读 - 改 - 写” 竞态条件。
总结
- GPIO 配置核心是
GPIO_InitTypeDef结构体,仅需配置GPIO_Pin、GPIO_Speed、GPIO_Mode三个成员,按 “时钟使能→配置结构体→调用 GPIO_Init ()” 三步完成; GPIO_Mode是打包好的枚举值,直接对应 “输入 / 输出 + 上下拉 / 开漏推挽”;- 输入模式下
GPIO_Speed仅需占位赋值,输出模式按需选择速度,操作输出引脚优先用原子函数保证稳定性。
Hal库的使用
hal库可以基于cubemx进行图形化配置,输入和输出均可直接对引脚进行对应的图形化配置,但是这个复用输出等需要到相应的引脚去点击配置。
需要自行选择对应的功能,这个可以省去自己写初始化函数的步骤。

常用函数
| 函数名 | 功能说明 | 示例(CubeMX 配置后直接用) |
|---|---|---|
HAL_GPIO_ReadPin() |
读取单个引脚电平(输入模式) | HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) |
HAL_GPIO_WritePin() |
写单个引脚电平(输出模式,原子操作) | HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET)(置 1)HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET)(置 0) |
HAL_GPIO_TogglePin() |
翻转引脚电平(输出模式,原子操作) | HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0) |
HAL_GPIO_LockPin() |
锁定引脚配置(防止意外修改) | HAL_GPIO_LockPin(GPIOA, GPIO_PIN_0) |

浙公网安备 33010602011771号