STM32F10x系列GPIO寄存器BRR、BSRR、ODR、IDR的使用理解


引脚的高、低电平控制,有3种方法(3个寄存器)

分别是通过GPIO的 3个 管脚控制寄存器:

  1. ODR寄存器,   控制管脚的高、低电平,低16位有效,写1 高电平, 写0 低电平;
  2. BSRR寄存器, 控制管脚的高、低电平,32位有效,低16位写1 高电平,高16位写1 低电平;
  3. BRR寄存器,   控制管脚的电平,低16位有效,写1 低电平;

特别的:  F1和F4系列都有 ODR和BSRR,但F4 取消了BRR。所以为了代码通用,尽量不使用BRR,反正BSRR能完成.


ODR、BSRR的使用区别:

你应该有过和我一样的疑问:

ODR寄存器只用低16位,就能控制引脚的高、低电平,还能读寄存器的值,用以判断引脚电平状态;  

那么, 为什么要存在一个BSRR! 还分高、低16位!  还不能读寄存器的值!

写了几年的STM32代码, 一直在使用ODR, 几乎没用过BSRR. 直到今天查找F1和F4的GPIO操作区别时, 才发现BSRR的神奇之处。

(1) BSRR: 写入1生效, 写入0无动作.  同样置/复位, 比用ODR操作编译后要快几个动作, 想想以前用或/与操作, 真是多余了!

例如:  PB1要设高电平, PB11设低电平;注意看注释

// 通过 ODR 寄存器
GPIOB->ODR |=  0X01 ;        // 代码是一行, 但背后的运行是很多步:读取->或运算->写入
GPIOB->ODR &= ~(0X01<<11) ;  // 同样是:读取->或运算->写入

// 通过 BSRR 寄存器 
GPIOB->BSRR = 0X01 ;         // 某个位直接置1,OK, 搞掂了。其它没置1的位不产生变化
GPIOB->BSRR = 0X01<<11;      // 同上

(2) BSRR 操作, 不用关中断

这个不太理解, 功力不到时候. 引用网友的话吧:

“This way, there is no risk that an IRQ occurs between the read and the modify access.”
什么意思呢?就是你用BSRR和BRR去改变管脚状态的时候,没有被中断打断的风险。也就不需要关闭中断。


使用总结:

操作管脚状态, BSRR = 快 + 简单 !

 

 

(完~~~)

 

 

<think>好的,我现在需要帮用户理解STM32BSRRODR寄存器之间的关系。首先,我得回顾一下用户提供的参考资料,确保自己正确掌握这些寄存器的功能。 根据引用[1]和[2],ODR是可读可写的寄存器,直接控制GPIO的高低电平。写1就是高电平,写0就是低电平。不过,如果在操作ODR时发生中断,可能会被中断打断,导致状态设置不及时,所以建议使用BSRRBRR来替代,因为它们操作更安全。 BSRR是一个只写寄存器,分为高16位和低16位。低16位用于设置引脚为高电平(写1有效),高16位则用于设置引脚为低电平(同样写1有效)。而BRR只能将引脚设置为低电平,同样是写1有效。这样设计的好处是,通过BSRR可以同时设置多个引脚的状态,而无需像ODR那样需要先读取当前状态再修改,避免了竞态条件的问题。 接下来,用户的问题是关于BSRRODR之间的关系。我需要解释它们各自的用途,以及为什么有时候推荐使用BSRR而不是直接操作ODR。可能需要从原子操作、中断安全性和效率等方面来比较。 首先,ODR直接反映引脚的输出状态,但修改它需要整个寄存器的读写,这在多任务或中断环境中可能不安全。例如,如果一个中断在修改ODR的过程中发生,并尝试修改同一端口的不同引脚,可能会导致数据冲突。而BSRRBRR允许单独设置或清除某个位,不需要先读取当前值,因此操作是原子的,不会被中断打断。 另外,BSRR的高16位和低16位设计使得可以同时设置和清除不同的位,而ODR每次只能整体写入。这对于需要同时改变多个引脚状态的场景更高效。 用户可能还想知道如何在实际应用中选择使用这些寄存器。例如,当需要快速切换某个引脚状态时,使用BSRR会更可靠;而需要读取当前输出状态时,ODR则是必要的。 总结来说,BSRRODR都是控制GPIO输出的寄存器,但BSRR提供了更安全和高效的操作方式,尤其在需要避免中断干扰的情况下。而ODR则适用于需要读取当前输出状态的场合。</think>### STM32 BSRRODR寄存器关系解析 在STM32GPIO控制中,BSRR(Bit Set/Reset Register)和ODR(Output Data Register)均可用于控制引脚输出电平,但两者在操作方式和应用场景上有显著区别[^1][^2]。 #### 1. ODR寄存器的特性 - **直接电平控制**:通过32寄存器直接读写引脚状态。例如,对某位写$1$时对应引脚输出高电平,写$0$时输出低电平。 - **可读可写**:可读取当前所有引脚的输出状态。 - **潜在风险**:修改ODR需要先读取当前值再修改,在多线程或中断场景中可能引发**竞态条件**(Race Condition),导致数据冲突。 #### 2. BSRR寄存器的特性 - **原子操作**:通过高低16位分离设计实现无锁操作: - **低16位**:写$1$时对应引脚设为高电平(例如`BSRR = 0x00000001`设置引脚0为高电平)。 - **高16位**:写$1$时对应引脚设为低电平(例如`BSRR = 0x00010000`设置引脚0为低电平)。 - **只写属性**:无法读取当前状态,但操作过程不会被中断打断。 #### 3. 关键差异对比 | 特性 | ODR | BSRR | |---------------------|----------------------|----------------------| | 操作类型 | 读/写 | 只写 | | 原子性 | 非原子操作 | 原子操作 | | 中断安全性 | 低(需加锁) | 高(无需额外保护) | | 典型应用场景 | 批量更新引脚状态 | 快速单引脚状态切换 | #### 4. 实际应用示例 - **设置引脚PA5为高电平**: ```c GPIOA->BSRR = 0x00000020; // 低16位写1(原子操作) ``` - **清除引脚PA5电平**: ```c GPIOA->BSRR = 0x00200000; // 高16位写1(原子操作) ``` - **使用ODR时的风险操作**: ```c GPIOA->ODR |= 0x00000020; // 需先读取ODR值,可能被中断打断 ``` #### 5. 设计原理 BSRR通过分离**置位**和**复位**操作,避免了传统“读-改-写”流程中的中间状态暴露问题。其操作可简化为: $$ \text{BSRR动作} = (\text{目标状态} \land \text{掩码}) \oplus \text{当前状态} $$ 而ODR的修改过程需要: $$ \text{新ODR值} = (\text{旧ODR值} \land \neg\text{掩码}) \lor (\text{目标值} \land \text{掩码}) $$
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值