文章目录
- 一、GPIO基础知识
- 1.GPIO是什么?
- 2.引脚和GPIO的区别和联系?
- 3.绝多数引脚都是GPIO,有限的引脚怎么实现更多的功能?
- 4. 怎么知道具体的芯片外设资源?
- 5.怎么查看GPIO引脚功能?
- 二、GPIO的8种工作模式
- 三、GPIO寄存器
- 1.端口模式寄存器(GPIOx_MODER)
- 2.端口输出类型寄存器(GPIOx_OTYPER)
- 3.端口输出速度寄存器(GPIOx_OSPEEDR)
- 4.端口上拉/下拉寄存器(GPIOx_PUPDR)
- 5.端口输入数据寄存器(GPIOx_IDR)
- 6.端口输出数据寄存器(GPIOx_ODR)
- 7.端口置位/复位寄存器(GPIOx_BSRR)
- 8.端口配置锁定寄存器(GPIOx_LCKR)
- 9.复用功能寄存器(GPIOx_AFRL、AFRH)
- 四、GPIO常用库函数
- 五、配置HAL库操作IO口步骤
一、GPIO基础知识
1.GPIO是什么?
GPIO的全称是general purpose intput output。它是通用输入输出端口。既可以做输入也可以做输出。GPIO端口可通过程序配置成输入或者输出。
2.引脚和GPIO的区别和联系?
STM32F4的引脚中,有部分是做GPIO使用,部分是电源引脚/复位引脚/启动模式引脚/晶振引脚/调试下载引脚。

- 一共有9组
IO:PA~PI,其中PA~PH每组16个IO,PI只有PI0~PI11,一共有140个IO口:16*8+12=140
STM32F4中约有140个引脚可做IO口使用,还有36个引脚可做电源引脚/复位引脚/启动模式引脚/晶振引脚/调试下载引脚等
3.绝多数引脚都是GPIO,有限的引脚怎么实现更多的功能?
STM32的大部分引脚除了当GPIO使用外,还可以复用为外设功能引脚(比如串口)。一个引脚,可以作为IO口,同时也可以作为复用功能外设引脚。
复用的原理 可以用图像抽象如下: 
通过开关控制引脚组,可以大大节省IO口资源。
4. 怎么知道具体的芯片外设资源?
可以通过查找ST MCU选型手册来查找。

5.怎么查看GPIO引脚功能?
每个STM32芯片的芯片数据手册(例如:STM32F429IGT6.pdf)都会提供引脚功能描述,如下表。

其中的FT标识表示该IO口可以5V容忍。
二、GPIO的8种工作模式
GPIO有8种工作模式:
-
4种输入模式
-
输入浮空

IO口电平直接进入TTL施密特触发器(上拉与下拉均没有起作用),然后到达输入数据寄存器,这样CPU可以通过输入数据寄存器来读取IO口的状态 -
输入上拉

输入上拉与输入浮空的区别就是上拉会起作用。 -
输入下拉

输入下拉与输入浮空的区别就是下拉会起作用。 -
模拟输入

IO口电平直接进入模拟通道,ADC控制单元采集电压信号,CPU读取ADC控制单元相关的寄存器来读取模拟信号并且转化为数字信号(不是CPU转换的,而是ADC控制单元转换的)。
-
-
4种输出模式(带上下拉)
-
开漏输出(带上拉或者下拉)


只可以输出强低电平,高电平得靠外部电阻拉高。输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行. 适合于做电流型的驱动,其吸收电流的能力相对强 -
开漏复用功能(带上拉或者下拉)

复用功能输出连接的片上的外设模块,CPU控制外设控制模块。 -
推挽式输出(带上拉或者下拉)

设置IO口输出为1,则为高电平;设置IO口输出为0,则为低电平。可以输出强高低电平,连接数字器件。 -
推挽式复用功能(带上拉或者下拉)

