C51内存优化(data/idata/xdata)

发布者:huanhui最新更新时间:2021-05-28 来源: eefocus关键字:C51  内存优化  data  xdata 手机看文章 扫描二维码
随时随地手机看文章

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

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


关键字:C51  内存优化  data  xdata 引用地址:C51内存优化(data/idata/xdata)

上一篇:非常简单的8×8LED点阵c51源代码
下一篇:93C46/93c06/93c46/93c56/93c66/93c86的驱动程序(C51)

推荐阅读最新更新时间:2024-11-10 11:12

c51单片机外扩 62256 静态RAM
学习汇编语言寻址方式时 理论的知道 但是想知道地址总线物理的连接 所以自己就买了一个62256芯片(32K 静态RAM)进行连接,然后写程序测试。 上面原理图中 有个问题 62256芯片A0-A7没有接 需要用 74HC573 74HC573的链接图 然后网上又找到一张图 C51单片机中有ALE引脚,这个引脚会控制P0脚输出的是地址还是数据 使用原件 AT89S51 62256 74HC573 C51单片机建议买STC公司生产的40脚双列直插的 可以自己制作串口下载线
[单片机]
<font color='red'>c51</font>单片机外扩 62256 静态<font color='red'>RAM</font>
位变量访问float的二进制位(c51)
;问题:C语言不允许使用位变量来访问浮点数据类型的二进制位,请看一下代码: union flm { float mf; long ml; }; bdata struct bady { char ml; union flm ex; }try; sbit tryf31 = try.ex.ml ^ 31; sbit trym10 = try.ml ^ 0; sbit trym17 = try.ml ^ 7; ;处理方法:通过将浮点数和长整数构造一个联合(两者均为32位),后用位变量来访问联合中长整型的位,由于float和long在union中占用了相同的存储空间,也就访问了浮点数的对应位。
[单片机]
手动编译链接生成c51的hex文件
这个纯粹是个人爱好。现在系统的UI的做得越来越好,但还是莫名的喜欢那个命令行,算是种怀旧吧。 再次声明:该举动仅为个人爱好而已 虽然是手动编译,但还是需要个keil安装后的环境。 详细步骤: 1.用记事本或者notepad++编写超简单的代码 例如: #include reg52.h sbit L1 = P1^2; void main() { L1 = 0; while(1); } 保存为test.c 这个源码最好建立到keilC51BIN目录下,避免敲过多的路径。 2.cmd 下进入keil 安装目录 keilC51BIN 执行如下命令: c51x te
[单片机]
#C51按键处理(初阶基础)
前言 引入按键处理的思想过程 样例:按键处理系列,低配初阶最基本方法,按下有效 提示:以下是本篇文章正文内容,下面案例可供参考 一、单按键处理逻辑 1.等待按下 2.按键抖动 2.1 硬件消抖:R-S触发器、RC电路 2.2 软件消抖,延时消抖5-20ms 3.判断为有效按下 4.松开抖动 软件消抖 5.判断为松开按键 unsigned char key_num = 0;//充分考虑是否需要赋初始值0。任何局部变量建立后记得清0。标志法其它位置清0,或者每次进入函数体初始化清0。 if(!KeyIn1) { Delay_xms(10); //消抖。缺点:进程占用,复杂程序影响其它时基。后续采用中断定时
[单片机]
#<font color='red'>C51</font>按键处理(初阶基础)
C51自学笔记】实时时钟芯片DS1302
简介: 芯片内部具有可编程日历时钟和31个字节的静态RAM,日历时钟可自动进行闰年补偿,计时准确,接口简单,使用方便,工作电压范围宽,功耗低,芯片自身还具有对备份电池进行涓流充电功能,可以有效地延长备份电池的使用寿命。 连接图:8051单片机与DS1302的一种接口电路 单片机与DS1302之间采用3线串行通信方式 RST为通信允许信号,RST=1允许通信,RST=0禁止通信。 IO为双向串行数据传送信号,SCLK为串行数据的位同步脉冲信号。 8051作为主机通过控制RST、SCLK和IO信号实现两芯片之间的数据传送。 DS1302芯片的X1和X2端外接32.768KHz的石英晶振 Vcc1和Vcc2是电源引脚,单电源
[单片机]
【<font color='red'>C51</font>自学笔记】实时时钟芯片DS1302
C51单片机0~60计数器
源码 #includeunsigned char code table ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; unsigned char second=0; bit a=0; char t=0; int0_srv() interrupt 1{ t++; if(t==20){t=0;a=1;} TH0=0x3c; TL0=0xb0; } main(){ P0=P2=table ; TMOD=0x01; TH0=0x3c; TL0=0xb0; ET0=1; EA=1; TR0=1; while(1){ if(a){
[单片机]
<font color='red'>C51</font>单片机0~60计数器
DataMan 302读码器:让汽车发动机连杆二维码的检测读取简单
文/奇瑞汽车股份有限公司 杨成 奇瑞汽车有限公司(以下简称奇瑞汽车)是国内知名的自主品牌汽车整车及零部件制造商,其汽车核心部件 自主研发、设计和加工制造的发动机更是奇瑞汽车的骄傲。 在奇瑞汽车发动机的连杆加工生产线中,发动机连杆采用二维码进行等级和生产信息记录,通过A、B两种等级以及不合格件进行设备的自动分类。连杆等级测量工序由全自动高效率的组合式设备构成。连杆加工在该工序中由四大部分组成: 1)工序机床本体采用SIEMENS的CPU317系统,其主要功能和作用是控制机床的夹具动作和机械手,并发出信号启动外部设备和接受外面设备发送过来的信息; 2)尺寸测量系统采用意大利Marposs公司的测量
[汽车电子]
C51单片机运用定时器T0中断实现电子时钟
上面是 电路原理图 下面是程序源代码: /***************************************************************************** 功能描述:运用定时器T0实现 电子时钟 **************************************************************************/ #include reg52.h #include intrins.h #define uint unsigned int #define uchar unsigned char sbit p32=P3^2; sbit p33=P
[单片机]
<font color='red'>C51</font>单片机运用定时器T0中断实现电子时钟
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved