1、keil C51 指针总结上课所提到变量就是一种在程序执行过程中其值能不断变化的量。要在程序中使用变量必须先用标识符作为变量名,并指出所用的数据类型和存储模式,这样编译系统才能为变量分配相应的存储空间。定义一个变量的格式如下:存储种类 数据类型 存储器类型 变量名表在定义格式中除了数据类型和变量名表是必要的,其它都是可选项。存储种类有四种:自动(auto),外部(extern),静态(static)和寄存器(register),缺省类型为自动(auto)。这些存储种类的具体含义和使用方法,将在第七课变量的存储中进一步进行学习。而这里的数据类型则是和我们在第四课中学习到的名种数据类型的定义是一样
2、的。说明了一个变量的数据类型后,还可选择说明该变量的存储器类型。存储器类型的说明就是指定该变量在单片机 c 语言硬件系统中所使用的存储区域,并在编译时准确的定位。表 61 中是 KEIL uVision2 所能认别的存储器类型。注意的是在 AT89c51 芯片中 RAM 只有低 128 位,位于 80H 到 FFH 的高 128 位则在 52 芯片中才有用,并和特殊寄存器地址重叠。特殊寄存器(SFR)的地址表请看附录二 AT89c51 特殊功能寄存器列表表 61 存储器类型 存储器类型 说 明 data 直接访问内部数据存储器(128 字节),访问速度最快 bdata 可位寻址内部数据存储器(
3、16 字节),允许位与字节混合访问 idata 间接访问内部数据存储器(256 字节),允许访问全部内部地址 pdata 分页访问外部数据存储器(256 字节),用 MOVX Ri 指令访问 xdata 外部数据存储器(64KB),用 MOVX DPTR 指令访问 code 程序存储器(64KB),用 MOVC A+DPTR 指令访问 如果省略存储器类型,系统则会按编译模式 SMALL,COMPACT 或 LARGE 所规定的默认存储器类型去指定变量的存储区域。无论什么存储模式都能声明变量在任何的 8051 存储区范围,然而把最常用的命令如循环计数器和队列索引放在内部数据区能显著的提高系统性能
4、。还有要指出的就是变量的存储种类与存储器类型是完全无关的。. 数据存储模式存储模式决定了没有明确指定存储类型的变量,函数参数等的缺省存储区域,共三种:1. 1. Small 模式所有缺省变量参数均装入内部 RAM,优点是访问速度快,缺点是空间有限,只适用于小程序。2. 2. Compact 模式所有缺省变量均位于外部 RAM 区的一页(256Bytes),具体哪一页可由 P2 口指定,在 STARTUP.A51 文件中说明,也可用 pdata 指定,优点是空间较 Small 为宽裕速度较 Small 慢,较 large 要快,是一种中间状态。3. 3. large 模式所有缺省变量可放在多达
5、64KB 的外部 RAM 区,优点是空间大,可存变量多,缺点是速度较慢。提示:存储模式在单片机 c 语言编译器选项中选择。之前提到简单提到 sfr,sfr16,sbit 定义变量的方法,下面我们再来仔细看看。sfr 和 sfr16 能直接对 51 单片机的特殊寄存器进行定义,定义方法如下:sfr 特殊功能寄存器名= 特殊功能寄存器地址常数;sfr16 特殊功能寄存器名= 特殊功能寄存器地址常数;我们能这样定义 AT89c51 的 P1 口sfr P1 = 0x90; /定义 P1 I/O 口,其地址 90Hsfr 关键定后面是一个要定义的名字,可任意选取,但要符合标识符的命名规则,名字最好有一
6、定的含义如 P1 口能用 P1 为名,这样程序会变的好读好多。等号后面必须是常数,不允许有带运算符的表达式,而且该常数必须在特殊功能寄存器的地址范围之内(80HFFH),具体可查看附录中的相关表。sfr 是定义 8位的特殊功能寄存器而 sfr16 则是用来定义 16 位特殊功能寄存器,如 8052 的 T2 定时器,能定义为:sfr16 T2 = 0xCC; /这里定义 8052 定时器 2,地址为 T2L=CCH,T2H=CDH用 sfr16 定义 16 位特殊功能寄存器时,等号后面是它的低位地址,高位地址一定要位于物理低位地址之上。注意的是不能用于定时器 0 和 1 的定义。sbit 可定
7、义可位寻址对象。如访问特殊功能寄存器中的某位。其实这样应用是经常要用的如要访问 P1口中的第 2 个引脚 P1.1。我们能照以下的方法去定义:(1)sbit 位变量名位地址sbit P1_1 = Ox91;这样是把位的绝对地址赋给位变量。同 sfr 一样 sbit 的位地址必须位于 80H-FFH 之间。(2)Sbit 位变量名特殊功能寄存器名位位置sft P1 = 0x90;sbit P1_1 = P1 1; /先定义一个特殊功能寄存器名再指定位变量名所在的位置当可寻址位位于特殊功能寄存器中时可采用这种方法(3)sbit 位变量名字节地址位位置sbit P1_1 = 0x90 1;这种方法其
8、实和 2 是一样的,只是把特殊功能寄存器的位址直接用常数表示。在单片机 c 语言存储器类型中供给有一个 bdata 的存储器类型,这个是指可位寻址的数据存储器,位于单片机的可位寻址区中,能将要求可位录址的数据定义为 bdata,如:unsigned char bdata ib; /在可位录址区定义 ucsigned char 类型的变量 ibint bdata ab2; /在可位寻址区定义数组 ab2,这些也称为可寻址位对象sbit ib7=ib7 /用关键字 sbit 定义位变量来独立访问可寻址位对象的其中一位sbit ab12=ab112;操作符“后面的位位置的最大值取决于指定的基址类型,
9、char0-7,int0-15,long0-31。下面我们用上一课的电路来实践一下这一课的知识。同样是做一下简单的跑马灯实验,项目名为 RunLED2。程序如下: sfr P1 = 0x90; /这里没有使用预定义文件,sbit P1_0 = P1 0; /而是自己定义特殊寄存器sbit P1_7 = 0x90 7; /之前我们使用的预定义文件其实就是这个作用sbit P1_1 = 0x91; /这里分别定义 P1 端口和 P10,P11,P17 引脚void main(void)unsigned int a;unsigned char b;dofor (a=0;a)一. 普通指针普通指针的定
10、义方式如下, char * ptr; 跟标准的定义方式一样。这种指针占三个字节.第一个字节是标识存储类型,是指针指向的变量的数据类型. 第二个字节是指针存储地址的高位字节.第三个字节是指针存储地址的低位字节.普通指针默认存储在 内部存储器 data,即片上 RAM,如果想指定指针的存储位置,可以在 * 后加上存储类型,如下面几种定义方式:char * data ptr; /与 char * ptr;等价,即默认的定义方式char * xdata ptr; /指针存储在片外 RAMchar * idata ptr; /指针存储在 idatachar * pdata ptr; /指针存储在 pda
11、ta由定义普通指针写的程序最终的代码较长,运行速度相对较慢,因为 keil 在编译的时候不知道这个指针将要指向的变量的数据类型,只有当程序执行的时候才能知道,所以编译器不能对这段代码进行优化,不过,这样做的优点的此指针可以指向存储在任何位置的变量.二.内存特殊指针内在特殊指针的定义方式为: char xdata * ptr;这个指针存储的时候占的字节数是不一定的,占一个字节的变量类型为:idata, data, pdata, bdata.占两个字节的变量类型为: code,xdata。下图是我在 keil 上测试的时候截的图: 注意:char xdata * ptr;这里定义的 ptr 所指向
12、的变量存储在 xdata 中,即外部变量,这样的话指针变量ptr 占两个字节,我们再定义一个外部变量。char xdata variable1;ptrvariable1;/这样是正确的。这段程序中,变量 varies 是存储在外部存储器中的,是最合适的.char data variable2;ptr = 变量 variable2 存储在片上存储器中.一个字节的指针即可以够用,不过这样写程序也不算错,我试过 keil 也能运行。像普通指针一样,定义内存特殊指针时也可以指定指针的存储位置.char xdata * data ptr;这个定义是说,定义了一个指向(存储在 xdata)变量的一个(存储
13、在 data)的指针.内在特殊指针产生的代码可以经过编译器优化,运行速度较快.因为指针指向变量的存储位置是知道的,所以编译器在编译的时候可以进行优化.这样程序通过最简洁的方式去寻址,但是代价是降低了程序的灵活性.三.指针类型转换编译器在适当的时候对指针的类型进行转换.如进行参数传递的时候.如下面这个外部函数声明 printf 中的形参 ptr 是一个变通指针,编译器为函数分配三个字节extern void printf(char * ptr);char data * ptr1 ;char xdata * ptr2 ;voia main(void)printf(ptr1); /这样在参数传递的时
14、候转换printf(ptr2); /未转换在第一个 printf()调用中,实参是指向 data,占两个字节.但是函数原型中形参是变通指针,占三个字节.这样,参数传递的过程中将 ptr1 扩展了成三个字节再传递.注意:为了防止在传递参数的时候造成类似的指针类型错误.在调用函数前,最好进行必要的外部函数声明(extern .)或引用相应的头文件(#include .)或者在函数调用填写参数的时候加上数据类型转换.这样就有两种的转换方式.1.形参为普通类型,实参为内存特殊类型:补充第一个字节为相应的数据类型代码.高位地址没有的补充第二字节为 02.实参为内存特殊类型,形参为普通类型:截取相应的地址
15、字节.四,由上面的说明我们可以看出,只要我们写程序的时候在*两面都加上类型的标识符就可以了。但是在使用的时候*两边都有类型标识,很容易记混。char xdata * data ptr;这是一个指向一个存储在 xdata 的数据类型为 char 的指针,但这个指针却存储在 data 中。我是这样记的,与 char 在一起的 xdata 标识都是描述指针指向的变量的。而跟指针在一起的标识是描述指针自己的。(文章原创,转帖请注明出处 http:/)补充,关于 C51 里的存储类型的说明存储的类型有:code, data, bdata, idata, pdata, xdata片内 ROM 部分:code: 8051 的只读存储器,程序代码的保存的地方片内 RAM 部分:data: 片内 RAM 的低 128B,直接寻址访问.idata: 片内所有 RAM,只能使用间接寻址访问;bdata: 片内 RAM 可位寻址空间,0x200x2F,可位寻址访问.片外 RAM 部分xdata: 片外 RAM 全部的 64K 空间,使用 DPTR16 位指针间接寻址.pdata: 片外 RAM 的 256B, 0x000xFF,使用 R0,R1 间接寻址,