您的位置 首页 电路

STM32之位带操作

Cortex-M3支持了位操作后,可以使用普通的加载存储指令来对单一的比特进行读写。在CM3支持的位带中,有两个区中实现了位带。

  Cortex-M3支撑了位操作后,能够运用一般的加载/存储指令来对单一的比特进行读写。

  在 CM3 支撑的位带中,有两个区中完成了位带。

  其间一个是 SRAM 区的最低 1MB 规模,0x20000000 ‐ 0x200FFFFF(SRAM 区中的最低 1MB);

  第二个则是片内外设区的最低 1MB规模,0x40000000 ‐ 0x400FFFFF(片上外设区中的最低 1MB)。

  这两个区中的地址除了能够像一般的 RAM 相同运用外,它们还都有自己的“位带别号区”,位带别号区把每个比特胀大成一个32 位的字。当你经过位带别号区拜访这些字时,就能够到达拜访原始比特的意图。

  CM3 运用如下术语来表明位带存储的相关地址

  *位带区: 支撑位带操作的地址区

  *位带别号: 对别号地址的拜访终究效果到位带区的拜访上(留意:这中心有一个地址映射进程)

  

  位带区中的每个比特都映射到别号地址区的一个字 —— 这是只要 LSB 有用的字(位带别号区的字只要 最低位 有意义)。

  关于SRAM中的某个比特,

  该比特在位带别号区的地址:AliasAddr =0x22000000 + ((A‐0x20000000)*8+n)*4

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

关于片上外设位带区的某个比特,

  该比特在位带别号区的地址:AliasAddr =0x42000000 + ((A‐0x40000000)*8+n)*4

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

                    其间 A 为该比特地点的字节的地址,0 <= n <= 7

                    “*4”表明一个字为 4 个字节,“*8”表明一个字节中有 8 个比特。

                    当然,位带操作并不只限于以字为单位的传送。亦能够按半字和字节为单位传送。 

                    

  位带操作有许多优点,其间重要的一项便是,在多使命体系中,用于完成共享资源在使命间的“互锁”拜访。多使命的共享资源有必要满意一次只要一个使命拜访它——亦即所谓的“原子操作”。

  在 C 言语中运用位带操作

  在 C编译器中并没有直接支撑位带操作。比方,C 编译器并不知道同一块内存,能够运用不同的地址来拜访,也不知道对位带别号区的拜访只对 LSB 有用。

  欲在 C中运用位带操作,最简略的做法便是#define 一个位带别号区的地址。例如:

    #define DEVICE_REG0 ((volatile unsigned long *) (0x40000000))

    #define DEVICE_REG0_BIT0 ((volatile unsigned long *) (0x42000000))

    #define DEVICE_REG0_BIT1 ((volatile unsigned long *) (0x42000004))

    …

    *DEVICE_REG0 = 0xAB;        //运用正常地址拜访寄存器

  *DEVICE_REG0_BIT1 = 0x1; // 经过位带别号地址设置 bit1

  还能够更简化:

    //把“位带地址+位序号”转换成别号地址的宏

    #defineBITBAND(addr, bitnum)((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))  

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

    #defineMEM_ADDR(addr)*((volatile unsigned long *) (addr))

    所以:

    MEM_ADDR(DEVICE_REG0) = 0xAB;             //运用正常地址拜访寄存器  

    MEM_ADDR(BITBAND(DEVICE_REG0,1)) = 0x1;        //运用位带别号地址

  留意:当你运用位带功用时,要拜访的变量有必要用 volatile 来界说。由于 C 编译器并不知道同一个比特能够有两个地址。所以就要经过 volatile,使得编译器每次都如实地把新数值写入存储器,而不再会出于优化的考虑 ,在半途运用寄存器来操作数据的复本,直到最终才把复本写回。

  

  在 GCC和 RealView MDK (即 Keil) 开发工具中,答应界说变量时手艺指定其地址。如:

   volatile unsigned longbbVarAry[7]__attribute__((at(0x20003014) ));

    volatile unsigned long* constpbbaVar= (void*)(0x22000000+0x3014*8*4);

    //在 long*后边的“const”告诉编译器:该指针不能再被修正而指向其它地址。

    //留意:at()中的地址有必要对齐到4 字节鸿沟。

  这样,就在0x20003014处置配了7个字,共得到了32*7=224 个比特。

  再运用这些比特时,能够经过如下的的方式:

    pbbaVar[136]=1; //置位第 136号比特

  不过这有个限制:编译器无法查看是否下标越界。

  那为什么不界说成“ baVarAry[224]“的数组呢?

  这也是一个编译器的限制:它不知道这个数组其实便是 bbVarAry[7],从而在核算程序对内存的占用量上,会无缘无故地多计入224*4个字节。

  关于指针义,为每个需求运用的比特取一个字面值的姓名,在下标中只运用字面值姓名,不再写实在的数字,就能够极大程度地防止数组越界。

  

  请留意:在界说这“两个”变量时,前面加上了“volatile”。假如不再运用bbVarAry 来拜访这些比特,而只是运用位带别号的方式拜访时,这两个 volatile 均不再需求。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/dianlu/257579.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部