STM32 BSRR BRR ODR 寄存器解析(F4系列已经去掉BRR寄存器了)
STM32 BSRR BRR ODR 寄存器解析(F4系列已经去掉BRR寄存器了)
- 一、用法
- 二、解释
- 三、BSRR、BRR、 ODR 之间的关系
G0x0系列GPIO寄存器
F4系列GPIO寄存器(没有BRR寄存器了)
一、用法
经常会看到类似如下的宏定义语句,用于对已经初始化后的 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;
}
因此,使用宏或者库函数本质上都是一样的。区别在于使用宏更快,而使用函数更灵活。
注意:在要求速度/时序的更快更严格的场合(模拟I2C,模拟SPI,Σ-∆ADC中DOUT/RDRY同一引脚等情况的),建议使用宏定义操作IO口对应的引脚。
#define IN1() {GPIOA->MODER&=0XFF3FFFFF;} //PA11
#define OUT1() {GPIOA->MODER&=0XFF3FFFFF;GPIOA->MODER|=0X00400000;}#define IN2() {GPIOA->MODER&=0XFFF3FFFF;}//PA9
#define OUT2() {GPIOA->MODER&=0XFFF3FFFF;GPIOA->MODER|=0X00040000;}#define DRDY1 (GPIOA->IDR)&(uint16_t)0x0800
#define DRDY2 (GPIOA->IDR)&(uint16_t)0x0200
二、解释
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 的 HAL 库函数中,对 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;}
}
而早期 ST 的标准库 std 中,关于 GPIO 口输出高低电平的函数为如下形式,里面通过两个16位的指针分别指向 BSRR 的高16位和低16位。
typedef struct
{__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */__IO uint16_t BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */__IO uint16_t BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
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->BSRRL = GPIO_Pin;
}
void GPIO_ResetBits(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->BSRRH = GPIO_Pin;
}
可见,不管是输出高还是输出低,都是对 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;
这是因为在修改 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;
}
原文链接:https://blog.csdn.net/u011303443/article/details/76514537
STM32 BSRR BRR ODR 寄存器解析(F4系列已经去掉BRR寄存器了)相关推荐
- 【STM32】引脚配置—F1与F4系列
目录 一.stm32的GPIO模式简介 1.输入模式 2.输出模式 3.复用模式 各形式说明: 二.GPIO配置 1.GPIO初始化函数 2.外设使能函数及选择 关于使能函数的选择 3.完整的GPIO ...
- STM32 BSRR BRR ODR 寄存器解析
一.用法 经常会看到类似如下的宏定义语句,用于对已经初始化后的 IO 口输出高.低电平. #define SET_BL_HIGH() GPIOA->BSRR=GPIO_Pin_0 #define ...
- STM32F10x系列GPIO寄存器BRR、BSRR、ODR、IDR的使用理解
引脚的高.低电平控制,有3种方法(3个寄存器) 分别是通过GPIO的 3个 管脚控制寄存器: ODR寄存器, 控制管脚的高.低电平,低16位有效,写1 高电平, 写0 低电平; BSRR寄存器, ...
- STM32 通用输入输出端口GPIO BRR、BSRR、ODR寄存器详解
详细页面:http://alanzjl.sinaapp.com/2015/02/gpio_brr_bsrr_odr/ BRR.BSRR.ODR都是用来控制16位针脚的. 其中,BRR和ODR高16位都 ...
- STM32寄存器点亮LED(什么是寄存器、GPIO工作方式、点亮原理)
一.什么是寄存器 STM32编程通常有两种编程方法,一种是寄存器编程:另一种是固件库编程,其中寄存器编程是基础,而固件库编程是在寄存器编程的基础上升级而来的一种易于学习和开发的方法,是学习STM3 ...
- Arduino框架下STM32F1/F4系列HID模式程序烧录教程
Arduino框架下STM32F1/F4系列HID模式程序烧录教程 相关篇<Arduino框架下STM32全系列开发固件安装指南> HID BootLoader烧录模式 "Upl ...
- 三菱modbusRTU通讯实例_干货 | 解析西门子系列PLC编程实例
点击箭头处"工业之家",选择"关注公众号"! 解析西门子系列PLC编程实例 三辊卷板机有分为机械式和液压式,机械式又分为对称式和非对称式.用于重型机械公司,将金 ...
- 《React源码解析》系列完结!
前言 距离第一篇<React源码解析(一)>已经过去将近4个月的时间,由于是我第一次进行源码解析相关的写作,思路和文笔还不够成熟.一百多天以来,我基于读者反馈反思这几篇文章中的不足,同时也 ...
- stm32驱动NRF24L01_原理+代码解析
目录 概念 废话篇(24L01简介) 引脚分配 工作模式 通信地址理解(个人疑难点) 原理分析 寄存器赏析 寄存器操作指令 配置寄存器(CONFIG,位置:0X00) 自动应答使能寄存器(EN_AA, ...
最新文章
- 【ICML2021】学习权衡不完美的示范
- python函数注释 参数 省略号_解决python 输出是省略号的问题
- fguillot json rpc_使用Hyperf框架搭建jsonrpc服务
- 发现一个小坑的地方,unity的协程,想要停止,必须以字符串启动
- everything服务器网页设置,Everything HTTP 服务器设置
- Sentinel-1 影像与精轨数据下载(经常更新中)
- 回旋加速器和同步加速器的区别
- Java后台调用第三方支付接口(易宝支付)
- 保存电脑上的屏保图片
- python 爬取google总结
- 刷百度权重那些不为人知的事情
- 小组取什么名字好_寓意兴旺的公司名字取什么名字好
- 逆向破解之160个CrackMe —— 023-024
- epub 电子书的制作
- excel与access结合运用_当excel不够用时,如何利用Access进行数据分析?
- MySQL8数据库知识点概述
- 自定义鼠标滑过标签的title属性的样式
- Python爬虫任务4
- matlab2012卸载,matlab2012一些函数删除后的替代解决方法及用到操作
- iOS 13 适配,关闭黑暗模式(夜间模式)