利用这一技术后所有的动态局部变量都可以按已知的固定地址地进行直接寻址,用 PIC 汇编指令实现的效率最高,但这时不能出现函数递归调用。PICC 在编译时会严格检查递归调用的问题并认为这是一个严重错误而立即终止编译过程。
为了使编译器产生最高效的机器码,PICC 把单片机中数据寄存器的 bank问题交由编程员自己管理,因此在定义用户变量时你必须自己决定这些变量具体放在哪一个 bank 中。如果没有特别指明,所定义的变量将被定位在 bank0,除了 bank0 内的变量声明时不需特殊处理外,定义在其它 bank 内的变量前面必须加上相应的 bank序号
中档系列 PIC 单片机数据寄存器的一个 bank 大小为 128 字节,刨去前面若干字节的特殊功能寄存器区域,在 C 语言中某一 bank 内定义的变量字节总数不能超过可用 RAM 字节数。如果超过 bank 容量,在最后连接时会报错,大致信息如下:
Error[000] : Can't find 0x12C words for psect rbss_1 in segment BANK1
连接器告诉你总共有 0x12C(300)个字节准备放到 bank1 中但 bank1 容量不够。显然,只有把一部分原本定位在 bank1 中的变量改放到其它 bank 中才能解决此问题。
为避免频繁的 bank 切换以提高代码效率,尽量把实现同一任务的变量定位在同一个 bank 内;对不同 bank 内的变量进行读写操作时也尽量把位于相同 bank 内的变量归并在一起进行连续操作。
所有的局部变量将占用 bank0的存储空间,因此用户自己定位在 bank0 内的变量字节数将受到一定的限制,在实际使用时需注意。
bit 型位变量只能是全局的或静态的。PICC 将把定位在同一 bank 内的 8 个位变量合并成一个字节存放于一个固定地址。因此所有针对位变量的操作将直接使用 PIC 单片机的位操作汇编指令高效实现。基于此,位变量不能是局部自动型变量,也无法将其组合成复合型高级变量。
PICC 对整个数据存储空间实行位编址,0x000 单元的第 0 位是位地址 0x0000,以此后推,每个字节有 8 个位地址。编制位地址的意义纯粹是为了编译器最后产生汇编级位操作指令而用,对编程人员来说基本可以不管。但若能了解位变量的位地址编址方式就可以在最后程序调试时方便地查找自己所定义的位变量,如果一个位变量 flag1 被编址为 0x123,那么实际的存储空间位于:
字节地址=0x123/8 = 0x24
位偏移 =0x123%8 = 3
即 flag1 位变量位于地址为 0x24 字节的第 3 位。在程序调试时如果要观察 flag1 的变化,必须观察地址为 0x24 的字节而不是 0x123。
unsigned char tmpData @ 0x20; //tmpData定位在地址0x20
千万注意,PICC 对绝对定位的变量不保留地址空间。换句话说,上面变量 tmpData 的地址是 0x20,但最后 0x20 处完全有可能又被分配给了其它变量使用,这样就发生了地址冲突。因此针对变量的绝对定位要特别小心。从笔者的应用经验看,在一般的程序设计中用户自定义的变量实在是没有绝对定位的必要。
如果需要,位变量也可以绝对定位。但必须遵循上面介绍的位变量编址的方式。如果一个普通变量已经被绝对定位,那么此变量中的每个数据位就可以用下面的计算方式实现位变量指派:
unsigned char tmpData @ 0x20; //tmpData定位在地址0x20
bit tmpBit0 @ tmpData*8+0; //tmpBit0对应于tmpData第 0 位
bit tmpBit1 @ tmpData*8+1; //tmpBit0对应于tmpData第 1 位
bit tmpBit2 @ tmpData*8+2; //tmpBit0对应于tmpData第 2 位
如果 tmpData 事先没有被绝对定位,那就不能用上面的位变量定位方式。