历史上的今天
返回首页

历史上的今天

今天是:2025年04月01日(星期二)

正在发生

2021年04月01日 | 有关C51存储器类型与51单片机的物理区域

2021-04-01 来源:eefocus

1、 data区空间小,所以只有频繁用到或对运算速度要求很高的变量才放到data区内,比如for循环中的计数值。


2、 data区内最好放局部变量。


因为局部变量的空间是可以覆盖的(某个函数的局部变量空间在退出该函数是就释放,由别的函数的局部变量覆盖),可以提高内存利用率。当然静态局部变量除外,其内存使用方式与全局变量相同;


扩展阅读:51单片机的特殊功能寄存器(SFR)


3、 确保你的程序中没有未调用的函数。


在Keil C里遇到未调用函数,编译器就将其认为可能是中断函数。函数里用的局部变量的空间是不释放,也就是同全局变量一样处理。这一点Keil C做得很愚蠢,但也没办法。


4、 程序中遇到的逻辑标志变量可以定义到bdata中,可以大大降低内存占用空间。


在51系列芯片中有16个字节位寻址区bdata,其中可以定义8*16=128个逻辑变量。定义方法是: bdata bit LedState;但位类型不能用在数组和结构体中。


5、 其他不频繁用到和对运算速度要求不高的变量都放到xdata区。


6、 如果想节省data空间就必须用large模式,将未定义内存位置的变量全放到xdata区。当然最好对所有变量都要指定内存类型。


7、 当使用到指针时,要指定指针指向的内存类型。在C51中未定义指向内存类型的通用指针占用3个字节;而指定指向data区的指针只占1个字节;指定指向xdata区的指针占2个字节。如指针p是指向data区,则应定义为: char data *p;。还可指定指针本身的存放内存类型,如:char data * xdata p;。其含义是指针p指向data区变量,而其本身存放在xdata区。


bit---是在内部数据存储空间中 20H .. 2FH 区域中一个位的地址,或者 8051 位可寻址 SFR 的一个位地址。


code---是在 0000H .. 0FFFFH 之间的一个代码地址。


data---是在 0 到 127 之间的一个数据存储器地址,或者在 128 .. 255 范围内的一个特殊功能寄存器(SFR)地址。


idata---是 0 to 255 范围内的一个 idata 存储器地址。


xdata 是 0 to 65535 范围内的一个 xdata 存储器地址。


指针类型和存储区的关系详解


一、存储类型与存储区关系


data ---> 可寻址片内ram


bdata ---> 可位寻址的片内ram


idata ---> 可寻址片内ram,允许访问全部内部ram


pdata ---> 分页寻址片外ram (MOVX @R0) (256 BYTE/页)


xdata ---> 可寻址片外ram (64k 地址范围)


code ---> 程序存储区 (64k 地址范围),对应MOVC @DPTR


二、指针类型和存储区的关系


对变量进行声明时可以指定变量的存储类型如:


uchar data x和data uchar x相等价都是在内ram区分配一个字节的变量。


同样对于指针变量的声明,因涉及到指针变量本身的存储位置和指针所指向的存储区位置不同而进行相应的存储区类型关键字的使用如:


uchar xdata * data pstr


是指在内ram区分配一个指针变量("*"号后的data关键字的作用),而且这个指针本身指向xdata区("*"前xdata关键字的作用),可能初学C51时有点不好懂也不好记。没关系,我们马上就可以看到对应“*”前后不同的关键字的使用在编译时出现什么情况。


......


uchar xdata tmp[10]; //在外ram区开辟10个字节的内存空间,地址是外ram的0x0000-0x0009


......


第1种情况:


uchar data * data pstr;


pstr=tmp;


首先要提醒大家这样的代码是有bug的, 他不能通过这种方式正确的访问到tmp空间。 为什么?我们把编译后看到下面的汇编代码:


MOV 0x08,#tmp(0x00) ;0x08是指针pstr的存储地址


看到了吗!本来访问外ram需要2 byte来寻址64k空间,但因为使用data关键字(在"*"号前的那个),所以按KeilC编译环境来说就把他编译成指向内ram的指针变量了,这也是初学C51的朋友们不理解各个存储类型的关键字定义而造成的bug。特别是当工程中的默认的存储区类为large时,又把tmp[10] 声明为uchar tmp[10] 时,这样的bug是很隐秘的不容易被发现。


第2种情况:


uchar xdata * data pstr;


pstr = tmp;


这种情况是没问题的,这样的使用方法是指在内ram分配一个指针变量("*"号后的data关键字的作用),而且这个指针本身指向xdata区("*"前xdata关键字的作用)。编译后的汇编代码如下。


