文章目录
- 一、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~GPIOI
9个组,那么一共有对应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_Init
void 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_ReadPin
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:读取某个
GPIO
的输入电平。实际操作的是GPIOx_IDR
寄存器。 -
设置输出电平函数:
HAL_GPIO_WritePin
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
-
电平翻转函数:
HAL_GPIO_TogglePin
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
-
引脚电平锁定函数:
HAL_GPIO_LockPin
HAL_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();