STM32F4xx的GPIO可以分为GPIOA到GPIOK个端口,每个端口有16个IO口。
对每个GPIO端口,STM32F4xx安排了4个32位配置寄存器(GPIOx_MODER、GPIOx_OTYPER、GPIOx_OSPEEDR、GPIOx_PUPDR)用于对端口内的每个IO口进行配置,安排2个32位数据寄存器(GPIOx_IDR、GPIOx_ODR)用于每个端口的数据输入输出存储,此外,还安排了1个32位置位/复位寄存器(GPIOx_BSRR),1个32位锁定寄存器(GPIOx_LCKR)和2个32位复用功能选择寄存器(GPIOx_AFRH、GPIOx_AFRL)。
对每一个IO口而言,用户可以根据需要将其配置为通用输入模式,通用输出模式,内部外设复用模式,以及模拟模式,这些模式的设置通过对GPIOx_MODER设置完成。GPIOx_MODER的32位中每2位对应其组内的一个IO口(共16个),可以设置为上述的4个模式之一。
若某个IO口设置为输出模式则表明可以通过该IO口输出数字信号0或1(底或高电平)。可以通过设置GPIOx_OTYPER寄存器将该IO口设置为推挽输出或者开漏输出模式之一,32位的GPIOx_OTYPER的0~15位每位控制一个IO口。此外,通过寄存器GPIOx_OSPEEDR可以将口的输出速度设置为低速(2MHz)、中速(25MHz)、快速(50MHz)、高速(100MHz)四种模式之一。同样,32位的GPIOx_OSPEEDR每2位控制一个IO口。此时,数据输出寄存器GPIOx_ODR的0~15每一位对应于一个IO口的数据,可以对其进行读写。
若某个IO口设置位输入模式则表明可以通过该IO口输入数字信号0或1。通过设置GPIOx_PUPDR寄存器将该IO口设置为无上拉下拉、上拉、下拉3种模式之一。同样,32位GPIOx_PUPDR寄存器依然是每2位控制一个IO口。此时,数据输入寄存器GPIOx_IDR每隔1个AHB1时钟周期对输入IO口进行一次采样以获得IO口电平数据,它的0~15每一位对应一个IO口的数据,可以对该寄存器以字的方式读取。
STM32F4有很多内置外设,这些内置外设的外部引脚可以与GPIO复用,即对某个特定的IO口而言,我们可以设置其为通用的IO数字输入输出口或者模拟口,也可以将其设置为功能复用模式,此时该IO口就与被设置的内置外设的相关引脚关联,可以进行该外设相关引脚的输入或者输出操作。在硬件上,每个IO口都有一个复用器连接到内置外设。每个复用器有16个输入,即表明一个IO口可以和16个不同的外设相联。但同一时间复用器只允许一个外设的复用功能连接到IO引脚以保证共用一个IO引脚的外设之间不发生冲突。另外,不是每个IO口都可以复用为任意外设的复用功能,哪些IO口可以复用哪些外设的复用功能可以查找数据手册中的相关资料。当把某个IO口设置为内置外设的复用功能时,我们有以下工作需要明确:
将该IO口的GPIOx_MODER设置为功能复用模式(但要注意,若使用DAC或者ADC,要将相应IO口设置为模拟模式);
根据该复用IO口对应的内置外设的输入输出需求设置输入输出方式(GPIOx_PUPDR、GPIOx_OTYPER)和速度(GPIOx_OSPEEDR);
由于每个IO口的复用器有16个输入连接到不同的外设复用管脚,每次到底复用哪个外设是通过前述的两个32位复用功能选择寄存器GPIOx_AFRL和GPIOx_AFRH来控制的,其中GPIOx_AFRL控制IO口0~7,GPIOx_AFRH控制IO口8~15,每个IO口占4位,对这4位设置相应的值就可以选择IO口复用16个外设的哪个外设。
32位的复位/置位寄存器GPIOx_BSRR用于对每个端口的各IO口分别进行复位或者置位操作。其中0~15位用于对相应的IO口进行置位操作,将相应的位写1则会对对应的IO口置位,写0不产生任何操作;16~31位用于对相应的IO口进行复位,将相应的位写1则会对对应的IO口置位,写0不产生任何操作。当IO口为输出模式时,除了直接向该口写入相应的输出值,也可以采用复位/置为方式对该IO口输出1或0。
32位的锁定寄存器GPIOx_LCKR用于锁定特定IO口的配置,具体的操作可以参考相应手册内容。
GPIO的标准固件库操作
如果对STM32F4的GPIO相关寄存器操作非常熟悉的话,我们当然可以直接操作寄存器完成相关的GPIO端口操作。但为了简化这些操作,标准固件库提供了相应的定义、申明和函数给我们直接使用和调用。STM32F4的GPIO部件的相关申明与定义在头文件stm32f4xx.h中,另外的GPIO相关的定义、申明和函数及其实现都在stm32f4xx_gpio.h和stm32f4xx_gpio.c中。通过这些申明、定义和实现,我们能够较方便的进行GPIO的应用编程。
当我们要进行GPIO应用编程时,通常要进行以下几步操作:
使能要使用的IO口相应组的外设时钟;
对要使用的IO口进行初始化设置,通常包含如下信息:设置哪个IO口,IO口的使用模式(输入、输出、模拟、功能复用),输出类型和速度、输入类型、复用外设连接等;
使用该IO口进行相应的操作(读、写、复位、置位等)。
标准固件库对涉及上述操作的基本数据结构,用到的设备部件,以及相关的函数已经定义和实现完成,我们需要熟悉这些定义,或者在使用的时候能够知道如何找到这些定义。其中主要包括:
对GPIO相关的寄存器的定义GPIO_TypeDef(stm32f4xx.h中):
typedef struct
{
__IO uint32_t MODER; /*模式寄存器GPIOx_MODER*/
__IO uint32_t OTYPER; /*输出类型寄存器GPIOx_OTYPER*/
__IO uint32_t OSPEEDR; /*输出速度寄存器GPIOx_OSPEEDR*/
__IO uint32_t PUPDR; /*输入类型寄存器GPIOx_PUPDR*/
__IO uint32_t IDR; /*输入数据寄存器GPIOx_IDR*/
__IO uint32_t ODR; /*输出数据寄存器GPIOx_ODR*/
__IO uint16_t BSRRL; /*置位复位寄存器GPIOx_BSRR的0~15位,即置位寄存器*/
__IO uint16_t BSRRH; /*置位复位寄存器GPIOx_BSRR的16~31位,即复位寄存器*/
__IO uint32_t LCKR; /*锁存寄存器GPIOxd_LCKR*/
__IO uint32_t AFR[2]; /*复用功能选择寄存器组GPIOx_AFRL和GPIOx_AFRH */
} GPIO_TypeDef;
同时,针对各GPIO组,stm32f4xx.h中定义了指向各寄存器组的上述类型的指针GPIO_TypeDef* GPIOA~GPIOK,我们在程序中可以直接引用。比如,直接在程序中写GPIOG->IDR即是在访问GPIOG的输入数据寄存器;写GPIOG->BSRRL=0x08即表明将GPIOG的第4个IO口置位。
为了方便对GPIO进行初始化,在stm32f4xx_gpio.h中定义了相应的初始化结构GPIO_InitTypeDef:
typedef struct
{
uint32_t GPIO_Pin; /*进行初始化的IO口*/
GPIOMode_TypeDef GPIO_Mode; /*GPIO模式,由GPIOMode_TypeDef定义*/
GPIOSpeed_TypeDef GPIO_Speed; /*输出速度,由GPIOSpeed_TypeDef定义*/
GPIOOType_TypeDef GPIO_OType; /*输出类型,由GPIOOType_TypeDef定义*/
GPIOPuPd_TypeDef GPIO_PuPd; /*输入类型,由GPIOIType_TypeDef定义*/
}GPIO_InitTypeDef;
上述结构的每个成员正好对应对IO口初始化时需要设置的相关寄存器的值,而能够取的值也由后面注释中对应的宏或者枚举在stm32f4xx_gpio.h中声明好了,如IO口GPIO_Pin的取值通过宏定义为GPIO_Pin_0到GPIO_Pin_15,如IO模式GPIO_Mode的值通过枚举定义为GPIO_Mode_IN(输入),GPIO_Mode_OUT(输出),GPIO_Mode_AF(功能复用),GPIO_Mode_AN(模拟),我们可以直接使用这些值。此外,stm32f4xx_gpio.h和stm32f4xx_gpio.c中还声明和实现了IO初始化函数void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct),我们可以直接使用已经为我们准备好的数据和函数即可方便地完成初始化,如下例:
GPIO_InitTypeDef GPIO_InitStructure; /*申明初始化结构*/
void main() {
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);/*使能GPIOG的时钟*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6; /*IO口5和6*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; /*输出模式*/
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /*推挽输出*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; /*速度100MHz*/
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; /*无上拉下拉*/
GPIO_Init(GPIOG, &GPIO_InitStructure); /*调用函数初始化*/
……
}
当我们要使用的IO口的初始化完成后,即可根据需要对IO口进行访问和使用。为了方便我们的使用,stm32f4xx_gpio.h中也申明了相关函数供我们使用,主要包括:
/* 恢复GPIO为默认配置 ****/
void GPIO_DeInit(GPIO_TypeDef* GPIOx);
/* 配置相关函数 *********************************/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);/*GPIO初始化*/
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);/*初始化结构赋值*/
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);/*配置锁定*/
/* 读写函数 **********************************************/
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);/*输入位读*/
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);/*输入读*/
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);/*输出位读*/
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);/*输出读*/
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);/*置位*/
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);/*复位*/
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);/*输出位写*/
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);/*输出写*/
void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);/*输出位反转*/
/* 功能复用配置函数****************************/
void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF);
我们利用这些函数,可以对GPIO进行更多的操作。如上例我们可以修改为:
GPIO_InitTypeDef GPIO_InitStructure; /*申明初始化结构*/
void main() {
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);/*使能GPIOG的时钟*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6; /*IO口5和6*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; /*输出模式*/
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /*推挽输出*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; /*速度100MHz*/
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; /*无上拉下拉*/
GPIO_Init(GPIOG, &GPIO_InitStructure); /*调用函数初始化*/
while(1) {
GPIO_SetBits(GPIOG,GPIO_Pin_5|GPIO_Pin_6);/*置位*/
GPIO_ResetBits(GPIOG,GPIO_Pin5|GPIO_Pin_6);/*复位*/
}
}
则实现了对端口GPIOG的IO口5和IO口6的反复置位和复位。当然,我们也可以直接访问相应的寄存器实现这个功能:
while(1) {
GPIOG->BSRRL=GPIO_Pin_5|GPIO_Pin_6;/*置位*/
GPIOG->BSRRH=GPIO_Pin5|GPIO_Pin_6;/*复位*/
}
设计资源 培训 开发板 精华推荐
- LTC1981 的典型应用 - SOT-23 中的单通道和双通道微功率高侧开关控制器
- SSTC+PLLSSTC双TC合体板
- 基于CY7C63723/CY7C63722芯片的鼠标电路图及PCB和源代码
- 使用 Diodes Incorporated 的 ZXCD1000 的参考设计
- 68键机械键盘
- LTC3631EDD 演示板、高效率、高电压 100mA 同步降压转换器
- 创意小台灯
- LTC4071EDDB 演示板,具有低电池电量断开连接的锂离子/聚合物并联电池充电器系统
- NCP330MUTBGEVB:受控 3.0 A 负载开关、软启动、评估板
- RP505Kxx1B 1A PWM/VFM 降压 DC/DC 转换器的典型应用,带同步整流器