-
GPIO可以配置4种最大输出速度:
2MHz低速25MHz中速50MHz快速100MHz高速
上电复位后,GPIO默认为输入浮空状态,部分特殊功能引脚为特定状态。复位后,调试引脚处于复用功能上拉/下拉状态:
PA15:JTDI处于上拉状态PA14:JTCK/SWCLK处于下拉状态PA13:JTMS/SWDAT处于下拉状态PB4:NJTRST处于上拉状态PB3:JTDO处于浮空状态
三、GPIO寄存器
STM32F4 每组通用 I/O 端口包括 4 个 32 位配置寄存器(MODER、OTYPER、OSPEEDR 和 PUPDR)、2 个 32 位数据寄存器(IDR 和 ODR)、1 个 32 位置位/复位寄存器 (BSRR)、1 个 32 位锁定寄存器 (LCKR) 和 2 个 32 位复用功能选择寄存器(AFRH 和 AFRL)等。这样,STM32F4 每组 IO 有 10 个 32 位寄存器控制,其中常用的有 4 个配置寄存器+2 个数据寄存器+2 个复用功能选择寄存器,共 8 个。接下来我们详细介绍 IO 配置常用的 8 个寄存器: MODER、OTYPER、OSPEEDR、PUPDR、ODR、IDR 、AFRH 和 AFRL。同时讲解对应的 HAL 库配置方法。
重点说明:
- 每组
IO口由10个寄存器组成,如果芯片有GPIOA~GPIOI9个组,那么一共有对应9X10=90个寄存器。 - 如果配置一个
IO口需要2个位,那么刚好32位寄存器配置一组IO口(16个IO口) - 如果配置一个
IO口只需要1个位,一般高16位保留 BSRR寄存器32位分为低16位BSRRL和高16位BSRRH,BSRRL配置一组IO口的16个IO口的置位状态(1),BSRRH配置复位状态(0)
1.端口模式寄存器(GPIOx_MODER)
该寄存器是 GPIO 端口模式控制寄存器,用于控制 GPIOx的工作模式,

该寄存器各位在复位后,一般都是 0(个别不是 0,比如 JTAG 占用的几个 IO 口),也就是默认条件下一般是输入状态的。每组 IO 下有 16 个 IO 口,该寄存器共 32 位,每 2 个位控制 1个 IO。
2.端口输出类型寄存器(GPIOx_OTYPER)
该寄存器用于控制 GPIOx 的输出类型

该寄存器仅用于输出模式,在输入模式(MODER[1:0]=00/11 时)下不起作用。该寄存器低 16 位有效,每一个位控制一个 IO 口。设置为 0 是推挽输出,设置为 1 是开漏输出。复位后,该寄存器值均为 0,也就是在输出模式下 IO 口默认为推挽输出。
3.端口输出速度寄存器(GPIOx_OSPEEDR)
该寄存器用于控制 GPIOx 的输出速度,

该寄存器也仅用于输出模式,在输入模式(MODER[1:0]=00/11 时)下不起作用。该寄存器每 2 个位控制一个 IO 口,复位后,该寄存器值一般为 0。
4.端口上拉/下拉寄存器(GPIOx_PUPDR)
该寄存器用于控制 GPIOx 的上拉/下拉,

该寄存器每 2 个位控制一个 IO 口,用于设置上下拉,STM32F4 则由单独的寄存器PUPDR控制上下拉,使用起来更加灵活。
复位后,该寄存器值一般为 0。
前面,我们讲解了 4 个重要的配置寄存器。顾名思义,配置寄存器就是用来配置 GPIO 的相关模式和状态,接下来,分析怎么在 HAL 库中初始化 GPIO 配置。
GPIO 相关的函数和定义分布在 HAL 库文件 stm32f4xx_hal_gpio.c 和头文件stm32f4xx_hal_gpio.h 文件中。在 HAL 库中,操作四个配置寄存器初始化 GPIO 是通过 HAL_GPIO_Init 函数完成:
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
该函数有两个参数,第一个参数是用来指定需要初始化的 GPIO 对应的 GPIO 组,取值范围为 GPIOA~GPIOK。第二个参数为初始化参数结构体指针,结构体类型为 GPIO_InitTypeDef。下面我们看看这个结构体的定义:
typedef struct
{
uint32_t Pin; //指定 IO 口
uint32_t Mode; //模式设置
uint32_t Pull; //上下拉设置
uint32_t Speed; //速度设置
uint32_t Alternate;//复用映射配置
} GPIO_InitTypeDef;
初始化 GPIO 的常用格式是:
GPIO_InitTypeDef GPIO_Initure;
GPIO_Initure.Pin=GPIO_PIN_0; //PB0
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
设置 PB0 端口为推挽输出模式,输出速度为高速,上拉。从上面初始化代码可以看出,结构体 GPIO_Initure 的第一个成员变量 Pin 用来设置是要初始化哪个或者哪些 IO 口。第二个成员变量 Mode 是用来设置对应 IO 端口的输出输入端口模式,这个变量实际配置的是 GPIOx 的 MODER 寄存器。第三个成员变量 Pull 是用来设置上拉还是下拉,配置的是 GPIOx PUPDR 寄存器。第四个成员变量 Speed 用来设置输出速度,配置的是 GPIOx OSPEEDR 寄存器。第五个成员变量 Alternate,它是用来设置引脚的复用映射的。
5.端口输入数据寄存器(GPIOx_IDR)
该寄存器用于读取 GPIOx 的输入数据,

