在 CM3
其间一个是 SRAM 区的最低 1MB 规模,
第二个则是片内外设区的最低 1MB规模,
这两个区中的地址除了能够像一般的 RAM 相同运用外,它们还都有自己的“位带别号区”,位带别号区把每个比特胀大成一个32 位的字。当你经过位带别号区拜访这些字时,就能够到达拜访原始比特的意图。
CM3 运用如下术语来表明位带存储的相关地址
*
*
位带区中的每个比特都映射到别号地址区的一个字 —— 这是只要 LSB 有用的字(位带别号区的字只要 最低位 有意义)。
关于SRAM中的某个比特,
该比特在位带别号区的地址:AliasAddr =
该比特在位带别号区的地址:AliasAddr =
“*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; //运用正常地址拜访寄存器
还能够更简化:
//把“位带地址+位序号”
#defineBITBAND(addr, bitnum)((addr & 0xF0000000)+0x2000000+((addr &
//把该地址转换成一个指针
#defineMEM_ADDR(addr)
所以:
MEM_ADDR(DEVICE_REG0) = 0xAB;
MEM_ADDR(BITBAND(DEVICE_REG0,1)) = 0x1;
留意:当你运用位带功用时,要拜访的变量有必要用 volatile 来界说。由于 C 编译器并不知道同一个比特能够有两个地址。所以就要经过 volatile,使得编译器每次都如实地把新数值写入存储器,而不再会出于优化的考虑 ,在半途运用寄存器来操作数据的复本,直到最终才把复本写回。
在 GCC和 RealView MDK (即 Keil)
这样,就在0x20003014处置配了7个字,共得到了32*7=224 个比特。
再运用这些比特时,能够经过如下的的方式:
pbbaVar[136]=1;
不过这有个限制:编译器无法查看是否下标越界。
那为什么不界说成“ baVarAry[224]“
这也是一个编译器的限制:它不知道这个数组其实便是 bbVarAry[7],从而在核算程序对内存的占用量上,会无缘无故地多计入224*4个字节。
关于指针义,为每个需求运用的比特取一个字面值的姓名,在下标中只运用字面值姓名,不再写实在的数字,就能够极大程度地防止数组越界。
请留意:在界说这“两个”变量时,前面加上了“volatile”。假如不再运用bbVarAry 来拜访这些比特,而只是运用位带别号的方式拜访时,这两个 volatile 均不再需求。