关于stm32中的位带操作

前言

在stm32中操作GPIO口有一种非常常见便捷的方式,不需要调用32标准库函数,那就是位带(bit-band)操作。
首先,放上一张在全网广泛流传的照片,在几乎所有的位带操作相关的博客中都能找到这张图片。
网传图
在《Cortex-M3权威指南》中出现的存储器映射图能更好的帮助我们理解整个存储架构
在这里插入图片描述

简介(下定义)

位带操作,就是一种特殊的,能够实现单独操作某一bit位的操作方式。他的实现原理就是在存储空间中划分出位带区,将位带区的每一位膨胀4个字节后存放到位带别名区,访问操作位带别名区即可操作位带区的每一位。

位带区和位带别名区

STM32中,在SRAM和片上外设的最低1MB空间为位带区,相对应的这两个区域有专属的位带别名区。
外设位带区地址为0x40000000 ~ 0x40100000,大小为1MB,膨胀后地址为0x42000000 ~ 0x43FFFFFF,大小为32MB在stm32F103中这个范围包含了所有的片上外设的寄存器。所以可以实现对所有片上外设的位带操作。
SRAM位带区地址为0x20000000~0x20100000,大小为1MB,膨胀后地址为0x22000000 ~ 0x23FFFFFF,大小也为32MB。

位带区和位带别名区的地址转换

/*设位带区某位所在字节的地址为a,该位在该字节中的序号为n*/
AliasAddr = 0x4200000 + (A - 0x40000000)*8*4 + n*4  //片上外设
AliasAddr = 0x4200000 + (A - 0x40000000)*8*4 + n*4  //SRAM

首先我们需要明确的一点是,stm32中的地址最小代表着一个字节,即相邻地址之间间隔8位。所以每一位相当于膨胀到4个字节。
式子中A - 0x40000000算出相对位带区首地址偏移了多少个字节,然后 *8得出共计多少个位。因为每一个位膨胀四个字节,反映到位带别名区就是地址占4,所以 *4得别名区的地址。
还没完,刚刚得出的是位带区对应字节在别名区的换算,还需要加上位序号在别名区的换算才能真正定位到该字节。位序号代表便宜字节基地址的位数,而每一个位膨胀四个字节,所以位序号 *4就是位序号的换算。两者相加,再加上别名区的基地址,就可以得到该位在别名区的确切地址。

位带操作

一般为了方便,会使用宏定义将以上的操作封装好,并将地址转换成指针,通过访问指针实现对位带别名区的操作。

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5+(bitnum<<2))

#define MEM_ADDR(addr)  *((volatile unsigned long *)(addr))
#define BIT_BIT_ADDR(addr,bitnum)  MEM_ADDR(BITBAND(addr, bitnum))

在第一个宏定义中,addr & 0xF0000000提取出了地址最高位,片上外设是4,SRAM是2。addr & 0x00FFFFFF屏蔽了高两位,原因是两者相减相当于直接屏蔽高两位,屏蔽的位数和改位带区的最高位有关。最后的位操作左移相当于乘32和乘4。
第二个宏定义将参数转换为指针并访问,第三个宏定义将二者结合,最终直接访问以addr和bitnum为参数的地址。
注意,使用位带操作的时候必须使用volatile关键字来定义,因为系统并不知道有两个地址,所以提醒cpu不需要优化而老老实实地每次认真读写。

工程实践

从手册中可以查到我们想要实现位带操作的寄存器的地址偏移量

#define GPIOA_ODR_Addr  (GPIOA_BASE+12) //0x4001080c
#define GPIOA_IDR_Addr  (GPIOA_BASE+8)  //0x40010808

#define PAout(n)  BIT_BIT_ADDR(GPIOA_ODR_Addr,n)
#define PAin(n)   BIT_BIT_ADDR(GPIOA_IDR_Addr,n)
PAout(0)=0;//io口低电平
PAin(0) =1;//io口高电平

优越性

1.使代码更简洁
2.用于实现共享资源在任务间的“互锁”访问。多任务的共享资源必须满足一次只有一个任务访问它——亦即所谓的“原子操作”。以前的读-改-写需要3 条指令,导致这中间留有两个能被中断的空当。于是可能会出现如下图所示的紊乱危象:
在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值