STM32 的位带操作

版权声明:均是学习笔记、心得,如有冒犯,请指出,会及时处理。https://blog.csdn.net/qq_27485531 https://blog.csdn.net/qq_27485531/article/details/83352716

位操作就是可以单独的对一个比特位进行读和写,这个在51单片机中非常常见。51单片机中通过关键字sbit来实现位定义,STM32中则是通过访问位带别名区的地址来实现对某一位的操作。

例如51单片机中可以实现以下操作

#define LED_ON 0
sbit LED = P2^0;
LED = LED_ON;

而现在STM32的位段、位带别名区就为了实现这样的功能。STM32针对SRM和外设区开辟了两个内存空间(位带区),分别是SRAM和外社区的最低1MB的空间。这两个1MB的内存空间除了可以像正常的 RAM 一样操作外,他们还有自己的位带别名区,位带别名区就是把1MB位带区的每一个位膨胀成一个32位的字,当通过访问位带别名区的这些字时,就可以达到访问位带区某个比特位的目的。位带区的一个比特位经过膨胀之后,虽然变大到 4个字节,但是还是 LSB才有效。

由上图可以看出STM32 支持位带操作的两个内存区的范围是: 
 0x2000_0000‐0x200F_FFFF(SRAM 区中的最低1MB) 

0x4000_0000‐0x400F_FFFF(片上外设区中的最低1MB)

我们可以通过指针的形式访问位带别名区地址从而达到操作位带区比特位的效果。

位带别名区地址公式为

AliaAddr(addr,bitnum) = (addr&0xF0000000) + 0x2000000 + (addr&0xFFFFF)<<5 + bitnum<<2

ADDR为该比特位所在字节的地址,Bitnum为位序号

这里我以操作一个ODR寄存器(对于GPIO基地址的偏移为20)为例

例如

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x000FFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))           // 把一个地址转换成一个指针 
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))       // 把位带别名区地址转换成指针
#define GPIOH_ODR_Addr (GPIOH_BASE+20)                               //寄存器地址映射
#define PHout(n) BIT_ADDR(GPIOH_ODR_Addr,n)                          //输出

/*主函数
    * @beief 电亮LED灯
    * @param 无 
    * @revel 无
    */
int main
{
    LED_Config();                                                    //LED灯GPIO配置
    PHout(10) = 0;                                                   //点亮LED灯

}

关于主函数的点亮LED的操作,请参照stm32f4固件库函数点亮LED灯

关于为什么不直接对STM32的位带区进行位操作原因是STM32对内存的控制读写数据是按字节来算的,不能对一位进行直接操作。

位操作有如下优点

位带操作可以把代码缩小, 速度更快,效率更高,更安全。 
一般操作要6条指令,而使用 位带别名区只要4条指令。    
 一般操作是  读-改-写  的方式, 而位带别名区是 写 操作。防止中断对读-改-写  的方式的影响。

猜你喜欢

转载自blog.csdn.net/qq_27485531/article/details/83352716