对51单片机内存的知道,很多人有误解,最常见的是以下两种
① 超越变量128后有必要运用compact形式编译
实践的状况是只需内存占用量不超越 256.0 就能够用 small 形式编译
② 128以上的某些地址为特别存放器运用,不能给程序用
与 PC机不同,51单片机不运用线性编址,特别存放器与 RAM 运用重复的重复的地址。但拜访时选用不同的指令,所以并不会占用 RAM 空间。
因为内存比较小,一般要进行内存优化,尽量进步内存的运用功率。
以 Keil C 编译器为例,small 形式下未指存储类型的变量默以为data型,即直接寻址,只能拜访低 128 个字节,但这 128 个字节也不是全为咱们的程序所用,存放器 R0-R7有必要映射到低RAM,要占去 8 个字节,假如运用存放组切换,占用的更多。
所以能够运用 data 区最大为 120 字节,超出 120 个字节则有必要用 idata 显式的指定为直接寻址,别的仓库至少要占用一个字节,所以极限状况下能够界说的变量可占 247 个字节。当然,实践运用中仓库为一个字节肯定是不够用的,但假如嵌套调用层数不深,有十几个字节也够有了。
为了验上面的观念,写了个比如
#define LEN 120
data UCHAR tt1[LEN];
idata UCHAR tt2[127];
void main()
{
UCHAR i,j;
for(i = 0; i 《 LEN; ++i )
{
j = i;
tt1[j] = 0x55;
}
}
能够核算 R0-7(8) + tt1(120) + tt2(127) + SP(1) 一共 256 个字节
keil 编译的成果如下:
Program Size: data=256.0 xdata=0 code=30
creaTIng hex file from “。\Debug\Test”。。.
“。\Debug\Test” – 0 Error(s), 0 Warning(s)。
(测验环境为 XP + Keil C 7.5)
这段代码现已达到了内存分配的极限,再界说任何全局变量或将数组加大,编译都会报错 107
这儿要引出一个问题:为什么变量 i、j 不核算在内?
这是因为 i、j 是部分变量,编译器会试着将其优化到存放器 Rx 或栈。问题也就在这了,假如部分变量过多或界说了部分数组,编译器无法将其优化,就有必要运用 RAM 空间,尽管全局变量的分配经过精心核算没有超出运用范围,仍会发生内存溢出的过错!
而编译器是否能成功的优化变量是依据代码来的
上面的代码中,循环是臃肿的,变量 j 彻底不必要,那么将代码改成
UCHAR i;
UCHAR j;
for(i = 0; i 《 LEN; ++i )
{
tt1[i] = 0x55;
}
再编译看看,犯错了吧!
因为编译器不知道该怎么运用 j,所以没能优化,j 须占 RAM 空间,RAM 就溢出了。
(智能一点的编译器会主动将这个无用的变量去掉,但这个不在评论之列了)
别的,对 idata 的界说的变量最好放在 data 变量之后
关于这一种界说
uchar c1;
idata uchar c2;
uchar c3;
变量 c2 肯定会以直接寻址,但它有或许落在 data 区域,就浪费了一个可直接寻址的空间
变量优化一般要注意几点:
①让尽或许多的变量运用直接寻址,进步速度
假如有两个单字节的变量,一个长119的字符型数组
因为总长超越 120 字节,不或许都界说在 data 区
按这条准则,界说的方法如下:
data UCHAR tab[119];
data UCAHR c1;
idata UCHaR c2;
但也不是绝的,假如 c1, c2 需求以极高的频率拜访,而 tab 拜访不那么频频
则应该让拜访量大的变量运用直接寻址:
data UCAHR c1;
data UCHaR c2;
idata UCHAR tab[119];
这个是要依据详细项目需求来确认的
②进步内存的重复运用率
便是尽或许的运用部分变量,部分变量还有个优点是拜访速度比较快
由前面的比如能够看出,部分变量 i, j 是没有独自占用内存的
子程序中运用内存数目不大的变量尽量界说为部分变量
③关于指针数组的界说,尽或许指明存储类型
尽量运用无符号类型变量
一般指针需求一个字节额定的字节指明存储类型
8051 系列自身不支持符号数,需求外加库来处理符号数,一是大大下降程序运转功率,二是需求额定的内存
④防止呈现内存空泛
能够经过检查编译器输出符号表文件(.M51)检查
对前面的代码,M51文件中关于内存一节如下:
* * * * * * * D A T A M E M O R Y * * * * * * *
REG 0000H 0008H ABSOLUTE “REG BANK 0”
DATA 0008H 0078H UNIT ?DT?TEST
IDATA 0080H 007FH UNIT ?ID?TEST
IDATA 00FFH 0001H UNIT ?STACK
榜首行显现存放器组0从地址0000H开端,占用0008H个字节
第二行显现DATA区变量从0008H开端,占用0078H个字节
第三行显现IDATA区变量从0080H开端,占用007F个字节
第四行显现仓库从00FFH开端,占0001H个字节
因为前面代码中变量界说比较简单,且接连用完了一切空间,所以这儿显现比较简单
变量界说较多时,这儿会有很多行
假如全局变量与部分变量分配不合理,就有或许呈现相似下面的行
0010H 0012H *** GAP ***
该行表明从0010H开端接连0012H个字节未充分运用或底子未用到
呈现这种状况最常见的原因是局变量太多、多个子程序中的部分变量数目差异太大、运用了存放器切换但未充分运用。