如何将51单片机进行内存优化

发布时间:2023-10-10  

对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 “。DebugTest”。。.

“。DebugTest” - 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个字节未充分利用或根本未用到

出现这种情况最常见的原因是局变量太多、多个子程序中的局部变量数目差异太大、使用了寄存器切换但未充分利用。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>