仿真51单片机程序时发现一个很严重的BUG,程序里一个很重要的全局变量在运行时居然被改变了,原本设置的值是2000,但是调用时值居然是0,大致的代码如下:
//全局变量aaa值是2000
unsigned short aaa=2000;
void fun1(unsigned short x)
{
unsigned short b;
b=x;//这里仿真时发现全局变量莫名其妙变成0了
}
void fun2()
{
...
fun1(aaa);//调用全局变量
...
}
全局变量为何会被改动呢?而且还被初始化为0了。
在前面加上关键字volatile防止编译器对变量进行优化,仿真后还是不行,全局变量仍被修改。我又尝试换成数组类型、结构体类型,结果仍然不能阻止全局变量被修改。为什么一个全局变量在内存里好好地待着,生命周期那么长,结果还被莫名其妙改动了?
我用的单片机是STC12C5A,之前看到过STC-ISP里延时函数定义变量用data修饰,然后查询关键字data是干什么用的。其实宏晶他们的单片机RAM有两个部分,一部分是兼容传统8051的RAM共256 Bytes,另一部分是XRAM扩展区比较大,这部分的大小根据不同型号是不一样的,我的这片的XRAM好像是2K Bytes。由于程序里变量太多,需要的RAM比较多,我在配置的时候选择较大内存区域,如下图
然后查询编译生成的map文件(也就是.m51文件),发现那个全局变量是被存在了扩展XRAM里,不是传统RAM里。变量那么多,很有可能放在XRAM里会被修改,而且单片机对传统RAM的访问速度比XRAM要快,所以我尝试将全局变量放在传统RAM里,程序如下
//用关键字data修饰就能把变量放在传统RAM里
unsigned short data aaa=2000;
仿真之后成功了,全局变量没有再被莫名其妙修改了。其实挺奇怪的,这些底层的编译和硬件居然也是会变,我还没搞明白为啥传统RAM里的变量更安全。
总结就是,如果全局变量存放在扩展XRAM里可能会被莫名其妙地被修改(就是不太安全),而存放在传统RAM里就挺安全的,尽管容量小了点。以后也尽量遵循这个规律:局部变量放在扩展XRAM里(用xdata修饰),全局变量最好放在传统RAM里(data修饰)。