首页 > 学院 > 开发设计 > 正文

51单片机的data,idata,xdata,pdata的详解

2019-11-08 01:58:39
字体:
来源:转载
供稿:网友

1、80C51单片机存贮空间的分配

空间名称地址范围说明
DATAD:00H~7FH片内RAM直接寻址区
BDATAD:20H~2FH片内RAM位寻址区
IDATAI:00H~FFH片内RAM间接寻址区
XDATAX:0000H~FFFFH64KB常规片外RAM数据区
HDATAX:0000H~FFFFFFH16MB扩展片外RAM数据区
CODEC:0000H~FFFFH64K常规片内外ROM代码区
HCONST(ECODE)C:0000H~FFFFFFH16MB扩展片外ROM常数区(Dallas390可用作代码区)

BANK0

     ~

BANK31

B0:0000H~FFFFH

        ~

B31:0000H~FFFFH

分组代码区,最大可扩展32X64KB ROM

(1)data: 固定指前面0x00-0x7f的128个RAM,可以用acc直接读写的,速度最快,生成的代码也最小。

(2)bit :是指0x20-0x2f的可位寻址区。

(3)idata:固定指前面0x00-0xff的256个RAM,其中前128和dATa的128完全相同,只是因为访问的方式不同。 idata是用类似C中的指针方式访问的。 汇编中的语句为:mox ACC,@Rx.(不重要的补充:c中idATa做指针式的访问效果 很好)  (4)xdata: 外部扩展RAM,一般指外部0x0000-0xffff空间,用DPTR访问。

(5)pdata: 外部扩展RAM的低256个字节,地址出现在A0-A7的上时读写,用movx ACC,@Rx读写。这个比较特殊,而且C51好象有对此BUG,建议少用。但也有他的优点,具体用法属于中级问题,这里不提。 

(6)bdata如何使用它呢?若程序需要8个或者更多的bit变量,如果你想一次性给8个变量赋值的话就不方便了,(举个例子说说它的方便之处,想更深入的了解请在应用中自己琢磨)又不可以定义bit数组,只有一个方法char bdata MODE;sbit MODE_7 = MODE^7;sbit MODE_6 = MODE^6;sbit MODE_5 = MODE^5;sbit MODE_4 = MODE^4;sbit MODE_3 = MODE^3;sbit MODE_2 = MODE^2;sbit MODE_1 = MODE^1;sbit MODE_0 = MODE^0;8个bit变量MODE_n 就定义好了。

2、指针类型和存储区的关系      对变量进行声明时可以指定变量的存储类型如:       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空间了又增加了指针类型的分辨值。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表