资源描述
第四章第四章 单片机的单片机的C C语言编程语言编程-C51-C51 51 51系列单片机支持三种高级语言系列单片机支持三种高级语言:PL/M:PL/M、C C、BASICBASIC。BASIC BASIC语言适用于简单编程而对编程效率运行速度要求不高的场合,语言适用于简单编程而对编程效率运行速度要求不高的场合,80528052单片机内固化有解释单片机内固化有解释BASICBASIC语言。语言。PL/M PL/M是一种结构化的语言,很象是一种结构化的语言,很象PASCALPASCAL,PL/MPL/M编译器好象汇编器一样编译器好象汇编器一样产生紧凑的机器代码,可以说是高级汇编语言,但它不支持复杂的算术运产生紧凑的机器代码,可以说是高级汇编语言,但它不支持复杂的算术运算,无丰富库函数支持,学习算,无丰富库函数支持,学习PL/MPL/M无异于学习一种新的语言。无异于学习一种新的语言。C C语言是一种通用的程序设计语言,其代码率高,数据类型及运算符语言是一种通用的程序设计语言,其代码率高,数据类型及运算符丰富,并具有良好的程序结构,适用于各种应用的程序设计,是目前使用丰富,并具有良好的程序结构,适用于各种应用的程序设计,是目前使用最广的单片机编程语言,使用最广的单片机编程语言,使用C51C51编译器。编译器。由由C51C51产生的目标代码其运行速度高;所需存储空间小,符合产生的目标代码其运行速度高;所需存储空间小,符合C C语言的语言的ANSIANSI标准,生成的代码遵循标准,生成的代码遵循IntelIntel目标文件格式,而且可与目标文件格式,而且可与A51A51汇编语言或汇编语言或PL/M51PL/M51语言目标代码混和使用。语言目标代码混和使用。ANSL:American National Standard Institite 1 应用应用C51C51编程具有以下优点:编程具有以下优点:C51 C51管理内部寄存器和存贮器的分配,编程时,无需考虑不同存储管理内部寄存器和存贮器的分配,编程时,无需考虑不同存储器的寻址和数据类型等细节问题,但是先要根据单片机的存储结构来器的寻址和数据类型等细节问题,但是先要根据单片机的存储结构来恰当地定义;恰当地定义;程序由若干函数组成,具有良好的模块化结构;程序由若干函数组成,具有良好的模块化结构;有丰富的子程序库可直接引用,从而大大减少用户编程的工作量。有丰富的子程序库可直接引用,从而大大减少用户编程的工作量。C C语言和汇编语言可以交叉使用,汇编语言程序代码短、运行速度语言和汇编语言可以交叉使用,汇编语言程序代码短、运行速度快、但复杂运算编程耗时。用汇编语言编写与硬件有关的部分程序,快、但复杂运算编程耗时。用汇编语言编写与硬件有关的部分程序,用用C C语言编写与硬件无关的运算部分程序,充分发挥两种语言的长处,语言编写与硬件无关的运算部分程序,充分发挥两种语言的长处,提高开发效率。提高开发效率。24.1 C514.1 C51程序结构程序结构 同标准同标准C C一样,一样,C51C51的程序由一个个函数组成,其中必须有一个主的程序由一个个函数组成,其中必须有一个主函数函数main()main(),程序的执行从主函数,程序的执行从主函数main()main()开始,调用其他函数后开始,调用其他函数后返回主函数返回主函数main()main(),最后在主函数中结束整个程序,最后在主函数中结束整个程序,而不管函数的排而不管函数的排列顺序如何。列顺序如何。funn(funn(形式参数表形式参数表)/)/*函数函数n n*/形式参数说明形式参数说明 局部变量说明局部变量说明执行语句执行语句(包括调用其他函数语包括调用其他函数语句句););可见可见C C语言的函数以语言的函数以“”开始,开始,以以“”结束。结束。C C语言程序的组成结构:语言程序的组成结构:全局变量说明全局变量说明 /*可被各函数引用可被各函数引用*/main()/main()/*主函数主函数*/执行语句执行语句(包括函数调用语句包括函数调用语句););fun1(fun1(形式参数表形式参数表)/)/*函数函数1 1*/形式参数说明形式参数说明 局部变量说明局部变量说明 执行语句执行语句(包括调用其他函数语句包括调用其他函数语句););3C C语言的语句规则:语言的语句规则:1 1、每个变量必须先说明后引用。、每个变量必须先说明后引用。2 2、C C语言程序一行可以书写多条语句,但每个语句必须以语言程序一行可以书写多条语句,但每个语句必须以“;”结尾,结尾,一条语句也可以多行书写。一条语句也可以多行书写。3 3、C C 语言的注释用语言的注释用/*/表示。表示。4 4、“”花括号必须成对,位置随意,多个花括号可同行书写,也可逐花括号必须成对,位置随意,多个花括号可同行书写,也可逐行书写,为层次分明,增加可读性,同一层的行书写,为层次分明,增加可读性,同一层的“”花括号对齐,采用逐花括号对齐,采用逐层缩进方式书写。层缩进方式书写。44.2 C514.2 C51的数据类型的数据类型C51C51的数据有常量和变量之分。的数据有常量和变量之分。u 常量:在程序运行中其值不变的量。常量:在程序运行中其值不变的量。数值型常量:可以为十进制数、数值型常量:可以为十进制数、十六进制数十六进制数(用用0 x0 x表示表示)和字符(用和字符(用 引号括起)。引号括起)。符号型常量:用符号表示常量,此符号需用宏定义指令符号型常量:用符号表示常量,此符号需用宏定义指令(#define)(#define)对其进对其进行定义行定义(相当于汇编的相当于汇编的“EQUEQU”伪指令伪指令)。如:如:#define PI 3.1415#define PI 3.1415那么程序中只要出现那么程序中只要出现PIPI的地方,编译程序的地方,编译程序都译为都译为3.14153.1415。u 变量:在程序运行中其值可以改变的量。变量:在程序运行中其值可以改变的量。定义一个变量,编译系统就会自动为它安排一个存贮区,具体的定义一个变量,编译系统就会自动为它安排一个存贮区,具体的地址值用户不必在意。但在使用前一定要将它的数据类型和存储类型地址值用户不必在意。但在使用前一定要将它的数据类型和存储类型定义好。一个变量由变量名和变量值构成定义好。一个变量由变量名和变量值构成.变量名:存贮单元地址的符号表示。变量名:存贮单元地址的符号表示。变量的值:变量所在地址单元存放的内容。变量的值:变量所在地址单元存放的内容。5数据类型:决定数据的符号和长度。数据类型:决定数据的符号和长度。无论哪种数据都是存放在存贮单元中的,每一个数据究竟要占用几无论哪种数据都是存放在存贮单元中的,每一个数据究竟要占用几个单元,都要提供给编译系统,正如汇编语言中存放数据的单元要用个单元,都要提供给编译系统,正如汇编语言中存放数据的单元要用DBDB、DWDW、DDDD伪指令进行定义一样。伪指令进行定义一样。表表4.1 4.1 C51C51编译器支持数据类型(编译器支持数据类型(1 1)数数 据据 类类 型型长长 度度值值 域域位位 型型bit1Bit0或或1字符型字符型signed char1Byte-128+127unsigned char1Byte0255整整 形形signed int2Byte-32768+32767unsigned int2Byte065535signed long4Byte-2147483648+2147483647unsigned long4Byte042949672956数数 据据 类类 型型长长 度度值值 域域实型实型float4Byte1.176E-383.40E+38指针型指针型data/idata/pdata1Byte 1 1字节地址字节地址code/xdata2Byte2 2字节地址字节地址通用指针通用指针3Byte其中其中1 1字节为储存器类型编码,字节为储存器类型编码,2,32,3字节为地址偏移量字节为地址偏移量访问访问SFRSFR的数据类的数据类型型sbit1Bit0 或或 1sfr1Byte0255sfr162Byte065535表表4.1 4.1 C51C51编译器支持数据类型(编译器支持数据类型(2 2)7 字符型字符型(char)(char)、整型、整型(int)(int)和长整型和长整型(long)(long)均有符号型均有符号型(signed)(signed)和无和无符号型符号型(unsigned)(unsigned)两种,如果不是必须,尽可能选择两种,如果不是必须,尽可能选择unsignedunsigned型,这型,这将会使编译器省却符号位的检测,使生成的程序代码比将会使编译器省却符号位的检测,使生成的程序代码比signedsigned类型短类型短得多。得多。程序编译时,程序编译时,C51C51编译器会自动进行类型转换,例如将一个位变量赋编译器会自动进行类型转换,例如将一个位变量赋值给一个整型变量时,位型值自动转换为整型值;当运算符两边为不值给一个整型变量时,位型值自动转换为整型值;当运算符两边为不同类型的数据时,编译器先将低级的数据类型转换为较高级的数据类同类型的数据时,编译器先将低级的数据类型转换为较高级的数据类型,运算后的结果为高级数据类型。型,运算后的结果为高级数据类型。5151单片机内部数据存贮器的可寻址位单片机内部数据存贮器的可寻址位(20H(20H2FH)2FH)定义为定义为bitbit型,而特型,而特殊功能寄存器的可寻址位殊功能寄存器的可寻址位(即地址为即地址为X0HX0H和和X8HX8H的的SFRSFR的各位的各位)只能定义只能定义为为sbitsbit类型。类型。84.3 4.3 数据的存贮类型和存贮模式数据的存贮类型和存贮模式一、数据的存贮类型一、数据的存贮类型 C51C51是面向是面向8XX518XX51系列单片机及硬件控制系统的开发语言,由单片机系列单片机及硬件控制系统的开发语言,由单片机的存储结构决定,在编程时一定要指明所用的变量定位在哪一个存贮区的存储结构决定,在编程时一定要指明所用的变量定位在哪一个存贮区中,否则编译器无法工作。因此在定义变量类型(符号和大小)时,还中,否则编译器无法工作。因此在定义变量类型(符号和大小)时,还必须定义它的存放地,也就是存贮类型,有以下几种存贮类型:必须定义它的存放地,也就是存贮类型,有以下几种存贮类型:存储器类型存储器类型 描描 述述 data直接寻址的内部数据存储区直接寻址的内部数据存储区,访问变量速度最快访问变量速度最快(128 Byte)bdata可位寻址的内部数据存储区可位寻址的内部数据存储区,允许位与字节混合访问允许位与字节混合访问(16 Byte)idata间接寻址的内部数据存储区间接寻址的内部数据存储区,可访问全部内部地址空间可访问全部内部地址空间(256 Byte)pdata分页分页(256Byte)的外部数据存储区的外部数据存储区,由操作码由操作码 MOVX Ri 访问访问xdata外部数据存储区外部数据存储区(64KB),由操作码由操作码 MOVX DPTR 访问访问code程序存储区程序存储区(64KB),由操作码由操作码 MOVC A+DPTR 访问访问bit可位寻址区域中的位(可位寻址区域中的位(16 byte中的中的128个位)个位)sbitSFR中的可位寻址的位中的可位寻址的位9 访问内部数据存贮器访问内部数据存贮器(idata)(idata)比访问外部数据存贮器比访问外部数据存贮器(xdata)(xdata)相对相对要快一些,因此,可将经常使用的变量置于内部数据存贮器中,而将要快一些,因此,可将经常使用的变量置于内部数据存贮器中,而将较大及很少使用的数据单元置于外部数据存贮器中。较大及很少使用的数据单元置于外部数据存贮器中。例如:例如:char data x;/char data x;/*(等价于等价于data char x)data char x)定义变量定义变量 x x 为为8 8位,处于内部位,处于内部RAMRAM区区*/如果用户不对变量的存贮类型定义,则编译器承认默认存贮类如果用户不对变量的存贮类型定义,则编译器承认默认存贮类型,默认的存贮类型由编译控制命令的存贮器的模式来决定。型,默认的存贮类型由编译控制命令的存贮器的模式来决定。104.3.2 4.3.2 存贮器模式存贮器模式 采用定义变量、参数传递区的存贮器模式的方法,也可以决定变量采用定义变量、参数传递区的存贮器模式的方法,也可以决定变量和参数传递区存贮器类型,这时就不再需要对变量和参数传递区的存和参数传递区存贮器类型,这时就不再需要对变量和参数传递区的存贮器进行类型说明。贮器进行类型说明。存贮器模式决定了变量的默认存贮器类型、参数传递区和无明确存存贮器模式决定了变量的默认存贮器类型、参数传递区和无明确存贮区类型的说明。有三种存贮器模式:贮区类型的说明。有三种存贮器模式:SMALLSMALL、LARGE LARGE 和和 COMPACTCOMPACT。存储模式存储模式说说 明明SMALLSMALL默认的存储类型是默认的存储类型是datadata,参数及局部变量放入可直接寻址,参数及局部变量放入可直接寻址片内片内RAMRAM的用户区中的用户区中(最大最大128128字节字节)。堆栈只能放在此区域。堆栈只能放在此区域。堆栈的大小决定了函数嵌套调用的层数。由于此地方较小,堆栈的大小决定了函数嵌套调用的层数。由于此地方较小,决定了单片机的嵌套深度十分有限。决定了单片机的嵌套深度十分有限。COMPACTCOMPACT默认的存储类型是默认的存储类型是pdatapdata,参数及局部变量放入分页的外,参数及局部变量放入分页的外部数据存储区,通过部数据存储区,通过R0R0或或R1R1间接访问。间接访问。LARGELARGE默认的存储类型是默认的存储类型是xdataxdata,参数及局部变量直接放入片外,参数及局部变量直接放入片外数据存储区,使用数据指针数据存储区,使用数据指针DPTRDPTR来进行寻址。用此数据指来进行寻址。用此数据指针进行访问效率较低。针进行访问效率较低。11例如:设例如:设C C语言源程序为语言源程序为PROR.CPROR.C,若使程序中的变量类型和参数传递区限,若使程序中的变量类型和参数传递区限定在外部数据存贮区,有两种方法:定在外部数据存贮区,有两种方法:方法方法1 1:在程序的第一句加预处理命令:在程序的第一句加预处理命令:#pragma compact#pragma compact 方法方法2 2:用:用C51C51对对PROR.CPROR.C进行编译时,使用编译控制命令:进行编译时,使用编译控制命令:C51 PROR.C COMPACTC51 PROR.C COMPACT 4.3.3 4.3.3 变量说明举例变量说明举例 data char vardata char var;/*字符变量字符变量varvar定位在片内定位在片内RAMRAM区区*/char code MSGchar code MSG=“ENTER PARAMETER:ENTER PARAMETER:”;/*字符数组定位在程序存贮区字符数组定位在程序存贮区*/unsigned long xdata arrayunsigned long xdata array100100;/*无符号长型数组定位在片外无符号长型数组定位在片外RAMRAM 区,每元素占区,每元素占4bytes 4bytes*/float idata x,y,zfloat idata x,y,z;/*实型变量实型变量x,y,zx,y,z,定位在片内用间址访问的内部,定位在片内用间址访问的内部 RAMRAM区区 */bit lockbit lock;/*位变量位变量LockLock定位在片内定位在片内RAMRAM可位寻址区可位寻址区 */unsigned int pdata dimensionunsigned int pdata dimension;/*无符号整型变量无符号整型变量 dimensiondimension定位在定位在 分页的外部分页的外部RAMRAM区区 */12unsigned char xdata vector1044unsigned char xdata vector1044;/*无符号字符型三维数组,无符号字符型三维数组,定位在片外定位在片外RAMRAM区区*/sfr P0=0 x80;sfr P0=0 x80;/*定义定义P0P0口,地址为口,地址为80H80H*/char bdata flagschar bdata flags;/*字符变量字符变量flagsflags定位在可位寻址内部定位在可位寻址内部RAMRAM区区*/sbit flagsbit flags.s.0=flags00=flags0;/*定义定义SFRSFR中可位寻址的位中可位寻址的位flagflags s0 0为为flags.0 flags.0*/char data var1char data var1;bit bdata flagsbit bdata flags;float idata x,y,zfloat idata x,y,z;unsigned int pdata var2unsigned int pdata var2;unsigned char vector34unsigned char vector34;/*没有说明存储类型没有说明存储类型*/如果在变量说明时略去存贮器类型标志符,编译器会自动选择默认如果在变量说明时略去存贮器类型标志符,编译器会自动选择默认的存贮器类型。默认的存贮器类型进一步由控制指令的存贮器类型。默认的存贮器类型进一步由控制指令SMALLSMALL、COMPACTCOMPACT和和LARGELARGE限制。限制。例:如果声明例:如果声明char varchar var,则默认的存贮器模式为,则默认的存贮器模式为SMALLSMALL,varvar放在放在datadata存贮区;如果使用存贮区;如果使用COMPACTCOMPACT模式,模式,varvar放入放入p pdatadata存贮区存贮区 ;使用;使用LARGELARGE模式,模式,varvar被放入外部存贮区被放入外部存贮区(xdata(xdata存贮区存贮区)。134.4 4.4 指针指针4.4.1 4.4.1 指针与指针变量指针与指针变量 指针就是存储单元地址指针就是存储单元地址;存储这个地址的变量称为指针变量。存储这个地址的变量称为指针变量。(1 1)指针变量)指针变量:在汇编语言程序中,要取存贮单元在汇编语言程序中,要取存贮单元m m的内容可用直接寻址方式,也的内容可用直接寻址方式,也可用寄存器间接寻址方式可用寄存器间接寻址方式,如果用如果用R1R1寄存器指示寄存器指示m m的地址,用的地址,用R1R1就是就是取取m m单元的内容。相对应的在单元的内容。相对应的在C C语言中可用变量名表示语言中可用变量名表示,取变量的值取变量的值(相当于直接寻址相当于直接寻址),也可用另一个变量,也可用另一个变量(如如P)P)存放存放m m的地址,的地址,P P就相当就相当于于R1R1寄存器,用寄存器,用*P P取得取得m m单元的内容单元的内容(相当于汇编的间接寻址方式相当于汇编的间接寻址方式)这这里里P P即为指针型变量。即为指针型变量。14下面表格表示两种语言将下面表格表示两种语言将m m单元的内容送单元的内容送n n单元的对照语句:单元的对照语句:直接寻址直接寻址 间接寻址间接寻址汇编语言汇编语言 C C 语言语言 汇编语言汇编语言C C 语言语言MOV MOV n,mn,m 传送语句传送语句 n=mn=m;赋值语句赋值语句MOV R1,#m;MOV R1,#m;m m的地址送的地址送R1R1MOV n,R1;MOV n,R1;m m的内容送的内容送n n P=&mP=&m;/*m m的地址送的地址送P P*/n=n=*P P;/*m m的内容送的内容送n n*/注:注:汇编语言程序中对符号地址汇编语言程序中对符号地址n n和和m m需用需用EQUEQU伪指令进行地址定义。伪指令进行地址定义。C C语言应对变量语言应对变量n n、m m和指针变量和指针变量P P进行类型定义。进行类型定义。表中表中&为取地址运算符,为取地址运算符,*为取内容运算符。为取内容运算符。15(2)(2)指针型变量的类型指针型变量的类型 由于由于C51C51是用于是用于5151单片机的,单片机的,5151单片机具有不同的存贮空间和不同的单片机具有不同的存贮空间和不同的地址范围,即使对于同一外部数据存贮器,又有用地址范围,即使对于同一外部数据存贮器,又有用RiRi分页寻址分页寻址(Ri(Ri为八为八位位)和用和用DPTRDPTR寻址寻址(DPTR(DPTR为十六位为十六位)两种寻址方式。两种寻址方式。指针是指示变量的地址的,因此,在指针类型的定义中要说明被指的指针是指示变量的地址的,因此,在指针类型的定义中要说明被指的变量的数据类型和存贮类型。同时指针变量本身也是一个变量,即指针变量的数据类型和存贮类型。同时指针变量本身也是一个变量,即指针变量本身有它的存贮类型和数据长度,其数据长度是由被指的变量的存变量本身有它的存贮类型和数据长度,其数据长度是由被指的变量的存贮类型而定的。贮类型而定的。指针变量所指的存储类型:指针变量所指的存储类型:data data 表示指针指向内部表示指针指向内部128B RAM128B RAM;idata idata 表示指针指向内部表示指针指向内部 256B 256B RAMRAM;pdata pdata 表示指针指向表示指针指向RiRi间址的外部间址的外部RAMRAM;以上均为八位地址指示,所以以上均为八位地址指示,所以指针长度为指针长度为1 Byte1 Byte。code code 表示指针指向程序存贮器。表示指针指向程序存贮器。xdata xdata 表示指针指向外部数据存贮器。表示指针指向外部数据存贮器。这些均为十六位地址指示,所以指这些均为十六位地址指示,所以指针长度为针长度为2Byte.2Byte.指针变量的数据类型同样有指针变量的数据类型同样有charchar、intint、longlong等,表示指针指向的数据的等,表示指针指向的数据的长度是占一个单元、两个单元还是长度是占一个单元、两个单元还是4 4个个单元。单元。16(3)(3)指针变量说明举例指针变量说明举例指针变量说明有两种格式:指针变量说明有两种格式:(其中(其中 为可选项为可选项 )指针变量存贮类型指针变量存贮类型 被指数据类型被指数据类型 被指数据存贮类型被指数据存贮类型 *指针变量名;指针变量名;例如:例如:被指向的存贮被指向的存贮器的数据类型器的数据类型为长型为长型pxpx指向程指向程序存贮器序存贮器longxdatacode*px;pxpx自身在外自身在外部数据存贮部数据存贮器中器中pxpx为指针为指针型变量型变量 被指数据类型被指数据类型 被指存贮类型被指存贮类型 *指针变量存贮类型指针变量存贮类型 指针变量指针变量 例如:例如:/*和上面定义等同和上面定义等同*/long code *xdata px;17例如:例如:char xdata*data pd;/*指针变量指针变量pdpd指向字符型指向字符型xdataxdata区,自区,自 身在身在datadata区,长度区,长度2 2字节字节 */long xdata*px;/*指针变量指针变量pxpx指向指向longlong型型xdataxdata区区(被被 指的数据在指的数据在 xdataxdata区,每个数据占四区,每个数据占四 个单元,指针自身在默认存贮器个单元,指针自身在默认存贮器(如未如未 指定编译模式则在指定编译模式则在datadata区区),指针长度,指针长度 为为2 2个字节个字节 */data char xdata*pd;/*与第一例等效与第一例等效 */说明:说明:“*”号不可少,它表示变量为指针变量。号不可少,它表示变量为指针变量。指针变量说明格式中的指针变量说明格式中的 为可选项为可选项 ,如,如 被指存贮类型被指存贮类型 缺省,缺省,则指针定义为通用型,如则指针定义为通用型,如 指针变量存贮类型指针变量存贮类型 缺省、指针变量则缺省、指针变量则存放在默认存贮区或者在存放在默认存贮区或者在datadata区。区。18 如果指针的存储类型缺省,指针定义为通用型指针,表示指针可如果指针的存储类型缺省,指针定义为通用型指针,表示指针可指向任何存贮空间,此时指针长度为指向任何存贮空间,此时指针长度为3 3字节:字节:第一字节第一字节第二字节第二字节第三字节第三字节存贮类型编码存贮类型编码所指地址的高八位所指地址的高八位所指地址的低八位所指地址的低八位通用型指针的存贮类型编码如下:通用型指针的存贮类型编码如下:存贮器类型存贮器类型idataxdatapdatadatacode编编 码码(v4.0)(v4.0)1 12 23 34 45 5编编 码码(v5.0)(v5.0)0 00 01 1-2-2-1-1 表中表中v4.0v4.0、v5.0v5.0表示表示 C51C51的版本。的版本。例如指针变量例如指针变量pxpx值为值为0 x021203(v4.00 x021203(v4.0版版)或为或为0 x001203(v5.00 x001203(v5.0版版)即指针指向即指针指向xdata xdata 区的区的1203H1203H地址单元。地址单元。如:如:char*pd;/*pd pd 定义为通用型指针定义为通用型指针*/例如,以例如,以xdataxdata类型的类型的0 x12340 x1234地址为指针可以表示如下:地址为指针可以表示如下:地址地址+0+0+1+1+2+2内容内容0 x020 x020 x120 x120 x340 x34194.4.4 4.4.4 指向数组的指针变量指向数组的指针变量如果用一个变量存放一个数组的地址,这个变量就称为指向数组的如果用一个变量存放一个数组的地址,这个变量就称为指向数组的指针变量。指针变量。数组的起始地址称为数组指针,一个数组数组的起始地址称为数组指针,一个数组a a 的起始地址用的起始地址用a a表示。表示。1 1)指向数组的指针变量的定义和赋值:)指向数组的指针变量的定义和赋值:设定义了一个数组设定义了一个数组a5a5和一个指针变量和一个指针变量ap:ap:char data a5;char data a5;char data char data*ap;ap;仅此两句并不能说明变量仅此两句并不能说明变量apap是指向数组的,还必须将数组的起是指向数组的,还必须将数组的起始地址赋给该变量:始地址赋给该变量:ap=a;/ap=a;/*数组数组a a 的起始地址赋给指针变量的起始地址赋给指针变量apap*/或或 ap=&a0;/ap=&a0;/*意义同上,意义同上,&是取地址运算符是取地址运算符*/也可以使定义和赋值在一条语句完成:也可以使定义和赋值在一条语句完成:char data char data*apapa a;或或 char data char data*ap=&a0;ap=&a0;202 2)利用指向数组的指针变量引用数组元素:利用指向数组的指针变量引用数组元素:指向数组的指针变量引用数组元素有两种方法:指向数组的指针变量引用数组元素有两种方法:*(ap+i)(ap+i)或或 ap(i)ap(i);它们等同于它们等同于*(a+i)(a+i)或或a(i)a(i)。例:例:main()main()char a5=11,22,33,44,55;char a5=11,22,33,44,55;char b,c,d;char b,c,d;char char *ap;ap;ap=a;/ap=a;/*ap ap等于数组等于数组a5a5的起始地址的起始地址 */b=a+2;/b=a+2;/*b b等于数组元素等于数组元素a2a2的地址的地址 */c=ap+3;/c=ap+3;/*c c等于数组元素等于数组元素a3a3的地址的地址 */d=d=*(ap+3);/(ap+3);/*d d等于数组元素等于数组元素a3a3的值,即的值,即d=44 d=44,等同于,等同于d=a(3)d=a(3)*/ap11ap+122ap+233ap+344ap+45521 当用常数作指针时,必须注意正确定义存储器类型和偏移量。当用常数作指针时,必须注意正确定义存储器类型和偏移量。例如,将常数值例如,将常数值0 x410 x41写入地址为写入地址为0 x80000 x8000的外部数据存储器。的外部数据存储器。#define XBYTE(char#define XBYTE(char*)0 x20000)0 x20000)XBYTE0 x8000=0 x41 XBYTE0 x8000=0 x41;其中,其中,XBYTEXBYTE被定义为被定义为(char(char*)0 x20000)0 x20000,0 x200000 x20000为一般指针,其存为一般指针,其存储类型为储类型为2 2,偏移量为,偏移量为0000H0000H,这样,这样XBYTEXBYTE成为指向成为指向xdataxdata零地址的指针。而零地址的指针。而XBYTE8000XBYTE8000则是外部数据存储器的则是外部数据存储器的0 x80000 x8000绝对地址。绝对地址。224.5 C514.5 C51对对SFRSFR、可寻址位、存储器和、可寻址位、存储器和I/OI/O口的定义口的定义4.5.1 4.5.1 特殊功能寄存器特殊功能寄存器SFRSFR定义定义 C51 C51对特殊功能寄存器对特殊功能寄存器SFRSFR有两种定义方法有两种定义方法:使用特定关键字使用特定关键字 sfrsfr自主形式的定义方式自主形式的定义方式:sfr sfr 寄存器名寄存器名=寄存器地址寄存器地址;/;/*其中寄存器名必须大写其中寄存器名必须大写 */如如 sfr SCON=0 x98sfr SCON=0 x98;/*串行通信控制寄存器地址串行通信控制寄存器地址98H 98H*/sfr TMOD=0 x89 sfr TMOD=0 x89;/*定时器模式控制寄存器地址定时器模式控制寄存器地址89H 89H*/sfr ACC=0 xe0 sfr ACC=0 xe0;/*A A累加器地址累加器地址E0H E0H*/sfr P1=0 x90 sfr P1=0 x90;/*P1P1端口地址端口地址90H90H*/定义了以后,程序中就可以直接引用寄存器名。定义了以后,程序中就可以直接引用寄存器名。使用头文件使用头文件 C51 C51建有头文件建有头文件 reg51.hreg51.h、reg52.hreg52.h,在该头文件中对,在该头文件中对5151或或5252系列单片系列单片机所有的特殊功能寄存器的进行了机所有的特殊功能寄存器的进行了sfrsfr定义,对特殊功能寄存器中有位名定义,对特殊功能寄存器中有位名称的可寻址位进行了称的可寻址位进行了sbitsbit定义,因此,只要用包含语句定义,因此,只要用包含语句#include#include 就可以直接引用特殊功能寄存器名,或直接引用位名称。就可以直接引用特殊功能寄存器名,或直接引用位名称。要特别注意:在引用时特殊功能寄存器或者位寄存器名或者位名称必要特别注意:在引用时特殊功能寄存器或者位寄存器名或者位名称必须须大写大写。234.5.2 4.5.2 对位变量的定义对位变量的定义 C51C51对位变量的定义方法有三种:对位变量的定义方法有三种:将变量用将变量用bitbit类型的定义符定义为类型的定义符定义为bitbit类型:类型:如如 bit mnbit mn;mnmn为位变量,其值只能是为位变量,其值只能是“0 0”或或“1 1”,其位地址,其位地址C51C51自行自行安排在可位寻址区的安排在可位寻址区的bdatabdata区。区。采用字节寻址位运算符的方法:采用字节寻址位运算符的方法:如如 bdata int ibasebdata int ibase;/*ibase ibase定义为整型变量定义为整型变量 */bit mybit=ibase15 bit mybit=ibase15;/*mybit mybit定义为定义为 ibaseibase的的D15D15位位 */这里位是运算符这里位是运算符 “”相当于汇编中的相当于汇编中的 “”,其后的最大取值依,其后的最大取值依赖于该位所在的变量的类型,如定义为赖于该位所在的变量的类型,如定义为charchar最大值只能为最大值只能为7 7。对特殊功能寄存器的位的定义。对特殊功能寄存器的位的定义。24 对特殊功能寄存器的位的定义的对特殊功能寄存器的位的定义的4 4种方法:种方法:方法方法1 1:使用头文件及:使用头文件及sbitsbit定义符;多用于无位名的可寻址位。定义符;多用于无位名的可寻址位。例如例如#include#include sbit P1_1=P11 sbit P1_1=P11;/*P1_1 P1_1为为P1P1口的第口的第1 1位位 */sbit ac=ACC7 sbit ac=ACC7;/*ac ac定义为累加器定义为累加器A A的第的第7 7位位 */方法方法2 2:使用头文件:使用头文件reg51.hreg51.h,再直接用位名称。,再直接用位名称。例如例如#include#include RS1=1 RS1=1;RS0=0RS0=0;方法方法3 3:用字节地址位表示:用字节地址位表示 例如例如 sbit OV=0 xD02sbit OV=0 xD02;方法方法4 4:用寄存器名:用寄存器名.位定义位定义 例如例如 sfr PSW=0 xd0sfr PSW=0 xd0;/*定义定义PSWPSW地址为地址为d0H d0H*/sbit CY=PSW7 sbit CY=PSW7;/*CY CY为为PSWPSW7 7*/254.5.3 C514.5.3 C51对存贮器和外接对存贮器和外接I/OI/O口的绝对地址访问口的绝对地址访问 C51C51对存贮器和外接对存贮器和外接I/OI/O口的绝对地址访问可以通过指针访问,也可以口的绝对地址访问可以通过指针访问,也可以通过函数访问。通过函数访问。下面介绍函数访问的方法:下面介绍函数访问的方法:1.1.对存贮器的绝对地址访问对存贮器的绝对地址访问 利用绝对地址访问的头文件利用绝对地址访问的头文件absacc.habsacc.h可对不同的存贮区进行访问。可对不同的存贮区进行访问。该头文件的函数有该头文件的函数有:CBYTE (CBYTE (访问访问codecode区字符型区字符型)DBYTE (DBYTE (访问访问datadata区字符型区字符型)PBYTE (PBYTE (访问访问pdatapdata或或I/O)I/O)XBYTE (XBYTE (访问访问xdataxdata或或I/O)I/O)还有还有CWORDCWORD、DWORDDWORD、PWORDPWORD和和XWORDXWORD四个函数,它们的访问区域同上,四个函数,它们的访问区域同上,只是访问的类型为只是访问的类型为int int 型型 例:例:#include#include#define com XBYTE#define com XBYTE0 x07ff0 x07ff用用“include”include”即可使用其中定义的宏来访问绝对地址,包括:即可使用其中定义的宏来访问绝对地址,包括:CBYTECBYTE、XBYTEXBYTE、PWORDPWORD、DBYTEDBYTE、CWORDCWORD、XWORDXWORD、PBYTEPBYTE、DWORD,DWORD,打开打开absacc.habsacc.h,可看到:,可看到:#define CBYTE(unsigned char volatile code*)0)#define DBYTE(unsigned char volatile data*)0)#define PBYTE(unsigned char volatile pdata*)0)#define XBYTE(unsigned char volatile xdata*)0)#define CWORD(unsigned int volatile code*)0)#define DWORD(unsigned int volatile data*)0)#define PWORD(unsigned int volatile pdata*)0)#define XWORD(unsigned int volatile xdata*)0)26 那么后面程序那么后面程序comcom变量出现的地方,就是对地址为变量出现的地方,就是对地址为07ffH07ffH外部外部RAMRAM或或I/OI/O口进行访问。口进行访问。例:例:XWORDXWORD0 0=0 x9988=0 x9988;即将;即将9988H(int9988H(int类型类型)送入外部送入外部RAMRAM的的0 0号和号和1 1号单元。号单元。使用中要注意使用中要注意:absacc.habsacc.h一定要包含进程序。一定要包含进程序。CBYTECBYTE、DBYTEDBYTE、XBYTEXBYTE等函数名必须大写。等函数名必须大写。例如:例如:rval=CBYTE0 x0002;rval=CBYTE0 x0002;指向程序存贮器的指向程序存贮器的0002h0002h地址地址 rval=XWORD0 x0002;rval=XWORD0 x0002;指向片外指向片外RAMRAM的的0004h0004h地址,因为是地址,因为是2 2个字节个字节 2.2.对外部对外部I/OI/O口的访问口的访问 由于单片机的由于单片机的I/OI/O口和外部口和外部RAMRAM统一编址,因此对统一编址,因此对I/OI/O口地址的访问可用口地址的访问可用XBYTE(MOVX DPTR)XBYTE(MOVX DPTR)或或 PBYTE(MOVX Ri)PBYTE(MOVX Ri)进行。进行。例如:例如:#include#include#define PORTA XBYTE 0 xFFC0#define PORTA XBYTE 0 xFFC0 将将PORTAPORTA定义为外部定义为外部I/OI/O口,地址为口,地址为 FFC0HFFC0H,长度为,长度为8 8位位。274.6 C514.6 C51的运算符的运算符1.1.赋值运算符赋值运算符“=”:将将 “”右边的值赋给右边的值赋给“”左边的变量左边的变量(注:不是相等运算符注:不是相等运算符)2.C512.C51的算术运算符:的算术运算符:+(+(加或正号加或正号);(减或负号减或负号);*(乘号乘号);/(/(除号除号);%(%(求余求余)优先级为:先乘除,后加减,先括号内,再括号外。优先级为:先乘除,后加减,先括号内,再括号外。3.C513.C51的关系运算符有六种:的关系运算符有六种:(小于小于);(大于大于);=(=(小于等于小于等于);=(=(大于等于大于等于);=(=(相等相等);!=(!=(不相等不相等)优先级:前四个高,后二个优先级:前四个高,后二个“=”和和“!=!=”级别低级别低 4.C514.C51的逻辑运算符有三种:的逻辑运算符有三种:&(&(逻辑与逻辑与);|(|(逻辑或逻辑或);!(!(逻辑非逻辑非)运算符的两边为关系表达式,逻辑表达式和关系表达式的值相同,运算符的两边为关系表达式,逻辑表达式和关系表达式的值相同,都是以都是以“0 0”代表假,以代表假,以“1 1”代表真。代表真。以上三种运算的优先级见图以上三种运算的优先级见图4.14.1。285.C515.C51的按位操作的运算符有六种:的按位操作的运算符有六种:&(&(按位与按位与);(按位或按位或);(按位异或按位异或);(位取反位取反);(位右移位右移 )(注注:移位操作为补零移位移位操作为补零移位)例例1 1:a=0 xf0a=0 xf0;表达式表达式a=a=的值为的值为0FH 0FH 例例2 2:a=0 xeaa=0 xea;表达式表达式a a2 2值为值为A8HA8H,即,即a a值左移两位,移位后空白值左移两位,移位后空白位补位补0 0。6.6.自增、自减运算符:自增、自减运算符:+i+i,-i(-i(在使用在使用i i之前,先使之前,先使i i值加值加(减减)1)1)i+i+,i-(i-(在使用在使用i i之后,再使之后,再使i i值加值加(减减)1)1)例:例:设设i i原值为原值为5 5 如如 j=+i j=+i 则则j j值为值为6 6,i i值也为值也为6 6。如如 j=i+j=i+则则j j值为值为5 5,i i值为值为6 6。7.7.复合赋值运算符:复合赋值运算符:+=+=,-=-=,*=,/=/=,%=%=,=,&=&=,=,|=|=。例:例:a+=ba+=b相当于相当于a=a+ba=a+b。A=gA=g相当于相当于a=ag a=ag 298.8.对指针操作的运算符对指针操作的运算符&:取地址运算取地址运算 *:取内容运算符(间址运算符):取内容运算符(间址运算符)这里要注意:这里要注意:“&”与按位与运算符的差别,如果与按位与运算符的差别,如果“&”为为“与与”,&的两边必须为的两边必须为变量或常量;变量或常量;例:例:a=&ba=&b;取;取b b变量的地址送变量变量的地址送变量a a。“*”与指针定义时指针前的与指针定义时指针前的“*”的差别,如的差别,如char char*ptpt;c=c=*ptpt;第;第二条语句将以二条语句将以ptpt的内容为地址的单元的内容送的内容为地址的单元的内容送C C。第一条语句中的。第一条语句中的“*”只表示只表示ptpt为指针变量,不代表间址取内容的运算。为指针变量,不代表间址取内容的运算。3031
展开阅读全文