C51单片机内存优化

发布者:HarmonySpirit最新更新时间:2016-12-15 来源: eefocus关键字:C51  单片机  内存优化 手机看文章 扫描二维码
随时随地手机看文章

  52本身有256B的数据存储区,如果没在意一些细节,很容易出现RAM超过128就报错的情况。现讲其问题解释如下:

  最常见的是以下两种:

  ① 超过变量128后必须使用compact模式编译,实际的情况是只要内存占用量不超过256.0,就可以用 small 模式编译

  ② 128以上的某些地址为特殊寄存器使用,不能给程序用。与 PC 机不同,51 单片机不使用线性编址,特殊寄存器与 RAM 使用重复的重复的地址。但访问时采用不同的指令,所以并不会占用 RAM 空间。

  ③是否把一些固定的代码存贮到了CODE区。如果把没变化的数据也存储到DATA去,就太浪费了!

  由于内存比较小,一般要进行内存优化,尽量提高内存的使用效率。

  以 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个字节未充分利用或根本未用到,出现这种情况最常见的原因是局变量太多、多个子程序中的局部变量数目差异太大、使用了寄存器切换但未充分利用


 


关键字:C51  单片机  内存优化 引用地址:C51单片机内存优化

上一篇:keil c51的内部RAM(idata)动态内存管理程序
下一篇:C51变量的存储

推荐阅读最新更新时间:2024-03-16 15:25

Atmel和STC的51单片机通用ISP下载线制作
暑假在学校准备比赛的时候,因为自己没有ISP下载线,无法把程序下载到AT的单片机上。STC的比较方便,拿个电平转换芯片MAX232接上去就可以用串口下载,这里就不详细讲工作原理了。下面主要说一下AT单片机的串口ISP下载线制作。 先说一下两种单片机下载程序是要用到的引脚: STC的下载引脚为P3.0、P3.1,也就是RXD和TXD; Atmel的下载引脚为P1.5、P1.6和P1.7,其次还要在上电后,把RST引脚的电平拉高才能进行下载。 为了在一块板上兼容两种品牌单片机的下载,所以设计时要考虑引脚复用带来的后果,本来想用CD40xx系列的模拟开关进行自动切换下载线,但是实验室只有4051,这是八选一的模拟开关
[单片机]
Atmel和STC的51<font color='red'>单片机</font>通用ISP下载线制作
PIC单片机三个定时器中断同时定时
16F877A有三个定时器,中断方式都调试出来了,想把它们整合到一块同时工作,可搞了半天,就是不干。最后整明白了,PIC16系列单片机的中断入口中有一个。PIC的功能是很强大,外围模块也多,速度也较快,但PIC的这个中断方案不好,应该改进。以下是三个定时中断同时工作的调试代码。 #include pic.h #define uchar unsigned char #define uint unsigned int __CONFIG(0x3B31); void init(); uint Timer0Num,Timer1Num,Timer2Num;// void timer0(); void timer1(); void timer
[单片机]
基于ARM高速闪存MCU应对广泛嵌入式需求
  由于采用了ARM7TDMI-S内核,LPC2000系列MCU工作频率达60MHz,与其他8-bit产品相比具有更强的功能延展性。同时它借助片上存储器加 模块实现了“零等待访问”高速闪存功能,提高了指令执行的效率。   此外,LPC2000的外设接口非常丰富,包括UART、SPI、I2C、CAN、ADC、 PWM、RTC等。LPC2000系列MCU应用领域非常广泛,从网络通信、 马达控制,到汽车和消费电子都适合于涉足。   嵌入式系统是面向用户、面向产品、面向应用的,它是将先进计算机技术、半导体技术和电子技术以及各行业的具体应用相结合的产物,因此它是一个高度密集、不断创新的知识集成系统。作为嵌入式系统,它必须能够根据应用的需
