受到“位带别名区“启发,STM32F103.H头文件计划。
受到“位带别名区“启发,STM32F103.H头文件计划。
现在已经使用STM32F103.H头文,基本代替了STM32库,
直接使用寄存器和位结构。
现在受到“位带别名区“启发,把STM32 外设寄存器全部加上
“位带别名区“定义。
每个比特膨胀成一个32 位的字!使用更高效!
例子:
//----------------------------
struct BB_CRC_DR_BITS {
Uint32 LPDS[32];//使用“位带别名区 每个比特膨胀成一个32 位的字 32比特膨胀到32个32位。
};
//----------------------------------
struct CRC_DR_BITS {
Uint32 LPDS :32; // 0-31
};
union CRC_DR_REG {
Uint32 all;
struct CRC_DR_BITS bit;
};
前后对比更方便!
struct CRC_REGS {
union CRC_DR_REG dr ; //
union CRC_IDR_REG idr ; //
u8 RESERVED0;
u16 RESERVED1;
union CRC_CR_REG cr ; //
};
#define STM32_Crc_Regs (((volatile struct CRC_REGS *)(CRC_BASE)))
//使用位带定义。
struct BB_CRC_REGS {
struct BB_CRC_DR_BITS DR ;
struct BB_CRC_IDR_BITS IDR ;
u32 RESERVED0[8];
u32 RESERVED1[16];
struct BB_CRC_CR_BITS CR ;
#define STM32_BB_Crc_Regs (((volatile struct BB_CRC_REGS *)(CRC_BASE+BB_OFFSET)))
//使用区别:
STM32_BB_Crc_Regs->CR.RESET=0X1;
STM32_Crc_Regs->cr.bit.RESET=1;
};
切低倒塌STM32库。看来STM32库又要升级了!
#define STM32_BB_Crc_Regs (((volatile struct BB_CRC_REGS *)(0x42000000+ (CRC_BASE-0x40000000)*32)))
STM32库 是应该 有 外设I/O寄存器的“位带别名区“定义的。
这样会非常高效。
位带操作的优越性
位带操作有什么
点亮与熄灭。另一方面,也对操作串行接口器件提供了很大的方便(典型如74HC165,CD4094)。
总之位带操作对于硬件I/O 密集型的底层程序最有用处了。
CM3 中还有一个称为“bit‐bang”的概念,它通常是通过“bit‐band”实现的,但是它俩在
个不同的概念。
位带操作还
读取整个寄存器
掩蔽不需要的位
比较并跳转
现在只需:
从位
比较并跳转
使代码更简洁,这只是位带操作优越性的初等体现,位带操作还有一个重要的好处是在多任务中,,用于实现共享资源在任务间的“互锁”访问。多任务的共享资源必须满足一次只
有一个任务访问它——亦即所谓的“原子操作”。以前的读-改-写需要3 条指令,导致这
中间留有两个能被中断的空当。于是可能会出现如下图所示的紊乱危象:
同样的紊乱危象可以出现在多任务的执行环境中。其实,图5.8 所演示的情况可以看作
是多任务的一个特例:主程序是一个任务,ISR 是另一个任务,这两个任务并发执行。
通过使用CM3 的位带操作,就可以消灭上例中的紊乱危象。CM3 把这个“读-改-写”
做成一个硬件级别支持的原子操作,不能被中断,
比STM32库更高效!
例如点亮LED
// 代码比STM32库
GPIO_ResetBits(GPIOC, GPIO_Pin_4); //关LED5
GPIO_SetBits(GPIOC, GPIO_Pin_7); //开LED2
// 一般读操作
STM32_Gpioc_Regs->bsrr.bit.BR4 =1;// 1:清除对应的ODRy位为0
STM32_Gpioc_Regs->bsrr.bit.BS7 =1;// 1:设置对应的ODRy位为1
//如果使用 位带别名区操作
STM32_BB_Gpioc_Regs->BSRR.BR[4] =1;// 1:清除对应的ODRy位为0
STM32_BB_Gpioc_Regs->BSRR.BS[7] =1;// 1:设置对应的ODRy位为1
代码比STM32库 高效 十倍 !
对内存变量的位操作。
// SRAM 变量
long CRCValue;
// 把“位带地址+位序号”转换别名地址宏
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
//把该地址转换成一个指针
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
// 对32位变量 的BIT1 置 1 :
MEM_ADDR(BITBAND( (u32)&CRCValue,1)) = 0x1;
//对任意一位( 第23位 ) 判断:
if(MEM_ADDR(BITBAND( (u32)&CRCValue,23))==1)
{
}
上面,SRAM变量要加volatile
volatile long CRCValue;
// STM32 内部SRAM有 20K---64K,完全在1MB之内。
是方便了
不过不同的场合,需求不一样
全部使用位变量操作寄存器,我觉得程序的可读性会变差
这个可以和c中插入汇编指令一样在特定的场合使用即可
总于硬件可以象8051那样的位操作了。
确实的,自从8051后,发现 8051位操作都不被支持。其实很不爽也可惜。
因为 位操作确实 比 逻辑 操作要 高效些。
而且使用也很频繁的。 从代码密度和效率看,都应该保留才对。
现在 CORTEX-M3 重振 30年前 8051就有的这个功能,而且更强。
剩下 如果 编译器 在 特意 支持一下,那就VERY GOOD 了。
C语句是短点,汇编可没省。
我对比过。用的多的话,还是子程序的方式省空间。
STM32_BB_Gpioc_Regs->BSRR.BR[4] =1
这句对应的汇编代码可不少呢。
代码的效率。
从图可以看出,
一般逻辑操作要 5 条 THUMB-2指令
而 位带别名区操作 只要 3 条THUMB-2指令
基本上与指南说的差不多的。
对任意 SRAM 的操作。
由于没有使用绝对定位,而是使用 取地址办法。这就消耗了4条指令!
正常 逻辑操作要 6条指令。
用位带别名操作+取地址办法共7条指令,其中位带别名操作才3条指令!!
虽然 多了一条指令,但是 可以它非常紧密。符合 ”原子操作“。
内存里没有特别要求最好不要用这玩意儿!
IO口倒是很有必要!
在模拟时序时是相当有用的!