MOV 0x08,#tmp(0x00) ;0x08和0x09是在内ram区分配的pstr指针变量地址空间


MOV 0x09,#tmp(0x00)


这种情况应该是在这里所有介绍各种情况中效率最高的访问外ram的方法了,请大家记住他。


第3种情况:


uchar xdata * xdata pstr;


pstr=tmp;


这中情况也是对的,但效率不如第2种情况。编译后的汇编代码如下。


MOV DPTR, #0x000A ;0x000A,0x000B是在外ram区分配的pstr指针变量地址空间


MOV A, #tmp(0x00)


MOV @DPTR, A


INC DPTR


MOV A, #tmp(0x00)


MOVX @DPTR, A


这种方式一般用在内ram资源相对紧张而且对效率要求不高的项目中。


第4种情况:


uchar data * xdata pstr;


pstr=tmp;


如果详细看了第1种情况的读者发现这种写法和第1种很相似,是的,同第1 种情况一样这样也是有bug的,但是这次是把pstr分


配到了外ram区了。编译后的汇编代码如下。


MOV DPTR, #0x000A ;0x000A是在外ram区分配的pstr指针变量的地址空间


MOV A, #tmp(0x00)


MOVX @DPTR, A


第5种情况:


uchar * data pstr;


pstr=tmp;


大家注意到"*"前的关键字声明没有了,是的这样会发生什么事呢?下面这么写呢!对了用齐豫的一首老歌名来说就是 “请跟我来”,请跟我来看看编译后的汇编代码,有人问这不是在讲C51吗? 为什么还要给我们看汇编代码。C51要想用好就要尽可能提升C51编译后的效率,看看编译后的汇编会帮助大家尽快成为生产高效C51代码的高手的。还是看代码吧!


MOV 0x08, #0X01 ;0x08-0x0A是在内ram区分配的pstr指针变量的地址空间


MOV 0x09, #tmp(0x00)


MOV 0x0A, #tmp(0x00)


注意:这是新介绍给大家的,大家会疑问为什么在前面的几种情况的pstr指针变量都用2 byte空间而到这里就用3 byte空间了呢?这是KeilC的一个系统内部处理,在KeilC中一个指针变量最多占用 3 byte空间,对于没有声明指针指向存储空间类型的指针,系统编译代码时都强制加载一个字节的指针类型分辩值。具体的对应关系可以参考KeilC的help中C51 User's Guide。


第6种情况:


uchar * pstr;


pstr=tmp;


这是最直接最简单的指针变量声明,但他的效率也最低。还是那句话,大家一起说好吗!编译后的汇编代码如下。


MOV DPTR, #0x000A ;0x000A-0x000C是在外ram区分配的pstr指针变量地址空间


MOV A, #0x01


MOV @DPTR, A


INC DPTR


MOV DPTR, #0x000A


MOV A, #tmp(0x00)


MOV @DPTR, A


INC DPTR


MOV A, #tmp(0x00)


MOVX @DPTR, A


这种情况很类似第5种和第3种情况的组合,既把pstr分配在外ram空间了又增加了指针类型的分辨值。


小结一下:大家看到了以上的6种情况,其中效率最高的是第2种情况,既可以正确访问ram区又节约了代码,效率最差的是第 6种,但不是说大家只使用第2种方式就可以了,还要因情况而定,一般说来应用51系列的系统架构的内部ram资源都很紧张,最好大家在定义函数内部或程序段内部的局部变量使用内ram,而尽量不要把全局变量声明为内ram区中。所以对于全局指针变量我建议使用第3 种情况,而对于局部的指针变量使用第2种方式。


keil C51存储区域分为程序存储区和数据存储区2大类型。


一.程序存储区(Pragram Area):


欲将声明的数据存放在程序存储区域,可以使用关键字“code”说明。


例 unsigned char code i=10;则表示 i为无符号字符型数据存放区域为程序存储区。


二.数据存储区(Data Memory):


数据存储区域分为内部数据存储区、外部数据存储区域和特殊功能寄存器寻址区。


1.内部数据存储区域(Internal Data Memory):可以使关键字"data、iadta、bdata"做相应说明。


data:直接寻址区,声明的数据存储范围为内部RAM低128字节 0X00~0X7F。


例 unsigned char data i=10;则表示 i为无符号字符型数据存放区域为数据存储区域(RAM)的低128字节范围内。


idata:间接寻址区,声明的数据存储范围为整个内部RAM区 0X00~0XFF。


例 unsigned char idata i=10;则表示 i为无符号字符型数据存放区域为数据存储区域(RAM)内。


bdata:可位寻址区,寻址范围为0X20~0X2F。


