1、1单片机汇编与C语言程序设计工程训练中心2单片机汇编与C语言程序设计C51数据与计算2C51函数4MCS-51汇编指令系统3 1C51构造数据类型3 3C51模块化流程控制语句53第一章 MCS-51汇编指令系统寻址方式31.1指令说明1.241.1 寻址方式51.2 指令说明v1、数据传送指令 MOV,MOVC,MOVX,XCH,PUSH,POPv2、转移指令 JMP,CJNE,JC,JB,CALL,RETv3、算数运算指令 ADD,ADDC,SUBB,MUL,DIV,INC,DECv4、逻辑运算指令 ANL,ORL,XRL,CPL,CLR,SETB6第二章 C51数据与计算位变量的C51定
2、义2.4C51数据类型及在MCS-51中存储方式、存储结构32.1C51单片机并行接口的定义32.3MCS-51特殊功能寄存器(SFR)的定义2.2C51运算符、表达式及其规则2.572.1.1 C51数据类型v1、C51的数据类型包括:v位型(bit)、无符号字符型(unsigned char)、有符号字符型(signed char)、无符号整型(unsigned int)、有符号整型(signed int)、无符号长整型(unsigned long int)、有符号长整型(signed long int)、浮点型(float)和指针类型等82.1.1 C51数据类型表1、C51的数据类型9
3、2.1.2C51数据在MCS-51中的存储方式v1、位变量(bit),位变量被定为在RAM的位寻址空间中;v2、字符变量(char),字符变量即长度为一个字节8位,最适合MCS-51单片机,MCS-51单片机每次可处理8位数据;v3、整型变量(INT),整型变量长度16位,占2个字节;v4、浮点型变量(Float),浮点型变量32位,占4个字节;102.1.2C51数据在MCS-51中的存储方式v1、在编程时,如果只强调速度,而不进行负数的运算,最好采用无符号的格式(unsigned);v2、无论何时,应尽量使用无符号字符型变量,因为它能直接被MCS-51所接受,基于同样的原理,也尽量使用位变
4、量;有符号字符变量虽也占用一个字节,但需要进行额外的操作来测试代码的符号位,这无疑会降低代码的效率;112.1.2C51数据在MCS-51中的存储方式v3、使用简化形式定义数据类型,其方法是在源程序开头使用#define语句自定义简化的类型标示符;例如: #define uchar unsigned char #define uint unsigned int 这样在编程时就可以用uchar代替unsigned char,用uint代替unsigend int来定义变量了。122.1.3C51的数据存储类型表2 C51存储类型与存储空间对应关系132.1.3C51的数据存储类型表2 C51存储
5、类型及其数据长度和值域存储类型长度(bit)长度(byte)值域范围data810255idata810255pdata810255xdata162065 535code162065 535142.1.3C51的数据存储类型v1、带存储类型的变量定义的一般格式如下:v 数据类型 存储类型 变量名v char data var1;v bit bdata flag;v float idata x,y,z;v unsigned int pdata var2;152.1.3C51的数据存储类型表3 C51存储模式说明162.2MCS-51特殊功能寄存器(SFR)的定义v1、除了程序计数器PC和4组个通
6、用寄存器组外,其他所有的寄存器都属于特殊功能寄存器(SFR),分散在片内的高128字节中,地址为80H-FFH;SFR中有11个寄存器具有位寻址功能,可以单独对每一位进行操作;v2、为了能直接访问这些SFR,C51提供了一种自主的定义方式(定义方法与并准C语言不兼容),定义的一般格式如下: sfr name=int constant;172.2MCS-51特殊功能寄存器(SFR)的定义v3、“sfr”是定义语句的关键字,其后必跟一个MCS-51单片机真实存在的特殊功能寄存器名;“=”后必须是一个整型常数,不允许带有运算符的表达式,是特殊功能寄存器名相对应的字节地址;这个常数的范围必须是SFR的
7、地址范围内,也就是80H-FFH之间;v例如:sfr SCON=0 x98;/串口控制寄存器/182.2MCS-51特殊功能寄存器(SFR)的定义v4、特殊功能寄存器(SFR)的命名和定义被放在“*.H”的头文件里面定义保存好,以便以后调用;v5、对于位寻址的SFR中的位,使用“sbit”关键字来定义(不与标准C语言兼容); 第一种格式:sbit name=sfrnameint cont 第二种格式:sbit name=int contint cont 第三种格式:sbit name=int constant192.2MCS-51特殊功能寄存器(SFR)的定义v例如:sfr PSW=0 xD0
8、; sbit OV=PSW2; sbit OV=0 xD02; sbit OV=0 xD2;(绝对地址) 202.3C51单片机并行接口的定义v1、MCS-51的并行IO接口除了芯片上的4个IO口(P0P3)外,还可以在片外扩展IO口;MCS-51的单片机的IO口与数据存储器统一编址,即把一个IO口当作数据存储器的一个单元来处理;v通常将片内和片外IO口统一在一个头文件里面进行定义;也可以在主程序的开头进行定义;v片内定义:sfr P0=0 x80;212.3C51单片机并行接口的定义v对于片外扩展的IO口,则根据硬件译码地址,将其视为片外数据存贮器的一个单元;使用#define进行定义;例如
9、: #include #define PORTA XBYTE0 xFFC0 absacc.h是51绝对地址访问函数的头文件,将PORTA定义为外部IO口,地址为FFC0H,长度8位;222.4位变量的C51定义v对于位变量的定义,定义位变量后,就可以用定义了的变量来表示MCS-51的位寻址单元;v位变量定义一般格式如下: 位类型标示符(bit) 位变量名; bit direction_bit;232.5C51运算符、表达式及其规则v1、C51算术运算符:+、-、*、/、%v乘除、求余运算符优先级高于加减v强制类型转换运算符 (类型名)(表达式);v2、C51关系运算符、表达式及优先级v = =
10、 !=v前4个优先级相同大于后2个,关系运算符低于算术运算符,关系运算符高于赋值运算符242.5C51运算符、表达式及其规则v3、C51逻辑运算符、表达式及优先级v“&”逻辑与,“|”逻辑或,“!”逻辑非v4、C51位操作及其表达式v&按位与,按位异或,位左移,|按位或,按位取反,位右移;v移位运算不会改变原变量本身;252.5C51运算符、表达式及其规则v5、自增减运算符,符合运算符及表达式v自增减运算符:+i,-i(使用前加减1)v i+,i-(使用后再加减1)v符合运算符:+=,-=,*=,/=,%=,=,&=,=,|=;采用符合运算符的目的是为了简化程序,提高C程序编译效率;26第三章
11、 C51构造数据类型结构3.4基于存储器的指针33.1指针33.3数组3.2273.1基于存储器的指针v基于存储器的指针以存储器类型为参量,它在编译时才被确定;因此,为指针选择存储器的方法可以省掉,以便这些指针的长度为一个字节(idata*,data*,pdata*)或2个字节(code*,xdata*).编译时,这类操作一般被“行内”编码,而无须进行库调用;v基于存储器的指针定义举例: char xdata* px;283.1基于存储器的指针v在xdata存储器中定义一个指向字符型(char)的指针变量px。指针自身在默认的存储区(决定于编译模式);长度为两个字节(值为0-0 xFFFF);
12、v char xdata* data pdx;v data char xdata* pdx;v除了明确定义指针位于MCS-51内部存储区(data)外,其他与上例相同,与编译模式无关293.2数组v1、一维数组的定义方式:v 类型说明符 数组名 整型表达式v int idata a6= ;v2、二维数组的定义方式:v 类型说明符 数组名常量表达式常量表达式v存取方式,顺序,按行存取,先存取第一行,依次下来;303.2数组v 3、字符数组v char a10=B,E,I,J,I,N,G,0;v 用字符串直接给字符数组置初值v char a10=“BEI JING”;(编译器会自动在字符末尾加上结
13、束符0),因此,字符数组的元素数目一定要比字符多一个;v 二维字符数组,第一个下标是字符串个数,第二个下标是每个字符串长度:v 例如:uchar code msg17= ;第二个下标个数必须给定; 313.3指针(重点内容)v1、首先了解数据在数据中是如何存贮和读取的?vC编译器在编译时会给一个变量在内存中分配相应的内存空间v变量名数据标号v变量值数据的内容v内存单元地址编号v内存单元内容内存单元中的数据323.3指针(重点内容)v2、变量名内存单元地址v变量值内存单元中的内容v3、内存中变量名a,b,c是不存在的,对变量名的存取通过地址进行;v两种存取方式:v“直接访问”,找地址,取变量值;
14、v“间接访问”,找存放a的地址的内存单元的地址;取出变量a的地址,然后从找到的a的地址中再取数据(变量值);333.3指针(重点内容)v4、学好指针必须弄清“变量的指针”和“指向变量的指针变量”(指针变量)v变量的指针就是变量的地址;v指向变量的指针变量,一个变量专门用来存放另一个变量的地址,则该变量称为指针变量;343.3指针(重点内容)v5、指针变量的定义v 类型识别符 *指针变量名v int *ap; float *pointer;v指针变量的引用是通过取地址运算符&来实现v ap=&a;(ap为指针变量,a为变量,&为取地址运算符)353.3指针(重点内容)v6、通过指针和指针变量来对
15、内存进行间接访问,就需要用到指针运算符“*”;v例如:x=a;x=*ap(这里*号代表指针运算符);这个“*”指针运算符,而非类型说明符,注意区分;v例如:int *ap(这里*号代表类型说明符);int a;v *ap = a;&*ap = &a;v *ap+ = a+;363.3指针(重点内容)v7、数组指针和指向数组的指针变量v数组的指针=数组的起始地址;v指向数组的指针变量;v例如:int a10;int *app;v app=&a0;v app=a;(C语言规定数组名a可以代表数组a10的首地址,实际上述两个等价);373.3指针(重点内容)v也可以将指针变量的定义和引用放在一个语句
16、中完成v int *app = &a0; int *app=a;383.3指针(重点内容)v通过通用指针引用数组元素;vapp=&a0,则app+i=a+i是数组元素ai的地址;v*(app+i)或*(a+i)是app+i或a+i所指向的数组元素,即ai;v指针变量可带下标:appi=*(app+i);vapp+1是指向数组首地址的下一个元素393.3指针(重点内容)v指针变量的运算:v1)、p+, p指向下一个单元;v2)、*p+ = *(p+)等价 /+运算符与*指针运算符优先级相同,结合方向为自右向左/;其作用是首先得到p指向的变量的值(即*p),然后执行p自加运算,指向下一个地址;v3
17、)、(*p)+,所指向的元素值加1,而非指针变量加1;403.3指针(重点内容)v8、指向多维数组的指针和指针变量vpa34;p=a;p+1=a+1;p+2=a+2指向第几行的首地址;v*(p+1)+3=&a13;指向a13的地址v*(*(p+1)+3)=a13;表示a13的值v*(p+i)+j;相当于&aij;第i行第j列地址v*(*(p+i)+j)相当于aij;413.4结构(重点内容)v1、结构的定义与应用v将不同类型的数据组成一个有机的整体,而组合在一起的数据又相互关联;v一个结构类型的一般形式为:v struct 结构名 结构成员说明 ;v结构类型定义完以后,还需要定义结构的变量42
18、3.4结构(重点内容)v2、结构变量的定义有2种:v1)先定义结构类型,再定义结构变量名;v struct date int month; int day; ; date date1,date2;(定义结构变量名)433.4结构(重点内容)v2)定义结构类型的同时定义该结构变量;v struct date int month; int day; date1,date2;(定义结构变量名)443.4结构(重点内容)v3对结构变量的引用遵循下述规则:v1)只能对结构类型变量进行赋值、存取和运算,结构不能作为一个整体参与赋值、存取和运算,不能整体作为函数的参数或函数返回值(因为C编译器不对抽象的结构
19、类型分配内存空间,只对具体的结构类型变量分配内存空间);v2)对多级结构变量,只有最低一级的成员才能参加赋值、存取和运算;453.4结构(重点内容)v3对结构变量的引用遵循下述规则:v3)成员运算符,引用方式为:v结构变量名.成员名(成员运算符“.”);v date1.year=1996;v结构类型变量的成员本身又属于一个结构类型变量,则需用若干个成员运算符“.”或“-”v clerk1.birthday.year=1957;463.4结构(重点内容)v4、结构数组v结构数组的一般定义举例:vstruct date int month; int day; struct date date110
20、; 引用例如:date15.month=0 x04; 473.4结构(重点内容)v5、指向结构类型数据的指针v指向结构体变量的指针变量的一般形式:vstruct 结构类型名 *指针变量名 struct msg1 uint lnk; uchar len,flg; ; struct msg1 *msg; void message(struct msg1 *m);483.4结构(重点内容)v6、指向结构数组的指针变量 struct uint lnk; uchar len,flg,nod;msg14; struct msg1 *p; void sendmessage(struct msg1 *m);
21、493.4结构(重点内容) main( ) struct msg1 *p; for(p=msg1; plen=8; p-flg=0; sendmessage(p);/*传递结构数组的指针变量*/ 503.4结构(重点内容)v对指针变量p做几点说明:v1、(*p).flg与p-flg和msg0.flg三者等价v2、p+1是指指针p指向数组结构msg0的下一个元素msg1的首地址;v3、指向运算符-的优先级高于自加运算符+v(+p)-flg; (p+)-flg;vp-flg+; +p-flg;(区分)513.4结构(重点内容)v对指针变量p做几点说明:v(+p)-flg; 先使p自加1指向msg1
22、的首地址。然后得到它指向的msg11.flg的成员值;v (p+)-flg;先得到msg10.flg的值,然后p自加1指向msg11的首地址vp-flg+; 先得到msg10.flg成员值,使用完后将msg10的值加1;v +p-flg;先将msg10.flg成员值加1,再使用;52第四章 函 数数组、指针作为函数的参数4.4函数的分类、定义34.1函数的调用34.3函数的参数和函数值4.2534.1函数的分类、定义v1、函数的分类v1)标准库函数,由C编译系统的函数库提供v2)用户自定义函数,根据用户自身需要编写的函数544.1函数的分类、定义v2、函数的定义v1)无参数函数的定义:返回值类
23、型标识符 函数名( ) 函数体语句 无参数函数一般不带返回值,因此函数返回值类型标识符可以省略。如果不带,默认值是int类型554.1函数的分类、定义v2、函数的定义v2)有参数函数的定义:返回值类型标识符 函数名(形式参数列表 )形式参数说明; 函数体语句564.1函数的分类、定义v2、函数的定义v3)空函数的定义:返回值类型标识符 函数名( )574.2函数的参数和函数值v1、函数之间的参数传递,由函数调用时,主调函数的实参与被调函数的形参之间进行数据传递来实现;v形参与实参的类型必须一致,否则会发生类型不匹配的错误;v形参在被调用前,不占用实际内存;584.2函数的参数和函数值v2、函数
24、的返回值v函数的返回值是通过函数中return语句获得的,一个函数可以有一个以上的return语句,但必须在选择结构中使用(if);vreturn语句中的返回值也可以是一个表达式;v函数的返回值类型一般在定义函数时,用返回类型标识符指定;v有时为了明确表示被调用函数不带返回值,可以将该函数定义为“无类型”void; 594.3函数的调用v1、函数调用的一般形式:v函数名 (实际参数列表);v对于有参数函数,若包含多个实际参数,应将参数间用逗号隔开;形参与实参数目一致;v如调用是无参数函数,则实际参数表可意省略,函数名后必须有一对空括号;604.3函数的调用v2、函数调用的方式:v1)函数调用语
25、句,即把被调函数名作为主调函数的一个语句; print_message( );v2)函数结果作为表达式的一个运算对象; result=2*gcd(a,b);v3)函数参数,被调函数作为另一个函数的实际参数;m=max(a,gcd(u,v);614.3函数的调用v3、对被调用函数的说明v1)被调用函数必须是已经存在的函数(库函数或用户自定义函数)v2)如果程序中使用了库函数,或不在同一文件中另外的自定义函数,则应该在程序开头使用#include包含语句,将所有函数信息包括到程序中;624.3函数的调用v3、对被调用函数的说明v3)被调函数的定义放在主调函数之前,就可以不必另作类型说明;634.4
26、数组、指针作为函数的参数v1、用函数指针变量调用函数v每一个函数都占用一段内存单元,它们有一个起始地址,使用指针变量,让它指向函数入口地址,让它来访问函数;644.4数组、指针作为函数的参数v 例如:main( ) int j,c; int (*p)( );/*函数指针变量定义*/ p=factorial; for(j=0;jnumber); 744.4数组、指针作为函数的参数v main( ) void show( ); /*函数申明*/ struct record note; note.number=3361; show(¬e); ¬e是struct record结构变量not
27、e的地址;754.4数组、指针作为函数的参数v当调用show( )函数时,地址¬e被传递给show的形式参数p,p是一个指向struct record类型结构变量的指针,这样p指向note,在show( )函数中p指向结构体变量的各个成员;76第五章 C51模块化流程控制语句顺序结构35.1循环结构35.3选择结构5.2775.1顺序结构v1、C语言是一种结构化的编程语言,结构化的语言是一种不允许交叉的流程;必须是有严格的结构化;v2、C语言的基本单元是模块,一般只有一个入口和一个出口,结构化语言由若干个模块组成,每个模块包含若干个结构,每个基本结构中由包含若干条语句;785.1顺序结构
28、v3、顺序结构是一种最基本,最简单的编程结构,这种结构中,程序由低地址向高地址顺序执行指令代码;图1 顺序结构795.2选择结构v1、选择结构,程序首先对一条语句进行测试。当条件为真时,执行一个方向上的程序流程;程序为假时,执行另一个方向上的程序流程,而对有些分支语句来说可能什么都不做;805.2选择结构图2 一般型的选择结构815.2选择结构v1)串行多分支结构(if else语句),串行多分支结构中,以单选择结构中的某一分支方向作为串行多分支方向继续进行选择结构的操作;v 一种if else语句; v 另一种 if else if 语句(语句嵌套的方式)825.2选择结构v条件选择语句用法
29、v1. if(表达式)语句;v if(p1 != 0)c=20;v2. if(表达式)语句1; else语句2;v if(p1 != 0) c=20; else c=0;835.2选择结构v3. if(表达式1)语句1; else if(表达式2)语句2; else if(表达式m)语句n; else 语句m;845.2选择结构v举例v if(a=1)c=0; else if(a=2)c=20; else if(a=3)c=30; else c=0;855.2选择结构v if语句的嵌套:v if( ) if( )语句1; else( )语句2; else if( )语句1; else( )语句
30、2;865.2选择结构v2)并行多分支结构,并行多分支结构中,根据判断条件的不同,而选择不同的操作中的一种来执行;v例如 switch-case语句875.2选择结构图3 串行的多分支结构图4 并行的多分支结构885.2选择结构v例如 switch-case语句v switch (表达式) case常量表达式1:语句1;break; case常量表达式2:语句2;break; case常量表达式n:语句n;break; default : 语句n+1; break;895.3循环结构v1、循环结构的常见状态,包括当型(while)和直到型(do-while)结构;v1)当型(while)是在每
31、一轮循环的开始处执行条件判断,当条件满足时继续执行循环体中的语句,否着跳出循环;v2)直到型(while)是先执行循环体中的语句,然后在循环结束处进行条件判断,如果条件满足继续开始新一轮循环;直到条件不满足跳出循环;905.3循环结构v2、for语句是循环语句中最复杂最灵活的一种;可用于给定的循环次数,或是次数不定的情况;v for(表达式1;表达式2;表达式3)v语句;/*循环体*/v第一部分为初始化表达式,第二部分对结束循环进行测试,第三部分为尺度增量;915.3循环结构v具体的执行过程为:v1.先对表达式1赋初值,进行初始化;v2.判断表达式2是否满足给定的循环条件,若满足,则执行循环体内语句,然后执行后续语句;v3.若表达式2为真,执行指定完循环语句后,求解表达式3;v4.重复第2步直到条件不满足跳出循环;