1、课程的基本要求课程的基本要求 通过本课程的学习,应该通过本课程的学习,应该 掌握掌握C51的程序设计语言;的程序设计语言;掌握掌握8051的中断、定时器的中断、定时器/定位器、定位器、串行通信等内部资源的串行通信等内部资源的C编程方法;编程方法;正确理解单片机的正确理解单片机的C语言模块化设计方法;语言模块化设计方法;了解了解8051外部扩展资源的外部扩展资源的C程序设计方法。程序设计方法。单片机的单片机的C语言和程序设计语言和程序设计6.2 C语言与语言与MCS-51单片机单片机6.3 C51运算符、表达式及其规则运算符、表达式及其规则6.4 C51数据与运算数据与运算6.5 C51函数函数
2、6.6 库函数简介库函数简介 6.7 8051内部资源的内部资源的C51编程编程 6.1 概述概述6.1 单片机的单片机的C语言和程序设计语言和程序设计对于对于8051及其兼容单片机,目前有四种语言支持:汇编语及其兼容单片机,目前有四种语言支持:汇编语言、言、BASIC语言、语言、PL/M语言和语言和C语言。语言。C语言是一种编译型程序设计语言,它兼顾了各种高级语言是一种编译型程序设计语言,它兼顾了各种高级语言的特点,并具备汇编语言的功能。语言的特点,并具备汇编语言的功能。与汇编语言相比,与汇编语言相比,C语言有很多的优点:语言有很多的优点:不要求了解单片机的指令系统,仅要求对不要求了解单片机
3、的指令系统,仅要求对8051的存的存储器结构有初步了解;储器结构有初步了解;寄存器分配,不同存储器的寻址及数据类型等细节寄存器分配,不同存储器的寻址及数据类型等细节可由编译器管理;可由编译器管理;程序有规范的结构;程序有规范的结构;函数库提供很多的标准程序。函数库提供很多的标准程序。单片机的单片机的C语言和标准语言和标准C语言的比较语言的比较vC51与标准的与标准的C语言定义的库函数不同语言定义的库函数不同.vC51中的数据类型和标准中的数据类型和标准C的数据类型也有一定的区别的数据类型也有一定的区别.vC51变量与标准变量与标准C中变量的存储模式不一样中变量的存储模式不一样.vC51与标准与
4、标准C的输入的输入/输出处理不一样输出处理不一样.vC51与标准与标准C语言在函数使用方面有一定的区别语言在函数使用方面有一定的区别.学习重点学习重点:学习学习C51程序设计,重点掌握标准程序设计,重点掌握标准C语言和语言和C51的区别的区别.主要内容主要内容:vC51的数据类型和存储类型、的数据类型和存储类型、v基本运算、构造数据类型、基本运算、构造数据类型、v函数以及程序设计中的其他一些问题等内容函数以及程序设计中的其他一些问题等内容.6.2 C语言与语言与MCS-51单片机单片机6.2.1 C语言编译器与程序开发过程语言编译器与程序开发过程6.2.2 C51程序结构程序结构全局变量说明全
5、局变量说明 /*可被本程序的各函数引用可被本程序的各函数引用*/函数函数1说明说明函数函数n说明说明主函数主函数main()局部变量说明局部变量说明 *只能在本函数内引用只能在本函数内引用*执行语句执行语句(包括函数调用语句包括函数调用语句)(形式参数表形式参数表)函数函数1(形式参数说明形式参数说明)局部变量说明局部变量说明 *只能在本函数内引用只能在本函数内引用*执行语句执行语句(包括调用其他函数语句包括调用其他函数语句)(形式参数表形式参数表)函数函数n(形式参数说明形式参数说明)局部变量说明局部变量说明 执行语句执行语句 例例6.1 程序如下:程序如下:#include#include
6、#define CON8279 XBYTE OX6EFF#define uchar unsigned charvoid INIT79();/*8279初始化初始化*/void main()uchar xdata*p;uchar code TAB =0 xC0,0 xF9,0 xA4,0 xB0,0 x99,0 x92,0 x82,0 xF8,0 x80,0 x90 /*0,1,2,3,4,5,6,7,8,9 */INIT79();P=&DAT8279;While(1)while(IE1=0);/*等待键输入等待键输入*/IE1=0;DAT8279=TAB*P;Void INIT79(void)
7、CON8279=0 xDC;CON8279=0 x10;注释部份/*/这部分内容不会被编译,也不被执行 编译预处理程序编译、执行前系统自动进行的特殊处理特点:以#开头 结束处无分号#define CON8279 XBYTE#define CON8279 XBYTE0 x6EFF 0 x6EFF#define#define 宏定义命令宏定义命令CON8279 CON8279 符号常量符号常量 0 x6EFF 0 x6EFF 宏体(可以是一个表达式,如宏体(可以是一个表达式,如3+43+4)v作用:用简单符号代表宏体部份内容作用:用简单符号代表宏体部份内容v意义:直观意义:直观/多次使用多次使用/
8、便于修改便于修改v注意:注意:#define#define 可出现在程序的任一位置(作可出现在程序的任一位置(作用范围:由此行到程序末尾)用范围:由此行到程序末尾)v宏定义不是宏定义不是CC语句,不必在行末加分号,否则会语句,不必在行末加分号,否则会连分号一起置换。连分号一起置换。v#include 标准方式标准方式只按标准方式只按标准方式(系统存放系统存放C库函数头文件所在目录库函数头文件所在目录)查找所要包含的文件查找所要包含的文件 对对CX51,CX51,默认只在默认只在C51includeC51include目录下查找目录下查找v#include “”先在源文件所在目录找指定头文件,先
9、在源文件所在目录找指定头文件,若无再按标准方式找(更保险)若无再按标准方式找(更保险)小小 结结CX51CX51语言程序的基本特点语言程序的基本特点CX51语言是一种函数式语言,其程序基本组成是函数语言是一种函数式语言,其程序基本组成是函数每个每个CX51程序必须有一个、也只能有一个主函数程序必须有一个、也只能有一个主函数main不管主函数在程序中的位置如何,程序执行总是从主函数不管主函数在程序中的位置如何,程序执行总是从主函数开始开始所有变量必须先定义(规定数据类型)后使用所有变量必须先定义(规定数据类型)后使用每个语句必须用分号每个语句必须用分号“;”结束(注意是结束(注意是“每个语句每个
10、语句”而不而不“每行语句每行语句”)编译预处理命令不是语句(行末不能用分号结束)编译预处理命令不是语句(行末不能用分号结束)Cx51语言本身没有输入语言本身没有输入/输出语句,其输入输出语句,其输入/输出功能须通输出功能须通过调用标准函数通过串行口实现过调用标准函数通过串行口实现使用系统提供的标准库函数或其他文件提供的现成函数时,使用系统提供的标准库函数或其他文件提供的现成函数时,必须使用必须使用“文件包含文件包含”。6.3 C51运算符、表达式及其规则运算符、表达式及其规则6.3.1 算术运算符及表达式算术运算符及表达式1.基本的算术运算符基本的算术运算符C51语言的算术运算符一共有语言的算
11、术运算符一共有5种:种:+加法运算符加法运算符 减法运算符减法运算符*乘法运算符乘法运算符/除法运算符除法运算符%模(取余数)运算符模(取余数)运算符例:14%4=0 x022.自增(自增(+),自减()运算符),自减()运算符(1)当)当+j(或(或j)时,是先将变量)时,是先将变量j的值加的值加1 (或减小(或减小1),再取变量值;),再取变量值;(2)当)当j+(或(或j)时,是先取变量值,)时,是先取变量值,再把变量的值加再把变量的值加1(或减(或减1)例如:例如:int i,j,k;i=4;j=+i;/*j 值为值为5,i 值也为值也为5*/i=5;k=i+;/*k值为值为5,i 值
12、为值为6*/3.算术表达式及优先级和结合性算术表达式及优先级和结合性 单目运算符优先级高于双目运算符,双目运算符优先级单目运算符优先级高于双目运算符,双目运算符优先级高于双目赋值运算符。高于双目赋值运算符。6.3.2 关系运算符、关系表达式关系运算符、关系表达式C51语言共有语言共有6种关系运算符:种关系运算符:(小于)(小于)(大于)(大于)=(大于等于)(大于等于)=(等于)(等于)!=(不等于)(不等于)6.3.3 逻辑运算符及表达式逻辑运算符及表达式C51提供三种以逻辑量为操作数的逻辑运算符:提供三种以逻辑量为操作数的逻辑运算符:!逻辑非逻辑非&逻辑与逻辑与|逻辑或逻辑或例如:若例如:
13、若a=3,b=4则则 !a=0 因为因为a=3为非为非0数,即为逻辑数,即为逻辑1;a|b=1 因为因为a、b为非为非0数,是逻辑数,是逻辑1;a&b=1因为因为a、b为非为非0数,是逻辑数,是逻辑1;!a&b=0 因为!因为!a优先于优先于&。6.3.4 位运算符及表达式位运算符及表达式C51语言提供语言提供6种位运算符,种位运算符,所有的位运算符都是针对整型操作数,而不能针对实型数据。所有的位运算符都是针对整型操作数,而不能针对实型数据。&按位与按位与 (例:(例:char a=3,b=6;则:则:a&b=2.)|按位或按位或 按位异或按位异或 按位取反按位取反 右移右移 左移左移635
14、赋值运算符赋值运算符赋值运算符赋值运算符 即是把运算符右侧操作数赋给左侧的操作数即是把运算符右侧操作数赋给左侧的操作数。即变量名即变量名=表达式表达式 当当“=”两侧类型不一致时,系统自动将右边表达式的值转两侧类型不一致时,系统自动将右边表达式的值转换成左侧变量的类型,再赋给该变量,具体规则如下:换成左侧变量的类型,再赋给该变量,具体规则如下:当整型变量当整型变量=实型数据时,实数的小数部分被舍去;实型数据时,实数的小数部分被舍去;当实型变量当实型变量=整型数据时,变量中的数值为浮点形式;整型数据时,变量中的数值为浮点形式;当短字节整型变量当短字节整型变量=长字节整型数据时,长字节整型数据时,
15、则长字节整型数据的低位数据赋给短字节整型变量则长字节整型数据的低位数据赋给短字节整型变量;当长字节整型变量当长字节整型变量=短字节整型数据时,短字节整型数据时,则短字节整型数据赋给长字节整型变量的低位数据,而则短字节整型数据赋给长字节整型变量的低位数据,而长字节整型变量的每一位高位数据被赋给短字节整型数据长字节整型变量的每一位高位数据被赋给短字节整型数据的符号值。的符号值。赋值语句赋值语句作用:使变量获得具体的运算值。作用:使变量获得具体的运算值。q语句形式语句形式 变量名变量名=表达式(常量、变量、函数、算式及其混合)表达式(常量、变量、函数、算式及其混合);lower=0;/*变量变量lo
16、werlower赋初值赋初值*/s=sin(x);/*求求sin(x)sin(x)*/注意:注意:函数函数sin()在头文件在头文件math.h中定义。中定义。所以程序开头处必须加上一行所谓所以程序开头处必须加上一行所谓“文件包含文件包含”:#include q变量赋初值亦可在数据类型定义时进行:变量赋初值亦可在数据类型定义时进行:int lower=0,x;把变量声明语句与赋值结合在一起的语句,术语上称为把变量声明语句与赋值结合在一起的语句,术语上称为 “初始化语句初始化语句”。2.复合赋值运算符复合赋值运算符 凡是有两个运算对象的运算符都可以与赋值运算符凡是有两个运算对象的运算符都可以与赋
17、值运算符“=”一起组成复合运算符。一起组成复合运算符。复合赋值运算符有以下复合赋值运算符有以下10种:种:+=,-=,*=,/=,%=,=,&=,|=,=。例如:例如:a+=b 等价于等价于 a=(a+b)a=4 等价于等价于 a=(a4)64 C51数据与运算数据与运算641 数据类型数据类型数据类型长度长度(bit)长度长度(byte)值域范围值域范围位型位型(bit)10,1字符型字符型(char)Unsigned char(char)Signed char88110255-128127整型整型(int)Unsigned intSigned int(int)161622065535-32
18、76832767长整型长整型(long)Unsigned longSigned long(long)32324404294967295-2147488364821474883647浮点型浮点型(float)Floatdouble326448约约10-381038约约10-30810308一般指针一般指针243存贮空间存贮空间065535 80C51单片机采用哈佛结构,单片机采用哈佛结构,RAM与与ROM分开,分开,SFR与片内与片内RAM统一编址。统一编址。KEIL CX51编译器将变量、常量定义成不同的存储类编译器将变量、常量定义成不同的存储类型型(data,bdata,idata,pdat
19、a,xdata,code)的方法,的方法,将它们定位在不同的存储区中。将它们定位在不同的存储区中。8051的变量的存储类型定义为:的变量的存储类型定义为:存储类别存储类别变量类型变量类型 存储类型存储类型 变量名变量名其中存储种类与存储类型为可选项。其中存储种类与存储类型为可选项。存储类别存储类别主要有四种:自动(主要有四种:自动(auto)(默认的存储种)(默认的存储种类)、外部(类)、外部(extern)、静态()、静态(static)和寄存器)和寄存器(register)。)。存储类型存储类型主要有:主要有:data,bdata,idata,pdata,xdata,code等。等。642
20、 变量及其数据类型变量及其数据类型1变量的说明变量的说明变量的格式如下:变量的格式如下:存储类说明存储类说明 类型说明符类型说明符修饰符修饰符标识符标识符=初值初值其中其中 部分可有可无。部分可有可无。(1)类型说明符)类型说明符 (char,int,long,)(2)标识符)标识符(3)变量初始化)变量初始化(4)存储类说明符)存储类说明符 aauto(自动存储类):堆栈(自动存储类):堆栈(默认存储类)默认存储类)bregister(寄存器存储类):(寄存器存储类):cextern(外部存储器类外部存储器类):dstatic(静态存储类):(静态存储类):(5)修饰符)修饰符 由于由于80
21、51存储空间的多样性,存储空间的多样性,C51提供了修饰存储空间提供了修饰存储空间类型的修饰符,类型的修饰符,用于指明定义的变量应分配在什么存储空间中。用于指明定义的变量应分配在什么存储空间中。C51存储空间类型的修饰符有存储空间类型的修饰符有 data,idata,pdata,xdata,code,bdata,无修饰符时,取决于编译时选用的存储方式无修饰符时,取决于编译时选用的存储方式存储类别存储类别 决定变量的决定变量的“寿命寿命”(何时(何时“生生”,何时,何时“灭灭”)一个完整的变量说明格式如下:一个完整的变量说明格式如下:存储类别存储类别 数据类型数据类型 存储类型存储类型 变量名变
22、量名如如 static int data x,y;static int data x,y;C51程序的存储类别有:程序的存储类别有:register型(寄存器型)型(寄存器型)存取速度快,一般只允许23个,且限于char型和int型,通常用于循环变量。auto型(自动变量型)型(自动变量型)优点同一内存区可被不同变量反复使用。以上两种变量均属于“动态存储型”,即调用函数时才为这些变量分配单元,函数调用结束其值自动消失。static型(静态变量型)型(静态变量型)程序执行开始至结束,始终占用该存储空间 extern型(外部变量型)型(外部变量型)同上,其值可供其他源文件使用以上两种均属于“静态存
23、储”性质,即从变量定义处开始,在整个程序执行期间其值都存在。从变量的存在时间来看,可分为静态存储变量和动态存从变量的存在时间来看,可分为静态存储变量和动态存储变量。储变量。v静态存储变量是指该变量在程序运行期间其存储空间不静态存储变量是指该变量在程序运行期间其存储空间不变,全局变量为静态存储变量;变,全局变量为静态存储变量;v动态存储变量是指该变量的存储空间不确定,在程序运动态存储变量是指该变量的存储空间不确定,在程序运行期间需要动态地为该变量分配存储空间,局部变量为行期间需要动态地为该变量分配存储空间,局部变量为动态变量。动态变量。变量的生存期 静态存储变量:与程序“共存亡”动态存储变量:与
24、函数“共存亡”寄存器变量:同动态变量未说明存储类别时,函数内定义的变量默认为auto型函数外定义的变量默认为extern型。2变量的数据类型变量的数据类型 对于对于Franklin C51编译器编译器,只有只有bit和和Unsigned char两两种数据类型可以直接支持机器指令,种数据类型可以直接支持机器指令,为了提高单片机的数据处理速度,在编制为了提高单片机的数据处理速度,在编制C51程序时一程序时一定要对变量和数据类型进行慎重的选择。定要对变量和数据类型进行慎重的选择。(1)位变量()位变量(bit)bit是是C51特有的数据类型,特有的数据类型,其值为其值为:1(ture)或)或0(f
25、alse)。)。bit类型可用的修饰符有类型可用的修饰符有bdata,data,idata,但最好是但最好是bdata修饰符修饰符例如:例如:bdata bit mark1 data bit mark2 idata bit mark3(2)字符变量()字符变量(char)字符变量的长度为一个字节,字符变量的长度为一个字节,标识符为标识符为char(-128127)或)或 unsigned char(0-255),(3)整型变量()整型变量(int)整型变量(整型变量(int)的长度为二个字节,)的长度为二个字节,标识符为标识符为int,unsigned int,。0 x78 0 x56 。整型
26、变量值整型变量值0 x5678(4)长整型变量()长整型变量(long int)长整型变量的长度为四个字节,长整型变量的长度为四个字节,标识符为标识符为unsigned long,long。(5)浮点型变量)浮点型变量(float)浮点型变量长度为四个字节,浮点型变量长度为四个字节,C51的浮点变量数据类型格式具有的浮点变量数据类型格式具有24位精度,尾数的位精度,尾数的高位始终为高位始终为1,位的分布为:位的分布为:1位符号位位符号位 8位指数位位指数位 23位尾数位位尾数位例如:浮点型变量值例如:浮点型变量值-12.5的十六进制表示为的十六进制表示为0 xC1480000地址地址 +00
27、x00+10 x00+20 x48+30 xC1 .。644 数据的存储数据的存储1存储类型与存储空间存储类型与存储空间存储类型存储类型 存储区存储区databdataidatapdataXdatacode直接寻址片内数据存储区,直接寻址片内数据存储区,128字节,字节,07FH;访;访问速度快,存放常用变量或临时性递变量。问速度快,存放常用变量或临时性递变量。可位寻址片内数据存储区,可位寻址片内数据存储区,16字节,字节,128位,允许位,允许位与字节混合访问。位与字节混合访问。间接寻址片内数据存储区,间接寻址片内数据存储区,128字节,字节,07FH。由由MOVX R0,MOVX R1 分
28、页访问片外数据分页访问片外数据存储区,存储区,256字节字节/页;高页;高8位地址保存在位地址保存在P2口中。口中。由由MOVX DPTR访问片外数据存储区(访问片外数据存储区(RAM),64K,00FFFFH;存放不常用变量、等待发送;存放不常用变量、等待发送或处理的数据。或处理的数据。由由MOVC A+DPTR访问程序存储区(访问程序存储区(ROM或或EPROM),),64K,00FFFFH;存放指令代码和;存放指令代码和固定信息固定信息片内数据存储区:片内数据存储区:data、bdata与与idatav当使用当使用data与与bdata存储类型定义时,存储类型定义时,CX51将它们定将它
29、们定位在片内位在片内RAM。它存取数据快,但资源有限。它存取数据快,但资源有限。v片内片内RAM存放临时性变量或使用频率较高的变量。存放临时性变量或使用频率较高的变量。片外数据存储区:片外数据存储区:pdata与与xdatavpdata能访问能访问1页(页(256字节)的外部字节)的外部RAM,主要用于,主要用于紧凑模式(紧凑模式(Compact Mode)。)。v当使用当使用xdata存储定义类型,其最大可寻址范围为存储定义类型,其最大可寻址范围为64K。程序存储区:程序存储区:codev当使用当使用code存储类型定义数据时,编译器会将其定义存储类型定义数据时,编译器会将其定义在代码空间(
30、在代码空间(ROM或或EPROM)。)。如:如:#define uchar unsigned char /*定义符号常量定义符号常量uchar*/uchar data a1;/*字符变量字符变量a1定位在定位在8051的片内数据存的片内数据存 储区中储区中*/bit bdata flag;/*位变量位变量flag定位在定位在8051的片内数据存储的片内数据存储 区中的可位寻址区区中的可位寻址区*/float idata x,y;/*浮点变量浮点变量x,y定位在定位在8051的片内数据的片内数据 存储区并只能通过间接寻址来访问存储区并只能通过间接寻址来访问*/uchar xdata s =3,4
31、,7,2,12,8;/*无符号字符数组无符号字符数组s定位在片外定位在片外RAM*/uchar code table 10=0 x3f,0 x06,0 x5b,0 x4f,0 x66,0 x6d,0 x7d,0 x07,0 x7f,0 x6f;/*无符号字符数组无符号字符数组table定位在片外定位在片外ROM*/2存储模式存储模式存储模式存储模式说明说明SMALLCOMPACTLARGE参数及局部变量放入可直接寻址的片内存储器参数及局部变量放入可直接寻址的片内存储器(最大最大128字节,默认存储类型是字节,默认存储类型是data),因此访,因此访问十分方便。另外所有对象,包括栈,都必须问十分
32、方便。另外所有对象,包括栈,都必须嵌入片内嵌入片内RAM。栈长很关键,因为实际栈长依。栈长很关键,因为实际栈长依赖于不同函数的嵌套层数赖于不同函数的嵌套层数参数及局部变量放入分页片外存储区参数及局部变量放入分页片外存储区(最大最大256字节,默认的存储类型字节,默认的存储类型pdata),通过寄存器,通过寄存器R0和和R1(R0,R1)间接寻址,栈空间位于间接寻址,栈空间位于8051系统内部数据存储区中系统内部数据存储区中参数及局部变量直接放入片外数据存储器参数及局部变量直接放入片外数据存储器(最大最大64K,默认存储类型为,默认存储类型为xdata),使用数据指针,使用数据指针DPTR进行寻
33、址。用此指针访问效率较低,这种进行寻址。用此指针访问效率较低,这种访问机制直接影响代码长度访问机制直接影响代码长度645 MCS-51结构的结构的C51定义定义1特殊功能寄存器特殊功能寄存器(SFR)的的C51定义定义sf r 特殊功能寄存器名特殊功能寄存器名“=”该特殊功能寄存器的地址常该特殊功能寄存器的地址常数数”;”例如:例如:sf r SCON=ox98;/*串口控制寄存器地址串口控制寄存器地址98H*sf r TMOD=ox89;*定时计数器控制寄存定时计数器控制寄存 器地址器地址89H*2.I0口的口的C51定义定义(1).片内片内IO口用关键字口用关键字sfr定义。定义。例如:例
34、如:sf r P1=0 x90;/*定义定义P1口,地址口,地址90H*(2).片外扩展片外扩展IO口的硬件译码地址,看作片外数据存储口的硬件译码地址,看作片外数据存储单元,用单元,用#define语句定义。语句定义。例如:例如:#include#define PORTA XBYTE0 xffc0;/*将将PORTA定义定义为外部为外部I/O口,地址为口,地址为0 xffc0,长度为,长度为8位位*3特殊位特殊位(sbit)的的C51定义定义(1)已定义的特殊寄存器名已定义的特殊寄存器名 基地址上特殊位的位置基地址上特殊位的位置(07)当特殊寄存器的地址为字节当特殊寄存器的地址为字节(8位位)
35、时,可使用这种方法。时,可使用这种方法。例如:例如:sfr PSW=0 xd0;/*定义定义PSW寄存器地址为寄存器地址为0 xD0*sbit OV=PSW 2;/*定义定义OV位为位为PSW.2地址为地址为0 xD2*sbit CY=PSW7;/*定义定义CY位为位为PSW.7地址为地址为0 xD7*(2)寄存器基地址寄存器基地址 基地址上特殊位的位置基地址上特殊位的位置(07)以以0 x800 xFF之间、并能被之间、并能被8整除的整常数作为基地址。整除的整常数作为基地址。例如;例如;sbit OV=0 xD02;/*OV位地址为位地址为0 xD2*sbit CY=0 xD07;/*CY位
36、地址为位地址为0 xD7*(3)0 x80到到0 xFF之间的位绝对地址之间的位绝对地址例如:例如:sbit OV=OxD2;sbit CY=OxD7;在主程序前只要加上在主程序前只要加上#include-即包含对上述特殊寄存器的定义即包含对上述特殊寄存器的定义4对存储器和外部扩展对存储器和外部扩展I/O的绝对地址访问。的绝对地址访问。利用库函数中的绝对地址访问的头文件利用库函数中的绝对地址访问的头文件absacch可可对不同区域的存储器和外部扩展对不同区域的存储器和外部扩展IO口进行访问。口进行访问。该头文件中的函数有:该头文件中的函数有:CBYTE地址地址(访问访问code区字符型区字符型
37、)DBYTE地址地址(访问访问data区字符型区字符型)PBYTE地址地址(访问访问pdata区或区或IO口字符型口字符型)XBYTE地址地址(访问访问xdata区或区或IO字符型字符型)例如:若有宏定义:例如:若有宏定义:#define DAC0832 XBYTE0 x7FFF那么程序中那么程序中DAC0832出现的地方,就是对地址为出现的地方,就是对地址为7FFFH的外部的外部RAM单元或单元或IO口进行访问。口进行访问。还有访问数据类型为还有访问数据类型为int型的型的4个函数:个函数:CWORD、DWORD、PWORD和和XWORD。它们的访问区域同上。例如赋值语句:它们的访问区域同上
38、。例如赋值语句:XWORD0=0 x9988;例如,将内部例如,将内部RAM 30H单元的内容送单元的内容送20H单元的程序如单元的程序如下。下。#include void main()DBYTE 0X20=DBYTE 0X30;例如:例如:CPU片外片外RAM清零清零 ORG 0000H LJMP MAIN ;跳转到主程序跳转到主程序 ORG 0030HMAIN:MOV DPTR,#0000H;送送RAM地址地址LOOP:MOV A,#00H;MOVX DPTR,A;往往RAM存存00HINCDPTR;地址加地址加1MOV A,DPL ;判断判断RAM地址是否已经到达尾地址地址是否已经到达尾
39、地址 CJNE A,#00H,LOOPMOV A,DPHCJNE A,#20H,LOOPWAIT:NOP;循环等待循环等待JMPWAITENDC程序:程序:#include#include#define uchar unsigned char#define uint unsigned intvoid main()uint i;for(i=0;i0 x2000;i+);XBYTEi=0;6.4.6 C51的指针的指针6.4.6.1 指针的基本概念指针的基本概念1.变量的地址变量的地址 变量包含变量名和变量的值两个含义,前者为数据的标变量包含变量名和变量的值两个含义,前者为数据的标识(内存地址)后
40、者为数据的内容。识(内存地址)后者为数据的内容。即为它们所占连续的内存单元的最低字节单元的地址。即为它们所占连续的内存单元的最低字节单元的地址。例如:例如:Long a=0 x12345678;单元地址单元地址 a的单元的单元2001 782002 562003 342004 12变量变量a的地址为的地址为2001H对于内存中变量的存取有两种方式对于内存中变量的存取有两种方式(1)直接存取直接存取例如:例如:int a=10 根据变量名与内存单元地址的对应关系,根据变量名与内存单元地址的对应关系,找到变量找到变量a在内存中的位置。在内存中的位置。(2)间接存取间接存取 1000h10变量变量a
41、1002h 2000h1000指针变量指针变量a_pointer例如要存取变量例如要存取变量a时,要以将变量时,要以将变量a的地址放入内存单元的地址放入内存单元(假设放在(假设放在2000、2001两个字节中两个字节中),然后从地址,然后从地址1000、1001的两字节内存单元中存取变量的值的两字节内存单元中存取变量的值10,在这里,存,在这里,存放在地址放在地址2000和和2001内存中的,实际就是指向变量内存中的,实际就是指向变量a的指的指针变量针变量a_pointer。2指针变量的概念指针变量的概念 变量的指针,简而言之即是变量的地址,对上面的变量变量的指针,简而言之即是变量的地址,对上
42、面的变量a,它的指针就是内存中存储地址它的指针就是内存中存储地址1000h。指针变量,是指专门用来存放另一个变量地址(指针)指针变量,是指专门用来存放另一个变量地址(指针)的变量,它的值是指针。的变量,它的值是指针。提到的地址提到的地址2000h,2001h两字节中存放的变量两字节中存放的变量a_pointer就是一个指针变量,它的值就是变量就是一个指针变量,它的值就是变量a的地址的地址1000h。(1)指针变量的定义)指针变量的定义 指针变量定义的一般形式为指针变量定义的一般形式为 存储类说明符存储类说明符 类型说明符类型说明符 修饰符修饰符 指针定位修饰符指针定位修饰符标识标识符符 =地址
43、初始值地址初始值 中的部分可有可无。中的部分可有可无。存储类说明符,类型说明符存储类说明符,类型说明符:与一般变量的说明相同。与一般变量的说明相同。修饰符是修饰符是:为指针指向的对象定位存储空间的说明。为指针指向的对象定位存储空间的说明。指针定位修饰符指针定位修饰符:是给指针本身定位所在存储空间,是给指针本身定位所在存储空间,一般不予以指定。一般不予以指定。例如:例如:int *a 类型说明符类型说明符 标识符标识符Unsigned char data *xdata xx /*外部外部RAM指针指向指针指向 内部内部RAM数据区数据区*/类型说明符类型说明符 修饰符修饰符 指针定位修饰符指针定
44、位修饰符(2)指针变量的使用)指针变量的使用1)&取地址运算符取地址运算符 当把某变量的地址赋给一个指针变量后,就是说该指当把某变量的地址赋给一个指针变量后,就是说该指针变量指向该变量针变量指向该变量例如:例如:int a,*pointer,b;pointer=&a;执行了执行了pointer=&a语句后,指针语句后,指针pointer指向变量指向变量a,即指,即指针变量针变量pointer对应的内存单元中装入变量对应的内存单元中装入变量a对应的内存单元对应的内存单元地址。地址。例如例如pointer=300;是非法的。;是非法的。2)*取指向运算符取指向运算符即取指针变量所指向的变量的值。即
45、取指针变量所指向的变量的值。例如:例如:b=*pointer;相当于相当于b=a&和和*都是单目运算符都是单目运算符,优先级相同优先级相同,且结合顺序是自右至且结合顺序是自右至左的左的.如如*pointer+等价于等价于*(pointer+)而不是而不是(*pointer)+。实际编程和运算中,变量地址和指针变量的地址是不实际编程和运算中,变量地址和指针变量的地址是不可见的,变量,指针变量和内存单元地址三者间的对应关可见的,变量,指针变量和内存单元地址三者间的对应关系是由编译器决定的,程序设计人员只是通过系是由编译器决定的,程序设计人员只是通过&和和*运运算符来使指针变量与变量建立起联系。算符
46、来使指针变量与变量建立起联系。6.6.6.4 指针与数组指针与数组1数组指针和指向数组的指针变量数组指针和指向数组的指针变量 一般把数组的起始地址放到一个指针变量中去,因此,一般把数组的起始地址放到一个指针变量中去,因此,我们把数组的起始地址称为数组指针我们把数组的起始地址称为数组指针。而把一个存放数组起始地址的变量称作指向数组的指而把一个存放数组起始地址的变量称作指向数组的指针变量。简称数组指针变量。针变量。简称数组指针变量。其定义格式如下:其定义格式如下:类型说明符(类型说明符(*标识符)标识符)或或类型说明符(类型说明符(*标识符)标识符)例如,例如,int a20;/*包含包含20个整
47、型元素的数组个整型元素的数组*/int*p;/*指向整型数据的指针指向整型数据的指针*/把指针变量指向数组,表示方法为:把指针变量指向数组,表示方法为:p=&a0 或或p=a此时此时p为数组指针变量。为数组指针变量。2指针和一维数组指针和一维数组(1)一维数组的地址一维数组的地址 一维数组在内存中的存放;从下标为一维数组在内存中的存放;从下标为 0 的元素开始,连续的元素开始,连续存放。下标为存放。下标为0的元素的地址即为整个数组的地址。的元素的地址即为整个数组的地址。例如:例如:int a 4 =0 x5678,0 x1234,0 x5678,0 x1234;单元地址单元地址 单元单元 20
48、0A78 200B56 200C34 200D12 200E78 200F56 201034 201112数组数组a的地址为的地址为a0的地址的地址 200A。(2)指针的使用指针的使用要用指针变量来处理一维数组只需将一维数组的地址赋给一要用指针变量来处理一维数组只需将一维数组的地址赋给一个指针变量即可。个指针变量即可。例如:例如:int*p,a4;pa;*数组数组a的地址赋给指针变量的地址赋给指针变量p*/即即p指向了数组指向了数组a,则,则*p=a 0。对指针变量,其算术运算的特殊性表现在:对指针变量,其算术运算的特殊性表现在:1)只能加减,不能乘除。只能加减,不能乘除。2)当某指针变量指
49、向一个数组时,对该指针变量加当某指针变量指向一个数组时,对该指针变量加l则不则不管这个数组是什么数据类型,这个指针变量都指向数组的管这个数组是什么数据类型,这个指针变量都指向数组的下一个元素下一个元素(只要没越界只要没越界)。如:做完。如:做完p+运算后,运算后,p就指向就指向数组数组a的下一个元素,即的下一个元素,即a 1。数组元素的引用可以采用两种方法:下标法和指针法。数组元素的引用可以采用两种方法:下标法和指针法。下标法:下标法:例如:例如:int a 10,*p;p a;数组的第数组的第n个元素可表示为;个元素可表示为;an或或pn 指针法:指针法:数组的第数组的第n个元素可表示为:个
50、元素可表示为:*(a+n)或或*(p+n)注意:数组名可看成是一个指针常量,其值不能改变。注意:数组名可看成是一个指针常量,其值不能改变。例例6.2 用选择法对数组进行排序用选择法对数组进行排序(从小到大从小到大)。方法思路方法思路 设数组长度为设数组长度为5,令,令i0(1).寻找寻找a i 及后面的元素中最小元素,及后面的元素中最小元素,a k;(2).若若k=i,转,转(4);(3).若若k!i,交换,交换ai与与ak的值;的值;(4).i+,若,若i4,转,转(1);否则结束。;否则结束。main()int a 5 =15,10,2,-78,5,i,k,j,temp;for(i0;i