2.外部数据存储区(External Data Memory):可以使用关键字"pdata、xdata"进行说明。


pdata:主要用于紧凑模式,能访问1页(256字节)的外部RAM,即在访问使用,pdata定义的数据时,不会影响P2口的输出电平(在访问某些自身内部扩展的外部RAM时本身就不会影响I/O端口)。


例 unsigned char pdata i;则表示 i为无符号字符型数据存放区域为外部数据存储区域(RAM)内(只能在一页范围内)具体操作哪一页,可由其他i/o口设定。


xdata:可访问64k的外部数据存储区,地址范围0X0000~0XFFFF,同pdata一样在访问芯片自身内部扩展的RAM时也不会影响I/O端口。


例 unsigned char pdata i;则表示 i为无符号字符型数据存放区域为外部数据存储区(RAM)。


3.特殊功能寄存器寻址区域(Speciac Function Register Memory)-SFR:8051提供128字节的SFR寻址区,该区域可以字节寻址,字寻址,能被8整除的地址单元还可以位寻址。该区域用于控制定时器、计数器、串口等外围接口。使用时可用关键字“sfr、sfr16、sbit”做相应的声明。


例 字节寻址 sfr P0=0x80;为P0 口地址为80H,“=”后0X00~0XFF 之间的常数。


字寻址 sfr16 T2=0XCC;指定Timer2 口地址T2L=0XCC T2H=0XCD。


位寻址 sbit EA=0xAF;指定第0xAF 位为EA,即中断允许


存储模式


在使用C51时有时我们并没有明确指定所定义的数据的存储类型,然而依然正确。 这是由于存储模式决定了没有明确指定存储类型的变量,函数参数等的缺省存储区域。


供有3种存储模式(存储模式在 C51 编译器选项中选择):


1.Small模式


所有缺省变量参数均装入内部 RAM,优点是访问速度快,缺点是空间有限,只适用于小程序。


2. Compact 模式


所有缺省变量均位于外部RAM区的一页(256Byte)。


3. Large 模式


所有缺省变量可放在多达 64KB 的外部RAM 区,优点是空间大,可存变量多,缺点是速度较慢。


C51存储器类型有bit sbit data xdata bdata pdata sfr code等,可能不全面有遗漏


对应的物理存储器是:


bit,即位数据:数据存储器位寻址区,即20H~2FH的范围,共16个字节,16*8=128个位,位地址00h~7fh,连续的。


sbit:特殊功能寄存器中的位数据:只有能够被8整除的那些特殊功能寄存器中的各个位才能被称为sbit,位地址80H~FFH,不连续的,间断的。


data:数据区,对51为00H~7FH共128个字节,对52为00H~FFH,共256个字节,用MOV寻址,前128用直接寻址或寄存器(R0~R7)寻址,后128用R0、R1间接寻址。


xdata:外部数据区,0000H~FFFFH连续,用DPTR间接寻址(MOVX指令)


bdata:位寻址去的字节,20H~2FH


sfr:特殊功能寄存器(80H~FFH),直接寻址


pdata:外部数据区,P2口保持数据,用R0R1间接寻址(MOVX指令)


code:程序存储器,用MOVC指令只读


推荐阅读

史海拾趣

DBM REFLEX公司的发展小趣事

DBM REFLEX公司成立于本世纪初,初期以提供光学组件的小规模定制服务为主。创始人对光学技术的深刻理解和对市场的精准把握,使公司迅速在光学器件领域崭露头角。随着技术的不断积累和市场需求的增长,DBM REFLEX逐渐扩大了产品线,开始为LED市场设计、铸模和生产高质量的光学器件。

ELECTRONIC ASSEMBLY公司的发展小趣事

在竞争激烈的电子组装市场中,一家名为“精准电子组装”的公司凭借其精准的市场定位脱颖而出。公司深入研究行业趋势和客户需求,准确把握市场脉搏,专注于为高端客户提供定制化的电子组装服务。通过不断挖掘客户需求、提升服务水平,精准电子组装在高端市场上占据了一席之地,实现了快速发展。

ARCOTRONICS公司的发展小趣事

在电子行业的早期,ARCOTRONICS公司凭借其卓越的研发团队,成功开发出一种新型的高效能电子元件。这一技术突破不仅大幅提升了电子设备的性能,还降低了生产成本,使公司在市场上迅速获得了竞争优势。这一技术突破为ARCOTRONICS公司奠定了坚实的基石,为其后续发展打下了坚实的基础。

Amidon Associates Inc公司的发展小趣事

