每组GPIO端口都有以下寄存器。
两个32位配置寄存器(GPIOx_CRL,CRH)
两个32位数据寄存器(GPIOx_IDR,ODR)
一个32位置位复位寄存器(GPIOx_BSRR:分BSRRH,BSRRL)
一个16位复位寄存器(GPIOx_BRR)
一个32位锁定寄存器(GPIOx_LCKR)
BSRRH 表示BSRR寄存器高16位。某位为’1’,则对应的I/O端口管脚置’0’(低电平);某位为’0’,则对应的I/O端口管脚保持不变。
BSRRL 表示BSRR寄存器低16位。某位为’1’,则对应的I/O端口管脚置’1’(高电平);某位为’0’,则对应的I/O端口管脚保持不变。
为什么配置寄存器有两个:一组GPIO有16个IO口,一个寄存器有32位,配置每个IO口要用4位,32/4=8,一个寄存器只能配置8个IO口,所以要用两个寄存器
CRL,CRH端口配置寄存器
CRL对应Px0-Px7,CRH对应Px8-Px15.
好像没啥好说的,就是gpio_init里那点东西
上拉/下拉输入模式那,还要用ODR寄存器设置一下;ODR是0就是下拉,是1就上拉。(下图)
// 上/下拉输入 PA0
GPIOA->CRL &=0xfffffff0; //让3210位置置0,其他不变
GPIOA->CRL |=0x00000008; //让3210位置置1000,其他不变
//上拉输入;保留的那几个就不用写ffff了,那个随便。
GPIOA->ODR &=0xfffe; //让ODR最后一位置0,就是位置0那里
IDR,ODR数据寄存器
IDR这个就简单,对应位置是0就是那个端口是低电平,1就是高电平;输入输出都是可以读状态的
//要检测PA0的电平
uint16_t x; //定义一个16位的数
uint16_t h=0xffff //1111111111111111
uint16_t l=0xfffe //1111111111111110
x=GPIOE->IDR&0xffbf;
if(x==h)//高电平
....
if(x==l)//低电平
....
也可以这样
if((GPIOE->IDR & l) == GPIOE->IDR)//低电平
....
if((GPIOE->IDR & l) != GPIOE->IDR)//高电平
....
ODR是设置输出端口,设置0就是低电平输出,1就是高电平输出,这个常用(下面的更常用,功能一样)
BSRR端口位设置/清除寄存器
0-15是给对应Px0到Px15高电平,16-31是给对应Px0-Px15低电平
都是置1有效
实际上作用是通过BSRR给ODR配置状态,但为什么不直接给ODR,还要倒手呢。
因为直接用ODR不方便
如果操作ODR寄存器,需要先读出ODR寄存器,然后修改相应的位的值,再写回ODR,分为3步。而BSRR寄存器设置位,只需要对相应的设置或复位的位直接写1,其他位写0(BSRR只对写1有效,写0无意义,不影响原先位的电平),可以直接一步到位。
在实时操作系统和中断会有比较大的意义,如果使用ODR寄存器,可能在读取ODR的值后,被其他优先级更高的操作打断(该高优先级的操作可能也操作了相应ODR),等到高优先级操作完成后再返回接着设置ODR,可能这个过程中ODR的值已经改变
那如果H和L都置1了,那个引脚会怎么样
这个我不清楚为什么,希望知道的能回复一下,实际用的话,后面的有效,举个例子
GPIOA->BSRRL |=1<<9; //这里PA9变高电平
GPIOA->BSRRH |=1<<9; //这里从高电平又变成低电平
BRR复位寄存器
这个就很多余,和BSRRH重复了,F4已经删除
LCKR锁定寄存器
锁住CRL或CRH,让端口再系统复位前不能
其他
//HAL库定义
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
//标准库定义
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint16_t BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */
__IO uint16_t BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
可以看到HAL库没有BSRRL和BSRRH了,只有一个BSRR
那么在HAL库就直接BSRR操作,BSRRL不变,BSRRH就多移动16位
GPIOA->BSRR |= 1<<9<<16