高手带你解析STM32 BSRR BRR ODR 寄存器

发布者:一直333最新更新时间:2018-11-23 来源: eefocus关键字:STM32  BSRR  BRR  ODR  寄存器 手机看文章 扫描二维码
随时随地手机看文章

 一、用法


经常会看到类似如下的宏定义语句,用于对已经初始化后的 IO 口输出高、低电平。


#define SET_BL_HIGH() GPIOA->BSRR=GPIO_Pin_0

#define SET_BL_LOW() GPIOA->BRR=GPIO_Pin_012


其作用类似于如下两个库函数,


void GPIO_SetBits(GPIO_Typedef* GPIOx, uint16_t GPIO_Pin)

void GPIO_ResetBits(GPIO_Typedef* GPIOx, uint16_t GPIO_Pin) 12


而且实际上这两个库函数就是通过修改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;

}12345678

因此,使用宏或者库函数本质上都是一样的。区别在于使用宏更快,而使用函数更灵活。


二、解释


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 123


这么来看的话,其实 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;

}

}123456789101112131415

可见,不管是输出高还是输出低,都是对 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;1234

而使用改写 BSRR 寄存器时,仅需要使用如下语句:

GPIOA->BSRR = GPIO_Pin_6;1


这是因为在修改 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;

}1234567

这是因为,0 和 1 与 1 进行异或操作被取反,0 和 1 与 0 进行异或操作保持原值。如下:

0 ^ 1 = 1

1 ^ 1 = 0

0 ^ 0 = 0

1 ^ 0 = 1


关键字:STM32  BSRR  BRR  ODR  寄存器 引用地址:高手带你解析STM32 BSRR BRR ODR 寄存器

上一篇:单片机STM32的几种输入模式以及外部中断的配置
下一篇:STM32比51单片机有什么优点的汇总

推荐阅读最新更新时间:2024-03-16 16:18

STM32 的gpio mode set 详解
最近在看数据手册的时候,发现在Cortex-M3里,对于GPIO的配置种类有8种之多: (1)GPIO_Mode_AIN 模拟输入 (2)GPIO_Mode_IN_FLOATING 浮空输入 (3)GPIO_Mode_IPD 下拉输入 (4)GPIO_Mode_IPU 上拉输入 (5)GPIO_Mode_Out_OD 开漏输出 (6)GPIO_Mode_Out_PP 推挽输出 (7)GPIO_Mode_AF_OD 复用开漏输出 (8)GPIO_Mode_AF_PP 复用推挽输出 对于刚入门的新手,我想这几个概念是必须得搞清楚的,平时接触的最多的也就是推挽输出、开漏输出、上拉输入这三种,但一直未曾对这些做过归纳。因此,在这里做一个总
[单片机]
<font color='red'>STM32</font> 的gpio mode set 详解
QuarkLink如何在STM32和STSAFE上进行安全的云管理
开发人员如何安全地将数千台STM32物联网设备配置并载入云服务?答案可能是QuarkLink™,这是意法半导体合作伙伴计划成员Crypto Quantique的解决方案,可促进密钥管理,自动化入职程序,并提供远程管理设备的仪表板。该解决方案可与STM32微控制器或STSAFE-A110安全元件配合使用。该公司还提供在B-L4S5I-IOT01A Discovery工具包上运行并连接到AWS的试用版。因此,开发人员可以快速测试 QuarkLink 的 API 和服务。该解决方案还支持Microsoft Azure,Eclipse Mosquitto,甚至可以适应独特的云计算平台。 uarkLink,物联网的安全性远不止密码学 为
[单片机]
STM32部分知识之SPI原理与配置
SPI接口简介:(同样是基于正点原子F4) SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。 SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。 PI接口框图 SPI内部结构简明图 SPI接口一般使用4条线通信: MISO 主设备数据输入,从设备数据输出。 MOSI 主设备数据输出,从设备数据输入。
[单片机]
<font color='red'>STM32</font>部分知识之SPI原理与配置
STM32 CubeMX 中如何查看系统时钟
代码如下: uint32_t sysclock = 0; sysclock = HAL_RCC_GetSysClockFreq(); 这样就可以在线仿真时看sysclock了,以判断单片机是否正常运行。这些函数都在rcc这个库文件里面,还可以查看时钟树上其他总线上的时钟。
[单片机]
位带操作在stm32中的C语言实现
首先: #define BITBAND(addr,bitnum) ((addr & 0xF0000000) + 0x2000000 + ((addr & 0xFFFFF) 5) + (bitnum 2)) 对上句程序的解释: 利用宏定义的方式将位带地址的映射表示出来,该函数有两个参数addr和bitnum,分别是原本的地址和在数据中的第几位。我们知道两个公式如下: 0x2000_0000‐0x200F_FFFF地址空间:AliasAddr = 0x22000000 + (A 0x20000000)*32 + n*4 0x4000_0000‐0x400F_FFFF地址空间:AliasAdd
[单片机]
毕业设计| 球上自平衡机器人
该机器人根据陀螺仪的位姿数据,通过三个全向轮驱动底部球体调整自己在球上的位置,保持动态平衡的同时实现全向移动。 保持动态平衡过程需要对机器人进行运动学分析 自平衡控制问题转化为三步:输入X、Y角度—控制器计算—输出A、B、C电机转速的控制模型。 # 控制器设计 # 首先考虑参考平衡车控制,球上自平衡机器人本质上依然是一个一阶倒立摆问题 这里参考了飞思卡尔直立车的控制方法,采用串级PID控制器,外环PD角度环,内环速度PI环。 由于我的驱动方案选择的是42步进电机,在速度闭环的时候有些问题。正常的直流电机+编码器的控制方案可以通过编码器将轮子的真实速度计算出来,从而和控制器的理想转速作差,实现速度控制。 而我这里的速度闭
[单片机]
毕业设计| 球上自平衡机器人
一步一步实现STM32-FOTA系列教程之Bootloader编写
前言 上一篇文章《一步一步实现STM32-FOTA系列教程之FLASH静态区读写》实现了对FLASH静态区读写的操作,有了这部分功能之后,就可以实现一个非常简单的Bootloader代码了。 转载请注明出处 Bootloader 功能说明 这里提供的Bootloader功能就非常的简单了,就是在Bootloader启动之后,读取FLASH静态区的参数信息,然后判断启动分区标志位的值,然后进入相应的分区,运行该分区的程序。 注意这里的教程中没有在 Bootloader 中编写联网获取新版本的代码,这部分的实现会放到主分区和备份分区的代码中实现。 Bootloader 启动流程 这个启动流程之前已经说过了,这里贴出来,
[单片机]
一步一步实现STM32-FOTA系列教程之Bootloader编写
基于STM32实现串口的两个分案解析
首先总结一下串口232,422,485 串口232:可双向传输,全双工,最大速率20Kbps,负逻辑电平,-15V~-3V逻辑“1”,+3V~+15V逻辑“0”。 串口422:可双向传输,4线全双工,2线单工。 串口485:可双向传输,4线全双工,2线单工,最大速率10Mb/s,差分信号,发送端:+2V~+6V逻辑“1”,-2V~-6V逻辑“0”,接收端:+200mV逻辑“1”,-200mV逻辑“0”。 对于串口的实现有以两个方案: 方案一,和原子的《例说STM32》一样,首先接收,然后处理,没有消息验证处理,这样就会出现消息覆盖,消息出错后死机,无法明确区分命令,无法及时应答握手信号。方案二,借鉴uC/OSII的消息队列,进
[单片机]
基于<font color='red'>STM32</font>实现串口的两个分案解析
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved