本文主要是介绍细说HAL_GPIO_TogglePin()函数写BSSR寄存器的原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
1.GPIO端口寄存器
2.HAL_GPIO_TogglePin()函数的定义
(1) 详细解读odr=GPIOx->ODR
(2)详细解读给BSRR寄存器赋值
(3)给BSRR寄存器的相应位赋值就可以改变PB3的引脚状态
(4)BRR寄存器
(5)ODR寄存器
1.GPIO端口寄存器
在结构体GPIO_TypeDef中,11个GPIO端口寄存器都是32位。其中,有4个配置寄存器(GPIOx_MODER,GPIOx_OTYPER,GPIOx_OSPEEDR和GPIOx_PUPDR)、2个数据寄存器(GPIOx_IDR和GPIOx_ODR)、1个置位/复位寄存器(GPIOx_BSRR)、1个锁定(locking)配置寄存器(GPIOx_LCKR)、2个功能选择寄存器(alternate function selection registers,GPIOx_AFRH和GPIOx_AFRL)和1个按位复位寄存器GPIO_BRR。因为STM32G4xx中有7个GPIO端口,所以上述寄存器中的x是指A、B、C、D、E、F、G。
譬如GPIO端口B的输出寄存器,就是GPIOB_ODR。
2.HAL_GPIO_TogglePin()函数的定义
重写函数HAL_GPIO_TogglePin():
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{uint32_t odr;assert_param(IS_GPIO_PIN(GPIO_Pin));odr = GPIOx->ODR;GPIOx->BSRR = ((odr & GPIO_Pin)<<GPIO_NUMBER)|(~odr & GPIO_Pin);
}
第一个参数GPIOx的类型为GPIO_TypeDef,也就是说,GPIOx只能是结构体GPIO_TypeDef的或员,即GPIO端口的寄存器。注意,在函数HAL_GPIO_TogglePin()的参数义中,参数GPIOx的前面有个“*”,表示GPIOx这个变量是一个指针型变量。因此,在访问结构体成员时,就要采用指针的形式。
(1) 详细解读odr=GPIOx->ODR
首先,语句odr=GPIOx->ODR,表示用指计形式访间GPIO端口的输出数据寄有(ODR),输出寄存器ODR的值也就是该寄存器所对应端口的状态。前面调用函数HAL_GPIO_TogglePin时,用的参数是LED3_GPIO_Port,而LEDB_GPIO_Port在main.h文件中定义为GPIOB,所以程序运行到此处,odr = GPIOx→ODR就是取出GPIOB的输出数寄存器的值,赋给变量odr。
(2)详细解读给BSRR寄存器赋值
其次,函数的最后一条语句,是一个给BSRR寄存器赋值的语句:
GPIOx->BSRR = ((odr & GPIO_Pin)<<GPIO_NUMBER)|(~odr & GPIO_Pin);
语句中,等号右侧将odr“与”GPIO_Pin后左移GPIO_NUMBER(在stm32g4xx_hal_gpio.c中有定义,为16)位,然后与~odr &.GPIO_Pin的结果相“或”,结果赋值给BSRR寄存器。
GPIO_Pin是HAL_GPIO_TogglePin函数的第2个参数,它的值为16位无符号数(uint16_t),本例对应的是PB3,所以该值为0x0008(从右侧数第3位为1,其余均为0)。
将odr“与”GPIO_Pin后即可得到当前PB3引脚的状态:如果PB3引脚的状态为1(高电平),“与”后的结果为0x0008,将此结果左移16位(GPIO_NUMBER),也就是移位到高16位(odr被定义为32位无符号数),移位后第19位为1;如果PB3引脚的状态为0(低电平),相“与”后的结果为0x0,移位后第19位同样也为0。
odr取“反”后与GPIO_Pin相“与”的含义。仍然以PB3为例,如果PB3引脚当前状态为1,取反(~)后为0,则与GPIO_Pin相“与”后的结果为0x0;如果PB3引脚当前状态0,则相“与”后的结果为0x0008。
这样,这条赋值语句执行后的结果就比较清楚了:当I/O引脚状态为1时,等号右侧“或”之前括号内的值为1,之后的为0;当I/O引脚状态为0时,之前的值为0,之后的值为1。但“或”之前的值会移位到高16位,“或”之后的值则没有移位。也就是说,当I/O引脚状态为1时,给BSRR寄存器的高16位赋值;当I/O引脚状态为0时,给低16位赋值。
(3)给BSRR寄存器的相应位赋值就可以改变PB3的引脚状态
在STM32G4系列MCU的参考手册中,查到BSRR寄存器的结构:
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
BR15 | BR14 | BR13 | BR12 | BR11 | BR10 | BR9 | BR8 | BR7 | BR6 | BR5 | BR4 | BR3 | BR2 | BR1 | BR0 |
w | w | w | w | w | w | w | w | w | w | w | w | w | w | w | w |
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
BS15 | BS14 | BS13 | BS12 | B811 | BS10 | BS9 | BS8 | BS7 | BS6 | BS5 | BS4 | BS3 | BS2 | BS1 | BS0 |
w | w | w | w | w | w | w | w | w | w | w | w | w | w | w | w |
BSRR寄存器的高16位为BR[15:0],其中BR是指bit reset,按位复位;低16位为BS[15:0],其中BS是指bit set,按位置位。这些位都是只写(write-only,字母w表示只写)的,读它是没有意义的只是返回0而已。BR[15;0]中的某位为1,会复位相应的输出数据位(ODx,即输出数据寄存器中的某位);SR[15:0]中的某位为1,会置位相应的输出数据位(ODx)。当然,要在硬件上实现端口或引脚输出状态的变化,是需要相应电路来实现的;不过,对使用者来说,需要的只是配置相应的的寄存器。
于是,库函数HAL_GPIO_TogglePin()通过操作GPIO的BSRR寄理了翻转I/0引脚状态的目的。
(4)BRR寄存器
在STM32G4系列MCU的参考手册中,查到BRR寄存器的结构:
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res |
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
BR15 | BR14 | BR13 | BR12 | BR11 | BR10 | BR9 | BR8 | BR7 | BR6 | BR5 | BR4 | BR3 | BR2 | BR1 | BR0 |
w | w | w | w | w | w | w | w | w | w | w | w | w | w | w | w |
BRR寄存器虽然是32位的,但实际用到的只是低16位,分别对应该GPIO端口的16个I/O。BRR寄存器的低16位与BSRR寄存器的高16都是按位复位寄存器(BR[15:0]),所起的作用是一样的。
(5)ODR寄存器
GPIO的BRR和BSRR对输出引脚状态的改变,是与ODR相一致的。也就是说,PB3通过BRR复位后,GPIOB的ODR寄存器的相应位(第3位)的值也会变为0。ODR也只是用了低16位,分别对应GPIO端口的16个引脚,OD[15:0]就是相应引脚的状态数据,rw表示该位可读可写。
在STM32G4系列MCU的参考手册中,查到ODR寄存器的结构:
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res | Res |
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
OD15 | OD14 | OD13 | OD12 | OD11 | OD10 | OD9 | OD8 | OD7 | OD6 | OD5 | OD4 | OD3 | OD2 | OD1 | OD0 |
rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw |
这篇关于细说HAL_GPIO_TogglePin()函数写BSSR寄存器的原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!