每组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.
image-1676552883687
好像没啥好说的,就是gpio_init里那点东西
上拉/下拉输入模式那,还要用ODR寄存器设置一下;ODR是0就是下拉,是1就上拉。(下图)
image-1676556832263

		//	上/下拉输入 PA0
		GPIOA->CRL &=0xfffffff0;			//让3210位置置0,其他不变
		GPIOA->CRL |=0x00000008;		//让3210位置置1000,其他不变
        //上拉输入;保留的那几个就不用写ffff了,那个随便。
        GPIOA->ODR &=0xfffe;		//让ODR最后一位置0,就是位置0那里

IDR,ODR数据寄存器

image-1676554614335
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)//高电平
....

image-1676555643721
ODR是设置输出端口,设置0就是低电平输出,1就是高电平输出,这个常用(下面的更常用,功能一样)

BSRR端口位设置/清除寄存器

image-1676556960685
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已经删除
image-1676561101559

LCKR锁定寄存器

image-1676561407041
锁住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