当前位置:首页 > 单片机 > 单片机
[导读]对 51 单片机内存的认识,很多人有误解,最常见的是以下两种:① 超过变量128后必须使用compact模式编译实际的情况是只要内存占用量不超过 256.0 就可以用 small 模式编译② 128以上的某些地址为特殊寄存器使用,不能

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

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

扩展阅读:EEPROM的几种保护方法

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

STM32与51单片机之间有什么差异呢?两者可以说是一场科技与性能的较量了。在科技飞速发展的今天,微控制器(MCU)已广泛应用于各类电子设备和系统中,发挥着举足轻重的作用。其中,STM32和51单片机作为两种常见的微控制...

关键字: STM32 51单片机 MCU

51单片机将是下述内容的主要介绍对象,通过这篇文章,小编希望大家可以对51单片机的相关情况以及信息有所认识和了解,详细内容如下。

关键字: 单片机 51单片机

MIKROE增加了图形功能,CLANG支持ARM和RISC-V以及许多其他功能

关键字: 编译器 RISC-V架构 工业自动化

在嵌入式系统开发中,单片机是不可或缺的重要组成部分。其中,STM32单片机和51单片机是两种常见的单片机芯片。本文将对比分析这两种单片机的区别,并探讨STM32单片机的优势。

关键字: stm32单片 51单片机

51单片机是指由美国INTEL公司生产的一系列单片机的总称,这一系列单片机包括了许多品种,如8031,8051,8751,8032,8052,8752等,其中8051是最早最典型的产品,该系列其它单片机都是在8051的基...

关键字: 51单片机 串行通信

IAR Embedded Workbench for Arm已全面支持恩智浦最新的S32系列,可加速软件定义汽车的车身和舒适性应用的开发

关键字: 电机控制 电动汽车 编译器

这款新编译器专为dsPIC®数字信号控制器 (DSC)优化设计,可为实时应用定制许可选项

关键字: 编译器 数字信号控制器 自动驾驶

51单片机是一种常见的微控制器,它具有串行通信接口(Serial Communication Interface,SCI)。通过串口通信接口,51单片机可以与其他设备或系统进行串行通信,实现数据传输和控制。

关键字: 51单片机 串口通信

C语言编译器是一种用于将C语言源代码转换为可执行程序的软件工具。它的主要功能是将C语言代码翻译成机器语言,以便计算机能够理解和执行。C语言编译器通常包括预处理器、编译器、汇编器和链接器等多个组件,它们协同工作以完成编译过...

关键字: C语言 编译器 Microsoft Visual C++

Pic单片机和51单片机是两种应用广泛的微控制器,它们各自具有不同的特点和优势,选择哪种单片机取决于具体应用需求。下面将对Pic单片机和51单片机进行详细的介绍和对比。

关键字: PIC单片机 51单片机 单片机
关闭
关闭