随着全球环保意识的不断提高,ARCOTRONICS公司积极响应绿色发展的号召,致力于推动电子行业的可持续发展。公司采用环保材料和节能技术,减少生产过程中的环境污染和能源消耗。同时,公司还积极参与社会公益活动,为社会的发展贡献自己的力量。这些举措不仅提升了公司的社会形象,也为其赢得了更多的商业机会。

这些故事虽然基于虚构,但它们反映了电子行业中公司发展的普遍规律和趋势。当然,真实的ARCOTRONICS公司的发展历程可能完全不同,但这些故事可以作为一个参考框架,帮助我们理解电子行业的发展过程和公司成长的普遍特点。

ADL [ADL Embedded Solutions Inc]公司的发展小趣事

随着技术实力的不断提升,ARCOTRONICS公司开始将目光投向国际市场。公司制定了一系列国际化战略,积极参与国际电子展会,与全球各地的合作伙伴建立紧密的合作关系。通过不断拓展市场,ARCOTRONICS公司的产品逐渐在国际上获得了广泛的认可,公司也因此成为了全球电子行业的重要参与者。

Coleman Cable Inc公司的发展小趣事

在发展过程中,Coleman Cable积极寻求与行业内外的合作伙伴建立稳固的合作关系。通过与知名电子制造商建立供应链合作关系,Coleman Cable的电缆产品得以广泛应用于各种电子设备中。同时,公司还与科研机构、高校等建立产学研合作关系,共同研发新技术、新产品,推动公司技术的不断创新和升级。

问答坊 | AI 解惑

学习嵌入式/射频技术的绝好教程

1. 本套装是台湾某教授给台湾知名电子企业员工培训讲课视频,授课的企业包括:明基电通、迅利电子、宇通全球等。 由于是给企业员工培训、且授课老师自己也有着多年的工程实践经验,所以视频讲课内容尽量摒弃繁琐的数学推导、抽象的概念,多从工程 ...…

查看全部问答>

基于Microchip PIC单片机的USB声卡

作者称声卡的采样频率是24KHz,采样精度12位,其声音品质虽然没有达到商业级水平,但对于耳机等应用已经足够了,比方说可以用来做一个USB电话之类的。 硬件原理图 USB声卡的核心单片机是PIC18F550,运行频率48MHz,通过SPI端口连接到12位D/A ...…

查看全部问答>

中国研制成功新一代“镁基特种电源”,号称全天候电池

中国科学家研制成功具有自主知识产权的新一代电源——镁基特种电源。这种电源不仅可替代锌锰电池、铅酸电池、镉镍电池等传统电源,还能在1500米深海、40000米高空等多种极端状态下正常工作,在工业和国防等领域有着广泛的用途。据新电源研制者、中 ...…

查看全部问答>

小弟想了解WAVECOM Q2406A,有用过的人请进。

WAVECOM Q2406 GSM模块,是怎么使用的?AT指令,但是,这个最基本的测试电路图是怎么样的? 希望有用过的人,能帮助我下。 本人喜欢这方面的,也正在做毕业设计,想了解下。lw96@163.com…

查看全部问答>

keil,如何看debug时候,的idata内容

有memory windows 在address 中输入d:0xf0,发现好像看到的是sfr,而不是高128字节的数据 (因为我已经执行了,所有数据区清零,可是在memory windows看到的依旧是FF???)…

查看全部问答>

单片机仿真的时候,正确运行是不是跟电脑的cpu利用率有关?

做了一个输如输出的仿真,有时候能够正确仿真,有时候达不到要求。反复试了几次,发现cpu利用接近100%的时候,仿真就不能正确运行了。 有没有人遇到过这种情况,是不是跟电脑的cpu的利用率有关,而不是仿真软件的问题?我用的keil跟protues联调。…

查看全部问答>

PXA270下摄像头(QCI接口)

各位英雄:        小弟想用PXA270+WINCE5.0平台,基于PXA270的QCI接口连接一个CMOS摄像头,可以采集视频并在LCD上预览。恳请英雄们指点些实现方案,比如摄像头型号、电路连接、驱动程序方面的?        ...…

查看全部问答>

有关UCOS2的一个怪问题

下面是个很简单的例程:问题是 Task1中的i 不为10时,Task2 能运行吗? static void Task2(void * pdata) {     uint8 err;         pdata = pdata; while (1)    {        ...…

查看全部问答>

eVC 用模拟器如何显示printf的内容

我安装的EVC4+sp4+EVC自带的sdk,好像说要控制台,怎么样才能拥有控制台阿?…

查看全部问答>

传感器套装是不是主要是各种温度传感器啊?

本帖最后由 dontium 于 2015-1-23 13:14 编辑 对这个传感器套装感兴趣。问一下哈。 …

查看全部问答>