[应用]
单片机C语言中数组的用法
数组是由具有相同类型的数据元素组成的有序集合。数组是由数组名来表示的,数组中的数据由特定的下标来唯一确定。引入数组的目的,是使用一块连续的内存空间存储多个类型相同的数据,以解决一批相关数据的存储问题。数组与普通变量一样,也必须先定义,后使用。数组在C51语言的地位举足轻重,因此深入地了解数组是很有必要的。下面就对数组进行详细的介绍。 (1)一维数组 一维数组是最简单的数组,用来存放类型相同的数据。数据的存放是线性连续的。 用以下例程说明数组的建立、数据操作: #include /* ----------------------------------------------------- 此程序用以说
[工业控制]
LED单片机定时闹铃程序
;*****led显示单片机定时闹铃程序************************************** ; 变量地址分配 ;********************************************************* Hour EQU 3AH; 小时计数器的地址 Minute EQU 3BH; 分钟计数器的地址 Second EQU 3CH; 秒计数器的地址 P1Val EQU 3DH; 数码管位驱动值的地址 ClockMode BIT 20H.0; 模式(正常走时/闹时)设置寄存器地址, 值为0时正常走时,为1时闹时设定 AlarmOnOff BIT 20H.1; 闹钟开启/关闭标志,为0关闭
[单片机]
基于单片机的自适应电开水机设计
摘要:本电开水机采用自适应的方式,模拟人工总结用户的用水规律,合理确定烧水时间与烧水量,在非用水时间段停止加热,解决了混合水和干滚水的问题,较好的达到了健康与节能的双重效果。 关键词:自适应;电路设计;电开水机;单片机 0 引言 电开水机具有清洁、高效、安装简便等特点,因此被广泛应用在学校、工厂、机关、宾馆等场所,为人们饮水提供了便利。目前市售的电开水机,通常由储水箱、加热器、进水阀等部件组成,结构简单,功能单一。使用这些电开水机可能存在两个严重的后果,一是存在阴阳水(生水与开水混合后的水),二是存在干滚水(反复烧开的水)。阴阳水的问题在大多数开水机中通过一些特殊的分离结构已经得到解决,但干滚水问题目前尚无较好的解决办法。
[工业控制]
基于<font color='red'>单片机</font>的自适应电开水机设计
关于单片机的硬件知识
简介:由于MCS-51单片机是在MCS-48的基础上推出的增强型产品。比后者提高了芯片的集成度,性能大为提高,硬件功能大大增加,功能单元的种类数量也得到了扩展。 I/O口 MCS-51单片内部I/O口的数量和种类多而齐全,尤其是它有一个全双工的串行口,更突出了这种单片机的本身特点。该串行口是利用两根I/O口线构成的,由4种工作方式,可通过编程选定。MCS-51有32根I/P口线,而MCS-48只有27根。 中央处理器 单片机的中央处理器是单片机内部的核心部件,它决定了单片机的主要功能特性。 中央处理主要由运算部件和控制部件组成。 ALU功能 MCS-51单片机ALU功能十分强,它不仅可对8位位变量进行逻辑“
[单片机]
基于51单片机开发板8*8LED矩阵的贪吃蛇程序
引语:过年的时候闲着无聊,恰好也刚学了点51开发板的东西,所以就想写一个贪吃蛇的小程序。在网上总结了一些关于贪吃蛇的算法,于是就有了以下的程序。 先来说以一下算法的原理:将8*8LED看作是直角坐标系,将左上角定为坐标原点。定义两个数组 snake_x ,snake_y 用来存储蛇的x,y轴坐标。因此,我们的核心算法就是小蛇惯性保持自己的运动姿态,产生食物,以及小蛇吃到食物后长度增加。 再来看一下我的开发板,我的开发板是德飞莱51开发板,这里不再讲解其8*8LED的工作原理,直接上代码 void Hc595SendByte() { unsigned char a; SRCLK=0; RCLK=0; for(a=
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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