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端口位的基本结构

image

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

端口位配置及寄存器

image

MODE[1:0] 意义
00 保留
01 最大输出速度为 10MHz
10 最大输出速度为 2MHz
11 最大输出速度为 50MHz

端口配置低寄存器(GPIOx_CRL) (x=A..E)

image

位域范围 含义说明
位 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)

image

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

端口输出数据寄存器(GPIOx_ODR) (x=A..E)

image

位域范围 含义说明
位 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)

image

位域范围 含义说明
位 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)

image

位域范围 含义说明
位 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状态

image

输出配置

当I/O端口被配置为输出时:

● 输出缓冲器被激活

─ 开漏模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将端口置于高阻状态(PMOS从不被激活)。

─ 推挽模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将激活P-MOS。

● 施密特触发输入被激活

● 弱上拉和下拉电阻被禁止

● 出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器

● 在开漏模式时,对输入数据寄存器的读访问可得到I/O状态

● 在推挽式模式时,对输出数据寄存器的读访问得到最后一次写的值。

image

复用功能配置

当I/O端口被配置为复用功能时:

● 在开漏或推挽式配置中,输出缓冲器被打开

● 内置外设的信号驱动输出缓冲器(复用功能输出)

● 施密特触发输入被激活

● 弱上拉和下拉电阻被禁止

● 在每个APB2时钟周期,出现在I/O脚上的数据被采样到输入数据寄存器

● 开漏模式时,读输入数据寄存器时可得到I/O口状态

● 在推挽模式时,读输出数据寄存器时可得到最后一次写的值

一组复用功能I/O寄存器允许用户把一些复用功能重新映象到不同的引脚

image

模拟输入配置

当I/O端口被配置为模拟输入配置时:

● 输出缓冲器被禁止;

● 禁止施密特触发输入,实现了每个模拟I/O引脚上的零消耗。施密特触发输出值被强置为’0’;

● 弱上拉和下拉电阻被禁止;

● 读取输入数据寄存器时数值为’0’。

image

标准库的使用

一、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)

三、配置注意事项

  1. 时钟使能:STM32 所有外设(包括 GPIO)默认关闭时钟,必须先调用RCC_APB2PeriphClockCmd()使能对应 GPIO 端口的时钟(F1 系列 GPIO 均在 APB2 总线)。

  2. 参数匹配

  • 输入模式(AIN/IN_FLOATING/IPU/IPD)下,GPIO_Speed参数无实际作用,但必须赋值(否则编译警告);
  • 输出模式(Out_PP/Out_OD/AF_PP/AF_OD)下,GPIO_Speed决定引脚响应速度,建议高频场景用GPIO_Speed_50MHz
  1. 原子操作:优先使用GPIO_SetBits()/GPIO_ResetBits()(操作 BSRR/BRR 寄存器),而非直接修改 ODR,避免 “读 - 改 - 写” 竞态条件。

总结

  1. GPIO 配置核心是GPIO_InitTypeDef结构体,仅需配置GPIO_PinGPIO_SpeedGPIO_Mode三个成员,按 “时钟使能→配置结构体→调用 GPIO_Init ()” 三步完成;
  2. GPIO_Mode是打包好的枚举值,直接对应 “输入 / 输出 + 上下拉 / 开漏推挽”;
  3. 输入模式下GPIO_Speed仅需占位赋值,输出模式按需选择速度,操作输出引脚优先用原子函数保证稳定性。

Hal库的使用

hal库可以基于cubemx进行图形化配置,输入和输出均可直接对引脚进行对应的图形化配置,但是这个复用输出等需要到相应的引脚去点击配置。

需要自行选择对应的功能,这个可以省去自己写初始化函数的步骤。

image

常用函数

函数名 功能说明 示例(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)
posted @ 2026-02-18 10:10  野云闲出眠  阅读(1)  评论(0)    收藏  举报