打印

【转帖】我对位带操作的理解

[复制链接]
831|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Ameya360皇华|  楼主 | 2017-7-20 16:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

今天对位带操作进行了浅显的学习。

我对位带操作的理解是,通过位带操作我们可以向操作51单片机一样,直接控制一个IO口的输出,或者得到一个IO口的输入。在51中我们经常这么写程序:

PA0 = 1;

在51单片机中以上语句实现了将PA0口的输出置1。

在stm32的应用程序中,利用位带操作,我们也可以达到上述的效果。

我们最容易想到的就是通过GPIO的管教来单独控制每盏LED的点亮和熄灭。

另一方面,也对操作串行接口器件提供了很大的方便(典型的74HC165

之类的)。当然位带操作不仅作用于此。

我们知道在芯片的内存中,一个地址对应这一个字节,也就是8个比特

的数据。比如说,我们可以查看stm32手册得GPIOx_CRL的寄存器偏移地址

是00h,它有32个比特,紧接着它的下一个寄存器GPIOx_CRH的偏移地址

是04h,也就是说GPIOx_CRL的32比特占据了00h到04h之间的4个地址

(00h,01h,02h,03h)。也就是一个地址,8个比特的数据。

位带操作所想实现的功能是,将这每个比特用4个地址来寻址,我们知

道4个地址原本对应的是32比特的数据。也就是将1个比特将膨胀为32比特。

必须说明的是膨胀后的32比特数据中只有最低位是有效的,也就是原始的那

一比特数据对应的是膨胀后的32比特数据的最低位。膨胀前的原始地址和膨

胀后的地址具有一一对应的关系。通过这样一种地址的映射将之前每个字节

中的8个比特剥离分散开来,以便于我们对每一个比特进行控制。我们知道

在GPIO中每一个比特对应这一个IO管脚,这样我们就能方便的对一个管脚进

行控制。我觉的形象的来说就是给每一个比特重新起了个别名。

在stm32中,不是每块内存区域都能进行位带操作的。支持位带操作的

内存区范围是:

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

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

对于SRAM 位带区的某个比特,记它所在字节地址为 A,位序

号 n(0<=n<=31),

则该比特在别名区的地址为:

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

对于片上外设位带区的某个比特,记它所在字节的地址为 A,位序号为

n(0<=n<=31),则该比特在别名区的地址为:

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

对以上公式,比如对片上外设这个公式来说,我的理解是:

膨胀后的映射地址起点从0x42000000开始

用(A – 0x40000000)将会得到相对于起始地址的偏移量

乘以32的原因是:以前8个比特用一个地址来表示,现在一个比特用4个地址来表示,所以以前一个地址表示的数据,现在要用32个地址来表示,所以乘以32

从3可以知道,我们乘以32后,我们得到了这个字节第0位比特膨胀后的地址,那么要得到第n位的,就加上n*4,乘以4的原因是一个比特用四个地址来表示。

n的取值范围是0到31是因为片上外设的寄存器都是32位的(0 ~ 31)

那么对SRAM映射公式的理解类似。

通过上述的位带映射后,我们对映射后的地址进行操作,也就是对原始

的地址进行操作了。并且可以对单个比特进行单独的操作。

那么相对与普通对单个比特的操作,位带操作除了方便之外还有什么优

势,那就是在效率方面,位带操作的效率更高。

比如,欲设置地址0x20000000中的比特2为1,使用位带操作和不使用

位带操作的汇编代码如下:(膨胀后的地址为0x22000008)

不使用位带操作的汇编代码:
LDR  R0 , =0x20000000 ;设置地址

LDR  R1 , [R0]   ;读取数据到寄存器

ORR.W  R1 , #0x04 ;改变第2比特的值

STR  R1 , [R0]  ;将数据写回原来的地址

使用位带操作的汇编代码:
LDR  R0 , =0x22000008 ; 设置地址(此为膨胀后的地址)

MOV  R1 , #1  ;设置数据

STR   R1 , [R0]  ;向地址写入数据

从上述代码中可以看出,位带操作的汇编指令更精简,效率更高。究其

原因,我的理解是,使用位带操作少了定位到具体哪一位的操作,我们只需

要向某个地址写入数据即可,而不需要确定写入到哪一位上,因为

位带映射之后,我们每一个比特都对应一个地址。

位带操作还能用来简化跳转的判断。当跳转依据是某个位的时候,比

如我们根据一个管脚的输入是高还是低,来决定我们之后的操作。以前

我们必须这么做:

1.      读取整个寄存器

2.      掩蔽不需要的位

3.      比较并跳转

现在只需:

1.      从位带别名区(即膨胀后的地址)读取状态位

2.      比较并跳转

从以上可以看出,位带操作的效率更高,究其原因,还是因为缺少了对

特定位的屏蔽和提取的操作。

以上,就是我对stm32的位带操作的理解,有什么理解不到位的地方,请

大家指证,希望和大家多多交流,处于博客字数的限制,下一篇我将介绍位

带操作在stm32中的C语言实现。

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

921

主题

931

帖子

12

粉丝