原创 我对位带操作的理解

2014-8-28 09:30 1366 6 13 分类: MCU/ 嵌入式

 

 

Stm32学习第二天

 

 

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

 

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

 

PA0 = 1;

 

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

   

        在stm32的应用程序中,利用位带操作,我们也可以达到上述的效果。我们最容易想到的就是通过GPIO的管教来单独控制每盏LED的点亮和熄灭。另一方面,也对操作串行接口器件提供了很大的方便(典型的如74HC165之类的)。当然位带操作不仅用于此。

 

       我们知道在芯片的内存中,一个地址对应这一个字节,也就是8个比特的数据。比如说,我们可以查看stm32手册得GPIOx_CRL的寄存器偏移地址是00h,它有32个比特,紧接着它的下一个寄存器GPIOx_CRH的偏移地址是04h,也就是说GPIOx_CRL32比特占据了00h04h之间的4个地址(00h01h02h03h)。也就是一个地址,8个比特的数据。

 

        位带操作所想实现的功能是,将这每个比特用4个地址来寻址,我们知道4个地址原本对应的是32比特的数据。也就是将1个比特将膨胀为32比特。必须说明的是膨胀后的32比特数据中只有最低位是有效的,也就是原始的那一比特数据对应的是膨胀后的32特数据的最低位。膨胀前的原始地址和膨胀后的地址具有一一对应的关系。通过这样一种地址的映射将之前每个字节中的8个比特剥离分散开来,以便于我们对每一个比特进行控制。我们知道在GPIO中每一个比特对应这一个IO管脚,这样我们就能方便的对一个管脚进行控制。我觉的形象的来说就是给每一个比特重新起了个别名。

 

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

 

   0x2000_00000x200F_FFFFSRAM 区中的最低 1MB 

   0x4000_00000x400F_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

 

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

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

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

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

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

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

 

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

 

通过上述的位带映射后,我们对映射后的地址进行操作,也就是对原始的地址进行操作了。并且可以对单个比特进行单独的操作。

 

那么相对与普通对单个比特的操作,位带操作除了方便之外还有什么优势,那就是在效率方面,位带操作的效率更高。比如,欲设置地址0x20000000中的比特21,使用位带操作和不实用位带操作的汇编代码如下:(膨胀后的地址为0x22000008)

 

1. 不使用位带操作的汇编代码:

 

LDR  R0 , =0x20000000 ;设置地址

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

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

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

 

2. 使用位带操作的汇编代码:

 

LDR  R0 , =0x22000008 ; 设置地址(此为膨胀后的地址)

MOV  R1 , #1  ;设置数据

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

 

     从上述代码中可以看出,位带操作的汇编指令更精简,效率更高。究其原因,我的理解是,使用位带操作少了定位到具体哪一位的操作,我们只需要向某个地址写入数据即可,而不需要确定写入到哪一位上,因为位带映射之后,我们每一个比特都对应一个地址。

 

 位带操作还能用来简化跳转的判断。当跳转依据是某个位的时候,比如我们根据一个管脚的输入是高还是低,来决定我们之后的操作。以前我们必须这么做:

 

1.     读取整个寄存器

2.    掩蔽不需要的位

3.      比较并跳转

 

现在只需:

 

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

2.      比较并跳转

 

从以上可以看出,位带操作的效率更高,究其原因,还是因为缺少了对特定位的屏蔽和提取的操作。

 

          以上,就是我对stm32的位带操作的理解,有什么理解不到位的地方,请大家指证,希望和大家多多交流。至于C语言的具体实现,出于字数的限制,我讲在下一篇文章来介绍。

 

 

 

   

 

 

 

 

 

 

  

       

PARTNER CONTENT

文章评论7条评论)

登录后参与讨论

用户1383711 2015-7-9 11:17

学习学习

用户514092 2014-9-5 07:55

mark

用户377235 2014-9-2 09:16

膜拜~~

用户1724500 2014-9-1 10:59

没事,希望我的文章对你有帮助~希望能多多交流。。谢谢

用户1712588 2014-9-1 10:57

曾经研究过,但是又忘了

用户377235 2014-8-28 11:38

好厉害啊,

用户377235 2014-8-28 10:03

写的不错,挺有用的
相关推荐阅读
用户1724500 2014-09-01 16:29
[博客大赛]stm32中位带操作的实现
    位带操作在stm32中的C语言实现    首先:    #define BITBAND(addr,bitnum)  ((addr & 0xF0000000)...
用户1724500 2014-09-01 16:27
[博客大赛]我对stm32中GPIO输入输出模式的理解
stm32学习第三天     最近学习了stm32的GPIO的相关操作,发现其GPIO的配置模式有好几种,包括: 1. 模拟输入; 2. 浮空输入; 3. 上拉输入; ...
用户1724500 2014-08-26 15:26
我对stm32工程设置中的宏定义的理解
Stm32学习第一天   1.   对工程设置中的宏定义的理解,在stm32F103VET6的工程设置如下: 如上图,工程设置中定义了两个宏定义:STM32F10X_HD,USE_STDPE...
我要评论
7
6
关闭 站长推荐上一条 /3 下一条