一、用法
经常会看到类似如下的宏定义语句,用于对已经初始化后的 io 口输出高、低电平。
#define set_bl_high() gpioa-》bsrr=gpio_pin_0
#define set_bl_low() gpioa-》brr=gpio_pin_0
其作用类似于如下两个库函数,
void gpio_setbits(gpio_typedef* gpiox, uint16_t gpio_pin)
void gpio_resetbits(gpio_typedef* gpiox, uint16_t gpio_pin)
而且实际上这两个库函数就是通过修改bsrr,brr寄存器的值来实现对 io 口设置的。如下便是输出高电平的函数体:
void gpio_setbits(gpio_typedef* gpiox, uint16_t gpio_pin)
{
/* check the parameters */
assert_param(is_gpio_all_periph(gpiox));
assert_param(is_gpio_pin(gpio_pin));
gpiox-》bsrr = gpio_pin;
}
因此,使用宏或者库函数本质上都是一样的。区别在于使用宏更快,而使用函数更灵活。
二、解释
bsrr 和 brr 都是 stm32 系列 mcu 中 gpio 的寄存器。 bsrr 称为端口位设置/清楚寄存器,brr称为端口位**寄存器。
bsrr 低 16 位用于设置 gpio 口对应位输出高电平,高 16 位用于设置 gpio 口对应位输出低电平。
brr 低 16 位用于设置 gpio 口对应位输出低电平。高 16 位为保留地址,读写无效。
所以理论上来讲,brr 寄存器的功能和 bsrr 寄存器高 16 位的功能是一样的。也就是说,输出低电平的宏语句,可以有如下两种写法。
#define set_bl_low() gpioa-》brr=gpio_pin_0
等价于
#define set_bl_low() gpioa-》bsrr=gpio_pin_0 《《 16
这么来看的话,其实 brr 寄存器是比较多余的。而实际上,在最新的 stm32f4 系列 mcu 的 gpio 寄存器中,已经找不到 brr 寄存器了,仅保留了 bsrr 寄存器用于实现端口输出高低电平。因此,在 stm32f4 系列 mcu 的库函数中,对 gpio 口输出高低电平的函数为如下形式:
void hal_gpio_writepin(gpio_typedef* gpiox, uint16_t gpio_pin, gpio_pinstate pinstate)
{
/* check the parameters */
assert_param(is_gpio_pin(gpio_pin));
assert_param(is_gpio_pin_action(pinstate));
if(pinstate != gpio_pin_reset)
{
gpiox-》bsrr = gpio_pin;
}
else
{
gpiox-》bsrr = (uint32_t)gpio_pin 《《 16u;
}
}
可见,不管是输出高还是输出低,都是对 bsrr 寄存器的操作。
三、bsrr、brr、 odr 之间的关系
配置 bsrr , brr 是为了对端口输出进行配置,而 odr 寄存器也是用于输出数据的寄存器,一个 odr 寄存器控制了一组(16位)的 gpio 输出。因此,对 odr 进行修改也可以到达对 io 口输出进行配置。
但是,由于对 odr 寄存器的读写操作必须以 16 位的形式进行。因此,如果使用 odr 改写数据以控制输出时,须采用“读-改-写”的形式进行。
假设需要对 gpioa_pin_6 输出高电平。采用改写 odr 寄存器的方式时,使用“读-改-写”操作,代码如下:
uint32_t temp;
temp = gpioa-》odr;
temp = temp | gpio_pin_6;
gpioa-》odr = temp;
而使用改写 bsrr 寄存器时,仅需要使用如下语句:
gpioa-》bsrr = gpio_pin_6;
这是因为在修改 odr 时,为了确保对端口 6 的修改不会影响到其他端口的输出,需要对端口的原始数据进行保存,之后再对端口 6 的值进行修改,最后再写入寄存器。而对 bsrr 的操作,是写 1 有效,写 0 不改变原状态,因此可以对端口 6 置 1,其他位保持为 0。bsrr 为 1 的位,会修改相应的 odr 位,从而控制输出电平。
对 bsrr 的操作可以实现原子操作。因此在设置单个 io 口输出时,使用 bsrr 进行操作会更加方便。
但也有例外的时候,在需要对单个io口进行 toggle 操作时(即对当前输出取反输出,当前输出为高则输出低,当前输出低则输出高),官方的库函数就是直接对 odr 寄存器进行操作的。代码如下:
void hal_gpio_togglepin(gpio_typedef* gpiox, uint16_t gpio_pin)
{
/* check the parameters */
assert_param(is_gpio_pin(gpio_pin));
gpiox-》odr ^= gpio_pin;
}
这是因为,0 和 1 与 1 进行异或操作被取反,0 和 1 与 0 进行异或操作保持原值。如下:
0 ^ 1 = 1
1 ^ 1 = 0
0 ^ 0 = 0
1 ^ 0 = 1
HTTP协议培训教程资料
H3CX3至尊版无线路由器评测 在游戏加速方面的表现是传统无线路由器所不能比拟的
SMT贴片加工必备:全面解析锡膏种类与特性
明纬电源60W单组输出导轨电源DRA-60系列介绍
T型滤波器对本地电源的隔离
STM32 BSRR BRR ODR寄存器详情解析
什么是CISC型CPU
孢子捕捉分析仪:纪录微生物世界的细腻之美
特斯拉正研发超过400英里的电动汽车电池
国产晶圆代工厂华虹半导体登录科创板今日申购
2030年全球电动汽车将有1.25亿辆,对电网有何影响?电网又该如何应对?
发挥FPGA优势,培养创新型嵌入式计算人才
如何自制一个带音箱功能的蓝牙鼠标
金士顿A1000固态硬盘评测 好不好用
大华股份创新升级“智慧红绿灯”应用
在SMT贴片加工中AOI和SPI有什么作用
自动驾驶汽车企业无法量产 与谷歌相比差在哪
恶劣工业环境的设计注意事项
湖南长株潭fm频道列表
昆仑芯2代AI芯片为开发者提供灵活便捷的部署方案