细说HAL_GPIO_TogglePin()函数写BSSR寄存器的原理

发布于:2024-04-27 ⋅ 阅读:(30) ⋅ 点赞:(0)

目录

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


网站公告

今日签到

点亮在社区的每一天
去签到