该寄存器用于读取某个 IO 的电平,如果对应的位为0(IDRy=0),则说明该 IO 输入的是低电平,如果是 1(IDRy=1),则表示输入的是高电平。HAL 库操作该寄存器读取 IO 输入数据相关函数:
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
该函数用来读取一组IO下一个或者多个IO口电平状态。比如我们要读取GPIOF.5的输入电平,方法为:
HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_5);//读取 PF5 的输入电平
该函数返回值就是 IO 口电平状态。
6.端口输出数据寄存器(GPIOx_ODR)
该寄存器用于控制 GPIOx 的输出电平,

该寄存器用于设置某个 IO 输出低电平(ODRy=0)还是高电平(ODRy=1),该寄存器也仅在输出模式下有效,在输入模式(MODER[1:0]=00/11 时)下不起作用。该寄存器在 HAL 库中使用不多,操作这个寄存器的库函数主要是 HAL_GPIO_TogglePin 函数:
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
该函数是通过操作 ODR 寄存器,达到取反 IO 口输出电平的功能。
7.端口置位/复位寄存器(GPIOx_BSRR)
该寄存器和 ODR寄存器具有类似的作用,都可以用来设置 GPIO 端口的输出位是 1 还是 0。

对于低 16 位(0-15),我们往相应的位写 1,那么对应的 IO 口会输出高电平,往相应的位写 0,对 IO 口没有任何影响。高 16 位(16-31)作用刚好相反,对相应的位写 1 会输出低电平,写 0 没有任何影响。也就是说,对于 BSRR 寄存器,你写 0 的话,对 IO 口电平是没有任何影响的。我们要设置某个 IO 口电平,只需要相关位设置为 1 即可。而 ODR 寄存器,我们要设置某个 IO口电平,我们首先需要读出来 ODR 寄存器的值,然后对整个 ODR 寄存器重新赋值来达到设置某个或者某些 IO 口的目的,而 BSRR 寄存器,我们就不需要先读,而是直接设置即可,这在多任务实时操作系统中作用很大。
BSRR 寄存器使用方法如下:
GPIOA->BSRR=1<<1; //设置 GPIOA.1 为高电平
GPIOA->BSRR=1<<(16+1)//设置 GPIOA.1 为低电平;
库函数操作 BSRR 寄存器来设置 IO 电平的函数为:
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
该函数用来设置一组 IO 口中的一个或者多个 IO 口的电平状态。比如我们要设置 GPIOB.5 输出高,方法为:
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET); //GPIOB.5 输出高
设置 GPIOB.5 输出低电平,方法为:
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, GPIO_PIN_RESET); //GPIOB.5 输出低
8.端口配置锁定寄存器(GPIOx_LCKR)

9.复用功能寄存器(GPIOx_AFRL、AFRH)
分高位AFRH和低位AFRL,分别控制8个IO口。这两个寄存器是用来设置 IO 口的复用功能的。实际上,在我们调用函数 HAL_GPIO_Init 的时候,如果我们设置了初始化结构体成员变量 Mode 为复用模式,同时设置了 Alternate 的值,那么会在该函数内部自动设置这两个寄存器的值,达到设置端口复用映射的目的。

四、GPIO常用库函数
-
初始化函数:
HAL_GPIO_Initvoid HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);作用:初始化一个或者多个
IO口(同一组)的工作模式,输出类型,速度以及上下拉方式。
GPIO_Init函数初始化样例:GPIO_InitTypeDef GPIO_Initure; GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1; //PB1,0 GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速 HAL_GPIO_Init(GPIOB,&GPIO_Initure); -
读取输入电平函数:
HAL_GPIO_ReadPinGPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);作用:读取某个
GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。 -
设置输出电平函数:
HAL_GPIO_WritePinvoid HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState); -
电平翻转函数:
HAL_GPIO_TogglePinvoid HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); -
引脚电平锁定函数:
HAL_GPIO_LockPinHAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); -
外部中断相关函数
五、配置HAL库操作IO口步骤
- 初始化
HAL库:HAL_Init(); - 初始化系统时钟 :
Stm32_Clock_Init( ); - 使能IO口时钟。
操作寄存器:配置IO口时钟使能寄存器:RCC->AHB1ENR
HAL库方法:__HAL_RCC_GPIOB_CLK_ENABLE(); - 初始化
IO口模式。
操作寄存器:GPIOx_MODER OTYPER OSPEEDR PUPDR
HAL库方法:HAL_GPIO_Init(); - 操作
IO口,输出高低电平。
操作寄存器:配置寄存器GPIOX_ODR或者GPIOx_BSRR。
HAL库方法:HAL_GPIO_WritePin();


















