当使用到ASCII码字库点阵的时候,我们习惯定义一个大的数组来存放。如果没有指定存储区域,数组一般都是保存在RAM当中的,如果单片机的RAM空间比较紧张,就需要将数组保存在ROM当中。对于51单片机,如果只在数组前加const,只是声明这个数组的内容是只读的,但是,数组还是保存在RAM中的,可以通过查看代码空间大小进行验证。网上还有不少人认为只要声明const,就是只读的,就是放在ROM里面的,这个是错误的。这个只读只是你无法直接更改数组的内容,因为编译器会强制报错。但是,通过指针指向数组的方式,还是可以间接更改数组的内容的。要指定数组保存在ROM里,除了需要const关键字,还需要加上数据存储类型(区域修饰符)。对于keil,用code表明变量存放在ROM中;对于IAR for 8051,用__code表面变量存放在ROM中。由于我用的平台是IAR for 8051,单片机是STC8A8K64S4A12,测试也是基于这个平台。下面讲一下用指针访问ROM中数组的方法。 首先定义一个数组 __code const unsignde char array[] = {0x11,0x22,0x33,0x44};//声明数组保存在ROM里
再定义一个指针:
unsigned char __code const *p;//这是一个指针,指向code区域的unsigned char常量(const)
再获取数组的首地址
p = array;//指向数组首地址
这里指针p一定要用__code修饰,如果不用__code修饰,会报错。指针可以正常访问ROM中数组的内容。
不过可能有人可能会这样做:
__code const unsignde char array[] = {0x11,0x22,0x33,0x44};//声明数组保存在ROM里
unsigned char *p;
p = (unsigned char*)array;//指向数组首地址 (类型强制转换)
这样虽然编译不会报错,p指向的地址就是数组存放在ROM当中的地址值,这样看起来没问题,把地址值打印出来验证也正确,但是在使用的时候,会发现怎么也没法访问到正确的数组内容,而是其他内容,感觉像是指针跑飞了一样。其实原因很简单,定义指针p时没有加上__code,那么p指向的地址空间是在RAM里面的。也就是在RAM中访问和ROM相同地址值的内容,当然永远也无法访问到数组的内容的。
如果硬要这样定义指针p,也不是没有办法访问ROM中的数组。比如先将ROM数组复制到RAM中,再进行访问,可以按照如下操作:
__code const unsignde char array[] = {0x11,0x22,0x33,0x44};//声明数组保存在ROM里
unsigned char *p;
unsigned char a[4];
for(unsigned char i = 0; i < 4; i++)
{
a[ i] = array[ i]; //直接访问ROM的数组,再复制到RAM中
}
p = a;
里面多了一个操作,再定义一个数组a,然后将数组array存放在ROM里面的内容复制到存放在RAM里面的a,再用p指向a的地址。虽然最终也可以正常获取数据,但是效率低下,这种操作是最不值得推荐的。