历史上的今天
返回首页

历史上的今天

今天是:2024年08月26日(星期一)

正在发生

2018年08月26日 | STM32 BSRR BRR ODR 寄存器解析

2018-08-26 来源:eefocus

一、用法


经常会看到类似如下的宏定义语句,用于对已经初始化后的 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


推荐阅读

史海拾趣

Brilliance公司的发展小趣事

随着市场竞争的加剧,Brilliance公司意识到只有不断创新才能在行业中立足。于是,公司加大了对研发的投入,引进了一批高端人才和先进设备。经过无数次的试验和改进,Brilliance成功研发出了一项具有颠覆性的技术,并将其应用于新产品中。这款新产品不仅性能卓越,而且具有极高的性价比,迅速占领了市场份额。

ETA Electric Industry Co Ltd公司的发展小趣事

随着技术实力的增强,ETA Electric Industry Co Ltd开始积极拓展国内外市场。他们参加了多个国际电子展会,与世界各地的潜在客户建立了联系。同时,公司还加强了与国内外大型电子企业的合作,为其提供定制化的解决方案。这些举措极大地提升了公司的知名度和市场份额,为公司的快速发展奠定了基础。

友盟(AP)公司的发展小趣事

友盟(AP)公司在电子行业的崛起,始于其坚持不懈的技术创新。在创立初期,友盟就敏锐地捕捉到了移动互联网快速发展的趋势,投入大量资源进行技术研发。公司团队深入研究用户行为分析、大数据分析等前沿技术,不断推出具有创新性的产品和服务。通过精准的数据分析和个性化推荐,友盟成功帮助众多合作伙伴提升了用户体验和业务效率,逐渐在行业内树立起了良好的口碑。

Elpac公司的发展小趣事

Elpac公司深知人才是企业发展的核心动力。因此,公司高度重视人才培养和团队建设。公司建立了完善的人才培训体系,为员工提供多样化的培训和发展机会。同时,公司还鼓励员工积极参与各种创新活动和竞赛,激发员工的创新精神和创造力。这种积极向上的企业文化吸引了大量优秀人才加入Elpac公司,为公司的持续发展提供了有力保障。

Conexcon Group公司的发展小趣事

面对日益激烈的市场竞争,Conexcon Group积极寻求与国内外知名企业的战略合作。通过与行业巨头的联合研发和市场推广,公司成功将自身产品推向了更广阔的市场。同时,这些合作也为公司带来了先进的技术和管理经验,进一步提升了公司的核心竞争力。在合作中,Conexcon Group始终坚持开放、共赢的原则,与合作伙伴共同推动电子行业的发展。

Holy Stone公司的发展小趣事

在追求业务发展的同时,Holy Stone始终注重品质提升和环境管理。公司陆续通过了ISO9001、ISO14001、QS9000、ISO/TS16949等国际认证,确保了产品的高品质和环保性。这些认证不仅提升了公司的品牌形象和市场竞争力,还为客户提供了更加可靠的产品和服务。此外,公司还积极履行社会责任,在环境治理、社会参与等方面做出了具体贡献。

问答坊 | AI 解惑

自己动手制作机器人,看起来很好玩

来源:窗户纸  http://www.getproject.com.cn/post/98.html 机器人,听起来挺神秘的,在大多数科幻电影和文学作品中,机器人通常无所不知,无所不能,跟人类相比起来,简直就是完美无瑕了。因此,作品中的机器人,要么是人类的好朋友, ...…

查看全部问答>

用DSP产生的FSK调制信号发射

本帖最后由 paulhyde 于 2014-9-15 09:23 编辑 我产生的调制信号频率150K,在不混频的情况下可以直接通过功率放大器进行电感耦合吗???两个电感线圈的距离为5CM 具体功率放大器怎样设计???  …

查看全部问答>

产品使用报告格式

如题,哪位大侠有产品使用报告的格式呀??借来用用…

查看全部问答>

探究CDC类的方法ExtTextOut 中的一个参数

virtual BOOL ExtTextOut ( int x, int y, UINT nOptions, LPCRECT lpRect, LPCTSTR lpszString, UINT nCount, LPINT lpDxWidths ); 想请教一下参数nOptions是否有效?本人通过测试,觉得ETO-CLIPPED、ETO-OPAQUE、NULL三者之间没有 ...…

查看全部问答>

VC++关于directshow图像旋转90度输出花屏的问题

VC++关于directshow图像旋转90度输出花屏的问题 我在transfilter对图像做了一个90度的旋转,再传给第三个filter,发现图像是花屏,解析度为176x144 如果解析度为高,宽相等就是正常的(如:240x240) 请问是什么原因?…

查看全部问答>

求vxworks的ospf源码 ?

求vxworks的ospf源码,哪位大侠有?请给一份,先谢了! jorsen_gong@hotmai.com …

查看全部问答>

招驱动工程师

岗位名称:驱动工程师 岗位要求: 1.电子、通信、计算机、自控类相关专业本科以上学历; 2.1年以上嵌入式产品开发经验,熟悉各种常用的外围扩展芯片的驱动。 比如SCI,SPI,I2C总线,smartcard,tuner。 3.精通C语言、汇编,有嵌入式系统和实时 ...…

查看全部问答>

香版!STM8S208的BEEP功能是不是不能用?

我问ST工程师的邮件:~~:    你好!    我需要用到BEEP功能,可是设定寄存器后跑程序,发现BEEP寄存器并没有改变.OPTION里面我有把PD4设成BEEP功能,OPTION里的PRSC设成(16MHZ TO 128KHZ P ...…

查看全部问答>

LPC11C14 IAP与CAN API问题

我在用LPC11C14写IAP在线升级程序时,将用户程序的向量表复制到RAM的0地址,再通过重映射寄存器重映射到FLASH的0地址,实现了用户程序调用中断,但现在要把CAN API的程序加上去,而CAN API要占用RAM的0x1000 0050-0x1000 00B8 ...…

查看全部问答>

学习FPGA过程中的困惑

现在刚开始接触FPGA不久,看了很长时间论坛了,也学习了Verilog,试着学习应用quartusii和modelsim,现在依旧感觉没有多大进步,好像根本还没有入门,简单的仿真还能进行,遇到复杂点的,比如几个模块联合编译仿真就总是仿真失败,也没有找到原因! ...…

查看全部问答>