STM32 位段详解

Wesley13
• 阅读 619

1 定义

首先需要明确下,位段,位带和别名区这三个名词

位段:STM32用户参考手册使用的名字

位带:CortexM3参考手册使用的

别名区:地址总线上用来位访问地址区域,

所以说,位段和位带是一个意思,是不同手册的不同叫法。

由上述的名词解释得知,位带功能并不是STM32独有的,是CortexM3的功能(CortexM4也有这样的功能)。MCS51有位操作,以一位(bit)为数据对象的操作,MCS51可以简单的将P1口的第2位独立操作:P1.2=0;P1.2=1 ;这样就把P1口的第三个脚(bit2)置0置1。而STM32的位段、位带别名区最重要的就为了实现这样的功能。

2 位带操作

2.1 范围

位带是有范围的,并不是CortexM3全部地址空间都支持的。在 CM3中,有两个区中实现了位带。其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低 1MB 范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。

支持位带操作的两个内存区的范围是:

0x2000_0000‐0x200F_FFFF(SRAM 区中最低1MB区域)

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

2.2 位带操作

对 SRAM 位带区的某个比特,记该比特所在字节的地址为A,位序号为 n (0<=n<=7),则它在别名区的地址为:

AliasAddr = 0x22000000 + ((A‐0x20000000)*8+n)*4 =0x22000000 + (A‐0x20000000)*32 + n*4

对于片上外设位带区的某个比特,记该比特所在字节的地址为A,位序号为 n (0<=n<=7),则该比特在别名区的地址为:

AliasAddr = 0x42000000 + ((A‐0x40000000)*8+n)*4 = 0x42000000 + (A‐0x40000000)*32 + n*4

上式中,“*4”表示一个字为 4 个字节,“*8”表示一个字节中有 8 个比特。STM32 位段详解

STM32 位段详解

2.3代码实现

把“位带地址+位序号”转换别名地址宏为:

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000 + ((addr &0xFF FFF)<<5) + (bitnum<<2))

把该地址转换成一个指针:

#define MEM_ADDR(addr, bitnum) *((volatile unsigned long *)((addr & 0xF0000000)+0x2000000 + ((addr &0xFF FFF)<<5) + (bitnum<<2)))

其中

addr的取值范围:

0x2000_0000‐0x200F_FFFF

0x4000_0000‐0x400F_FFFF

注意:addr取值要32位对齐

bitnum的取值范围:0-31

解析:

(addr & 0xf0000000) + 0x02000000:

区分SRAM还是外设,如果是外设,结果为4,再加0x2000000就等于0x4200000,0x42000000就是外设别名位带区。如果是SRAM,结果为2,再加上0x2000000就等于0x22000000,0x22000000就是SRAM别名位带区。

addr & 0x00ffffff:

屏蔽了最高2位,相当于减去0x20000000或者0x40000000。因为位带区的有效范围是1M,即0x100000,这样子就做到了低6位有效。

<< 5:

等价于乘以32

<< 2:

等价于乘以4

特别提醒:

当你使用位带功能时,要访问的变量必须用 volatile 来定义。因为 C 编译器并不知道同一个比特可以有两个地址。所以就要通过 volatile,使得编译器每次都如实地把新数值写入存储器,而不再会出于优化的考虑。

3 位段的优点

最容易想到的就是通过 GPIO 的管脚来单独控制每盏 LED 的点亮与熄灭。另一方面,也对操作串行接口器件提供了很大的方便(典型如 74HC165,CD4094)。位带操作可以把代码缩小, 速度更快,效率更高,更安全。总之位带操作对于硬件 I/O 密集型的底层程序最有用处了

位带操作还能用来化简跳转的判断。

当跳转依据是某个位时,以前必须这样做

1、读取整个寄存器

2、掩蔽不需要的位

3、比较并跳转

使用位带操作后

1、从未带别名区读取状态位

2、比较并跳转

STM32 位段详解

当然,对于写入操作也从4步精简到3步

STM32 位段详解

点击查看本文所在的专辑,STM32F207教程

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
3年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
PIC中档单片机汇编指令详解(5)
位操作指令详述BCF数据寄存器指定位清0语法形式:BCFf,b操作数:f为数据寄存器的低7位地址(0x00~0x7F)B为数据位编号(0~7)执行时间:一个指令周期执行过程:使数据寄存器f的的b位清0状态标志影响:无说明:该指令可对任何数据寄存器的任意一个位置清0,常用于标志位的设定和清除,或者把某一管脚置成低电平。指
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
20180109Java位运算
一,Java位运算1.表示方法:  在Java语言中,二进制数使用补码表示,最高位为符号位,正数的符号位为0,负数为1。补码的表示需要满足如下要求。 (1)正数的最高位为0,其余各位代表数值本身(二进制数)。 (2)对于负数,通过对该数绝对值的补码按位取反,再对整个数加1。 2.位运算符位运算表达式由
Stella981 Stella981
3年前
32位xp系统识别4G以上内存
32位xp系统识别4G以上内存大多数用户使用的xp系统都是32位,32位操作系统无法识别4G以上的内存,即便是4G内存,最多只能识别3.25G左右的内存。那么xp系统要怎么识别4G内存呢?!icon_rar.gif(https://static.oschina.net/uploads/img/202007/
可莉 可莉
3年前
20180109Java位运算
一,Java位运算1.表示方法:  在Java语言中,二进制数使用补码表示,最高位为符号位,正数的符号位为0,负数为1。补码的表示需要满足如下要求。 (1)正数的最高位为0,其余各位代表数值本身(二进制数)。 (2)对于负数,通过对该数绝对值的补码按位取反,再对整个数加1。 2.位运算符位运算表达式由