1、第3章 51单片机程序设计第3章 程序设计林海波林海波第3章 51单片机程序设计内内 容容 提提 要要概述汇编语言程序设计C语言程序设计第3章 51单片机程序设计3.1 概述 MCS-51单片机的编程语言可以是汇编语言也可以是高级语言(如C语言),高级语言编程快捷,但程序长,占用存储空间大,执行慢;汇编语言产生的目标程序简短,占用存储空间小,执行快,能充分发挥计算机的硬件功能。无论是高级语言还是汇编语言,源程序都要转换成目标程序(机器语言)单片机才能执行。第3章 51单片机程序设计连接连接/定位器定位器L51汇编语言汇编语言源程序源程序汇编器汇编器A51符号转换程序符号转换程序OHS51绝对地
2、址绝对地址目标程序目标程序.BINC语言程序语言程序浮浮动动地地址址目目标标程程序序编译器编译器C51 HEX图图 3-1 两种语言源程序转换成目标程序两种语言源程序转换成目标程序第3章 51单片机程序设计 目前很多公司将编辑器、汇编器、编译器、连接/定位器、符号转换程序做成集成软件包,用户进入该集成环境,编辑好程序后,只需点击相应菜单就可以完成上述的各步,如WAVE、KEIL、IAR等。汇编汇编:将汇编语言:将汇编语言源程序源程序转换成机器语言转换成机器语言目标目标程序的程序的过程称为汇编。过程称为汇编。汇编程序汇编程序:能将汇编语言:能将汇编语言源程序源程序转换成机器语言转换成机器语言目标
3、目标程序的系统软件称为汇编程序。程序的系统软件称为汇编程序。第3章 51单片机程序设计汇编的方法汇编的方法:汇编的方法有两种:汇编的方法有两种1.手工汇编手工汇编:人工查指令表,查出程序中每条指令对应的机人工查指令表,查出程序中每条指令对应的机器代码。早期的计算机使用。器代码。早期的计算机使用。2.机器汇编机器汇编:用计算机中的汇编程序对用户源程序进行汇编。用计算机中的汇编程序对用户源程序进行汇编。用机器汇编要提供给汇编一些信息,遵循汇编程用机器汇编要提供给汇编一些信息,遵循汇编程序的一些约定。这些由伪指令指定。序的一些约定。这些由伪指令指定。第3章 51单片机程序设计1)确定程序中每条汇编语
4、言指令的指令机器码确定程序中每条汇编语言指令的指令机器码2)确定每条指令在存储器中的存放地址确定每条指令在存储器中的存放地址3)提供错误信息提供错误信息4)提供目标执行文件提供目标执行文件(*.OBJ/*.HEX)和列表文件和列表文件(*.LST)地址地址 机器码机器码源程序源程序 ORG 2000H 2000H 78 30 MAIN:MOV R0,#30H 2002H E6 MOV A,R0 第3章 51单片机程序设计1.机器指令:指令系统中的全部指令。每条机器指令都机器指令:指令系统中的全部指令。每条机器指令都有对应的机器代码,可以被有对应的机器代码,可以被CPU执行。执行。2.伪指令:伪
5、指令:汇编控制指令,没有指令代码,只用于汇编汇编控制指令,没有指令代码,只用于汇编过程,为汇编程序提供汇编信息。过程,为汇编程序提供汇编信息。一、汇编语言指令类型一、汇编语言指令类型 宏汇编功能:将需要反复多次执行的程序段定义成一个宏宏汇编功能:将需要反复多次执行的程序段定义成一个宏指令名(宏定义)。编程时,可在程序中使用宏指令名来替指令名(宏定义)。编程时,可在程序中使用宏指令名来替代被定义的程序段(宏调用)。代被定义的程序段(宏调用)。3.2 伪指令伪指令第3章 51单片机程序设计宏定义过程宏定义过程:宏调用过程:宏调用过程:宏指令名宏指令名 实际参数实际参数 宏指令名宏指令名 实际参数实
6、际参数宏指令名宏指令名 MACRO 形式参数形式参数 ;被定义的程序段;被定义的程序段 ENDM第3章 51单片机程序设计二伪指令二伪指令 常用伪指令及功能:常用伪指令及功能:1.起始指令起始指令 ORG nn功能:定义程序或数据块的起始地址。功能:定义程序或数据块的起始地址。指示此语句后面的程序指示此语句后面的程序或数据块以或数据块以nn为起始地址,连续存放在程序存储器中。为起始地址,连续存放在程序存储器中。指令地址指令地址 机器码机器码源程序源程序 ORG 2000H 2000H 78 30 MAIN:MOV R0,#30H 2002H E6 MOV A,R0 ORG 3000H 3000
7、H 23 TAB:DB 23H,100,A 3001H 64 3002H 41第3章 51单片机程序设计2.字节定义字节定义 标号:标号:DB(字节常数,(字节常数,或字符或表达式)或字符或表达式)功能:功能:指示在程序存储器中以标号为起始地指示在程序存储器中以标号为起始地址的单元里存放的数为字节数据(八位二进址的单元里存放的数为字节数据(八位二进制数)。制数)。例如例如 LN:DB 32,C,25H,-1;LNLN+2 地址单元依次存放地址单元依次存放20H,43H,25H,FFH地址地址 数据数据LN20LN+143LN+225LN+3FF3.字定义字定义 标号:标号:DW(字常数或表达式
8、(字常数或表达式)作用:作用:指示在程序存储器中以标号为起始地址指示在程序存储器中以标号为起始地址的单元里存放的数为字数据(即的单元里存放的数为字数据(即16位的二进制数),位的二进制数),例如:例如:GH:DW 1234H,5678H,08GH1234GH+25678GH+40008第3章 51单片机程序设计 5.等值指令等值指令 标号标号 EQU(数值表达式)(数值表达式)表示表示EQU两边的量等值,用于为标号或标识符赋值。两边的量等值,用于为标号或标识符赋值。例如:例如:X1 EQU 2000H X2 EQU 0FH MAIN:MOV DPTR,#X1 ;DPTR=2000H ADD A
9、,#X2 ;A=A+0FH4保留字节保留字节 标号:标号:DS(数值表达式)(数值表达式)作用:作用:指示在程序存储器中保留以标号为起始地址的若指示在程序存储器中保留以标号为起始地址的若干字节单元,其单元个数由数值表达式指定。干字节单元,其单元个数由数值表达式指定。例如例如 L1:DS 32;从从L1地址开始保留地址开始保留32个存储单元。个存储单元。第3章 51单片机程序设计6.位定义位定义 标号标号 BIT 位地址位地址 作用:作用:同同EQU指令,不过定义的是位操作地址。指令,不过定义的是位操作地址。例如例如 AIC BIT P1.1。7.汇编结束汇编结束 END作用:指示源程序段结束。
10、作用:指示源程序段结束。END指令放在程序的最后。指令放在程序的最后。A51汇编程序还有一些其它的伪指令,列在教材表汇编程序还有一些其它的伪指令,列在教材表3-1中。中。第3章 51单片机程序设计汇编语言程序设计步骤汇编语言程序设计步骤一.确定方案和计算方法二.了解应用系统的硬件配置、性能指标三.建立系统数学模型,确定控制算法和操作步骤四.合理分配存储器单元和了解I/O接口地址五.编制源程序1.按功能设计程序,明确各程序之间的相互关系2.用流程图表示程序结构和功能开始1 YN?3.程序中用注释说明指令在程序中的作用,方便阅读、调试和修改第3章 51单片机程序设计第10章 C语言编程林海波林海波
11、第3章 51单片机程序设计内内 容容 提提 要要 C51程序结构程序结构 C51的数据类型的数据类型 数据的存贮类型和存贮模式数据的存贮类型和存贮模式 SFR、可寻址位、存储器和、可寻址位、存储器和I/O口的定义口的定义 C51的运算符的运算符 函函 数数 变量使用变量使用第3章 51单片机程序设计51系列单片机支持三种高级语言,即PL/M,C和BASIC。8052单片机内固化有解释BASIC语言,BASIC语言适用于简单编程而对编程效率运行速度要求不高的场合;PL/M是一种结构化的语言,很象PASCAL,PL/M 编译器好象汇编器一样产生紧凑的机器代码,可以说是高级汇编语言,但它不支持复杂的
12、算术运算,无丰富库函数支持,学习PL/M无异于学习一种新的语言。C语言是一种通用的程序设计语言,其代码率高,数据类型及运算符丰富,并具有良好的程序结构,适用于各种应用的程序设计,是目前使用较广的单片机编程语言。第3章 51单片机程序设计单片机的C语言采用C51编译器(简称C51)。由C51产生的目标代码短、运行速度高、所需存储空间小、符合C语言的ANSI标准,生成的代码遵循Intel目标文件格式,而且可与A51汇编语言或PL/M51语言目标代码混和使用。第3章 51单片机程序设计应用C51编程具有以下优点:(1)C51管理内部寄存器和存贮器的分配,编程时,无需考虑不同存储器的寻址和数据类型等细
13、节问题;()程序由若干函数组成,具有良好的模块化结构;()有丰富的子程序库可直接引用,从而大大减少用户编程的工作量。()C语言和汇编语言可以交叉使用.汇编语言程序代码短、运行速度快、但复杂运算编程耗时。如果用汇编语言编写与硬件有关的部分程序,用C语言编写与硬件无关的运算部分程序,充分发挥两种语言的长处,可以提高开发效率。第3章 51单片机程序设计10.1 C51程序结构程序结构 同标准C一样,C51的程序由一个个函数组成,这里的函数和其他语言的“子程序”或“过程”具有相同的意义。其中必须有一个主函数main(),程序的执行从main()函数开始,调用其 他函数后返回主函数main(),最后在主
14、函数中结束整个程序而不管函数的排列顺序如何。第3章 51单片机程序设计C语言程序的组成结构如下所示语言程序的组成结构如下所示:全局变量说明 /*可被各函数引用*/main()/*主函数*/局部变量说明 /*只在本函数引用*/执行语句(包括函数调用语句)fun1(形式参数表)/*函数1*/形式参数说明局部变量说明 执行语句(包括调用其他函数语句)funn(形式参数表)/*函数n*/形式参数说明 局部变量说明 执行语句第3章 51单片机程序设计C语言的语句规则:1.每个变量必须先说明后引用,变量名英文大小写是有差别的。2.C语言程序一行可以书写多条语句,但每个语句必须以“;”结尾,一个语句也可以多
15、行书写为好。3.C语言的注释用/*/表示。4.“”花括号必须成对,位置随意,可在紧挨函数名后,也可另起一行,多个花括号可以同行书写,也可逐行书写,为层次分明,增加可读性,同一层的“”花括号对齐,采用逐层缩进方式书写。第3章 51单片机程序设计10.2 C51的数据类型的数据类型 C51的数据有常量和变量之分。常量在程序运行中其值不变的量,可以为字符,十进制数或十六进制数(用0 x表示)。常量分为数值型常量和符号型常量,如果是符号型常量,需用宏定义指令(#define)对其进行定义(相当于汇编的“EQU”伪指令)如:#define PI 3.1415 那么程序中只要出现PI的地方,编译程序都译为
16、3.1415。变量在程序运行中其值可以改变的量。一个变量由变量名和变量值构成,变量名即是存贮单元地址的符号表示,而变量的值就是该单元存放的内容。定义一个变量,编译系统就会自动为它安排一个存贮单元,具体的地址值用户不必在意。第3章 51单片机程序设计10.2.1 C51变量的数据类型变量的数据类型 无论哪种数据都是存放在存贮单元中的,每一个数据究竟要占用几个单元(即数据的长度)都要提供给编译系统,正如汇编语言中存放数据的单元要用DB或DW伪指令进行定义一样,编译系统以此为根据预留存贮单元,这就是定义数据类型的意义.C51编译器支持数据类型见表10.1。第3章 51单片机程序设计表10-1 C51
17、的数据类型 第3章 51单片机程序设计对表10.1作如下说明:1.字符型(char)、整型(int)和长整型(long)均有符号型(signed)和无符号型(unsigned)两种,如果不是必须,尽可能选择unsigned型,这将会使编译器省却符号位的检测,使生成的程序代码比signed类型短得多。2.程序编译时,C51编译器会自动进行类型转换,例如将一个位变量赋值给一个整型变量时,位型值自动转换为整型值;当运算符两边为不同类型的数据时,编译器先将低级的数据类型转换为较高级的数据类型,运算后,运算结果为高级数据类型。3.51单片机内部数据存贮器的可寻址位(20H2FH)定义为bit型,而特殊功
18、能寄存器的可寻址位(即地址为X0H和X8H的SFR的各位)只能定义为sbit类型。第3章 51单片机程序设计10.2.2 关于指针型数据关于指针型数据(1)关于指针型变量 在汇编语言程序中,要取存贮单元m的内容可用直接寻址方式,也可用寄存器间接寻址方式,如果用R1寄存器指示m的地址,用R1取m单元的内容。相对应的在C语言中用变量名表示取变量的值(相当于直接寻址),也可用另一个变量(如P)存放m的地址,P就相当于R1寄存器。用*P取得m单元的内容(相当于汇编的间接寻址方式)这里P即为指针型变量。下面表格表示两种语言将m单元的内容送n单元的对照语句。注:注:上表省略了汇编语言程序中对符号地址上表省
19、略了汇编语言程序中对符号地址n和和m用用EQU伪指令进行具体地伪指令进行具体地址定义的址定义的 语句以及语句以及C语言对变量语言对变量n、m和指针变量和指针变量P进行类型定义的语句,实进行类型定义的语句,实际程序设计中,此步是不可际程序设计中,此步是不可 缺少的。表中缺少的。表中&为取地址运算符,为取地址运算符,*为取内容运为取内容运算符。算符。表10-2 汇编语言和C语言的对照 第3章 51单片机程序设计(2)指针型数据的类型指针型数据的类型 由于C51是结合51单片机硬件的,51单片机的不同存贮空间,有不同的地址范围,即使对于同一外部数据存贮器,又有用Ri分页寻址(Ri为八位)和用DPTR
20、寻址(DPTR为十六位)两种寻址方式,而指针本身也是一个变量,有它存放的存贮区和数据长度。因此,在指针类型的定义中要说明:被指的变量的数据类型和存贮类型;指针变量本身的数据类型(占几个字节)和存贮类型(即指针本身存放在什么存贮区)。例如类型定义为data或idata,表示指针指示内部数据存贮器;而pdata表示指针指向外部数据存贮器,用Ri间址。以上均为八位地址;而类型code/xdata表示指针指向外部程序存贮器或外部数据存贮器指针,本身(即被指 示地址)应为十六位长度。如果想使指针能适用于指向任何存贮空间,则可以定义指针为通用型,此时指针长度为3字节,第一字节表示存贮器类型编码,第二、三字
21、节分别表示所指 地址的高位和低位。第一字节表示的存贮器类型编码见表10-3:表10-3 通用型指针的存贮类型编码 第3章 51单片机程序设计10.3 数据的存贮类型和存贮模式数据的存贮类型和存贮模式 10.3.1数据的存贮类型数据的存贮类型 C51是面向8XX51系列单片机及硬件控制系统的开发语言,它定义的任何变量必须以一定的存贮类型的方式定位在8XX51的某一存贮区中,否则便没有意义。因此在定义变量类型时,还必须定义它的存贮类型,C51的变量的存贮类型如表10-4所示:第3章 51单片机程序设计表10-4 C51的变量的存贮类型 访问内部数据存贮器(idata)比访问外部数据存贮器(xdat
22、a)相对要快一些,因此,可将经常使用的变量置于内部数据存贮器中,而将较大及很少使用的数据变量置于外部数据存贮器中。例如定义变量x语句:data char x。如果用户不对变量的存贮类型定义,则编译器承认默认存贮类型,默认的存贮类型由编译控制命令的存贮的模式部分决定。第3章 51单片机程序设计10.3.2 存贮器模式存贮器模式 存贮器模式决定了变量的默认存贮器类型、参数传递区和无明确存贮区类型的说明。C51的存贮器模式有SMALL、LARGE和COMPACT(见表10-5)。在固定的存贮器地址进行变量参数传递是C51的一个标准特征,在SMALL模式下参数传递是在内部数据存贮区中完成的。LARGE
23、和COMPACT模式允许参数在外部存贮器中传递。C51同时也支持混 合模式,例如在LARGE模式下生成的程序可将一些函数分页放入SMALL模式中从而加快执行速度。例如设例如设C语言源程序为语言源程序为PROR.C,若使程序中的变量类型和参数传递区限定,若使程序中的变量类型和参数传递区限定 在在外部数据存贮区外部数据存贮区,有两种方法:,有两种方法:方法方法1:用:用C51对对PROR.C进行编译时,使用命令进行编译时,使用命令C51 PROR.C COMPACT。方法方法2:在程序的第一句加预处理命令:在程序的第一句加预处理命令#pragma compact 表10-5 存贮器模式 第3章 5
24、1单片机程序设计10.3.3 变量说明举例变量说明举例 data char var;/*字符变量var定位在片内数据存贮区*/char code MSG=PARAMETER:;/*字符数组MSG 定位在程序存 贮区*/unsigned long xdata array100;/*无符号长型数组定位在片外RAM区,每元素占4bytes*/float idata x,y,z;/*实型变量x,y,z,定位在片内用间址访问的内部 RAM区*/bit lock;/*位变量Lock定位在片内RAM可位寻址区*/unsigned int pdata sion;/*无符号整型变量sion定位在分页的外部RAM
25、*/unsigned char xdata vector1044 /*无符号字符型三维数组,定位在片外RAM区*/sfr P0=0 x80;/*定义P0口,地址为80H*/char bdata flags;/*字符变量flags定位在可位寻址内部RAM区*/sbit flag0=flags0;/*定义flag0为flags.0*/第3章 51单片机程序设计 如果在变量说明时略去存贮器类型标志符,编译器会自动选择默认的存贮器类型。默认的存贮器类型由控制指令SMALL、COMPACT和LARGE限制。例如如果声明char var,则默认的存贮器模式为SMALL,var放在data存贮区;如果使用C
26、OMPACT模式,var放入idata存贮区;在使用LARGE模式的情况下,var被放入外部数据存贮区(xdata存贮区)。10.3.4指针变量说明举例long xdata*px;/*指针px指向long型xdata区(每个数据占四个单元,指针自身在默认存贮器(如不指定编译模式在data区),指针长度为2个字节*/char xdata*data pd;/*指针pd指向字符型xdata区,自身在data区,长度2字 节*/data char xdata*pd;/*与上例等效*/data int*pn;(和int*data pn及intr*pn等效)/*定义一个类型为int型的通用型指针,指针自身
27、在data区长度为3字节*/第3章 51单片机程序设计在上例的指针声明中包含如下几个内容:1)指针变量名(如px)前面冠以“*”,表示px为指针型变量,此处*不带取内容之意。2)指针指向的存贮类型,即指向哪个存贮区,它决定了指针本身的长度(见表10.1)。存贮类型声明的位置在数据类型和指针名(如*px)之间,如无次项声明,则此指针型变量为通用型。3)指针指向的存贮区的数据类型,即被指向的存贮区以多少个单元作一个数据单位,当程序通过指针对该区操作时,将按此规定的单元个数的内容作为一个数据操作。4)指针变量自身的存贮类型,即指针处于什么区与自身的长度无关,该声明可位于声明语句的开头,也可在“*”和
28、变量名之间。此项由编译模式放在默认区,如无规定编译模式,通常在data区。第3章 51单片机程序设计10.4 C51对对SFR、可寻址位、存储器和、可寻址位、存储器和I/O口的定义口的定义 10.4.1 特殊功能寄存器特殊功能寄存器SFR定义定义 C51提供了一种自主形式的定义方式,使用特定关键字sfr 如 sfr SCON=0 x98;/*串行通信控制寄存器地址98H*/sfr TMOD=0 x89;/*定时器模式控制寄存器地址89H*/sfr ACC=0 xe0;/*A累加器地址E0H*/sfr P1=0 x90;/*P1端口地址90H*/定义了以后,程序中就可以直接引用寄存器名。C51也
29、建立了一个头文件reg51.h(增强型为reg52.h),在该文件中对所有的特殊功能寄存器的进行了sfr定义,对特殊功能寄存器的有位名称的可寻址位进行了sbit定义,因此,只要用包含语句#include,就可以直接引用特殊功能寄存器名,或直接引用位名称。要特别注意:在引用时特殊功能寄存器或者位名称必须大写。第3章 51单片机程序设计10.4.2 10.4.2 对位变量的定义对位变量的定义 C51对位变量的定义有三种方法:1.将变量用bit类型的定义符定义为bit类型:如 bit mn;mn为位变量,其值只能是“0”或“1”,其位地址C51自行安排在可位寻址区的bdata区。2.采用字节寻址变量
30、的位的方法:如 bdata int ibase;/*ibase定义为整型变量*/sbit mybit=ibase15;/*mybit定义为ibase的D15位*/这里位是运算符“”相当于汇编中的“”,其后的最大取值依赖于该位所在的字节寻址变量的定义类型,如定义为char最大值只能为7。第3章 51单片机程序设计3.对特殊功能寄存器的位的定义 方法1:使用头文件及sbit定义符;多用于无位名的可寻址位。例如#include sbit P1_1=P11;/*P1-1为P1口的第1位*/sbit ac=ACC7;/*ac定义为累加器A的第7位*/方法2:使用头文件reg51.h,再直接用位名称。例如
31、#include RS1=1;RS0=0;方法3:用字节地址位表示 例如 sbit OV=0 xD02;方法4:用寄存器名.位定义 例如 sfr PSW=0 xd0;/*定义PSW地址为d0H*/sbit CY=PSW7;/*CY为PSW7*/第3章 51单片机程序设计10.4.3 C51对存贮器和外接对存贮器和外接I/O口的绝对地址访问口的绝对地址访问 1.对存贮器的绝对地址访问 利用绝对地址访问的头文件absacc.h可对不同的存贮区进行访问。该头文件的函数有:CBYTE (访问code区字符型)DBYTE (访问data区字符型)PBYTE (访问pdata或I/O区字符型)XBYTE
32、(访问xdata或I/O区字符型)还有CWORD、DWORD、PWORD和XWORD四个函数,它们的访问区域同上,只是访问的类型为int 型。例:#include#define com XBYTE0 x07ff 那么后面程序com变量出现的地方,就是对地址为07ffH的外部RAM或I/O口进行访问。第3章 51单片机程序设计例:XWORD0=0 x9988;即将9988H(int类型)送入外部RAM的0号和1号单元。使用中要注意:absacc.h一定要包含进程序,XBYTE必须大写。2.对外部I/O口的访问 由于单片机的I/O口和外部RAM统一编址,因此对I/O口地址的访问可用XBYTE(MO
33、VX DPTR)或PBYTE(MOVX Ri)进行。例:XBYTE0 xEFFF=0 x10;将10H输出到地址为EFFFH端口 第3章 51单片机程序设计10.5 C51的运算符的运算符 1赋值运算符:将“”的右边的值赋值给左边的变量.2.C51的算术运算符:(加或正号);(减或负号);*(乘号);/(除号);%(求余)优先级为:先乘除,后加减,先括号内,再括号外3.C51的关系运算符有六种:(小于);(大于);=(小于等于);=(大于等于);=(相等);!=(不相等)优先级:前四个高,后二个“=”和“!=”级别低。第3章 51单片机程序设计4C51的逻辑运算符有三种:&(逻辑与);|(逻辑
34、或);!(逻辑非);逻辑表达式和关系表达式的值相同,以0代表假,以1代表真。以上三种运算的优先级见图10.1。5C51的按位操作的运算符有六种:&(按位与);(按位或);(按位异或);(位取反);(位右移)(注:补零移位)例1.a=0 xf0H;表达式a=a值为0FH例2.a=0 xea;表达式a2值为A8H,即a值左移两位,移位后空白位补0。6.自增、自减运算符:+i,-i(在使用i之前,先使i值加1,减1)i+,i-(在使用i之后,再使i值加1.,减1)例设i原值为5 j=+i 则j值为6,i值也为6 j=i+则j值为5,i值为6|非算术运算关系运算&和|=赋值运算图图10-1 运算符的优
35、先级运算符的优先级 第3章 51单片机程序设计7复合赋值运算符:+=;-=;*=;/=;%=;=;&=;=;|=。例:a+=b相当于a=a+b。a=7.相当于a=a 7.。8.对指针操作的运算符:&取地址运算 *间址运算符例 a=&b;取b变量的地址送变量a c=*b;将以b的内容为地址的单元的内容送c这里要注意:“&”与按位与运算符的差别,如果“&”为“与”,&的两边必须为变量或常量;“*”与指针定义时指针前的“*”的差别。如char*pt,这里的“*”只表示pt为指针变量,不代表间址取内容的运算。第3章 51单片机程序设计10.6 函函 数数 C语言程序由函数组成,下面介绍函数的要点。10
36、.6.1 函数的分类及定义 从用户使用角度划分,函数分为库函数和用户自定义函数。库函数是编译系统为用户设计的一系列标准函数(见本书附录二),用户只需调用,而无需自己去编写这些复杂的函数,如前面所用到的头文件reg51.h、absacc.h等,有的头文件中包括一系列函数,要使用其中的函数必须先使用#include包含语句,然后才能调用。用户自定义函数是用户根据任务编写的函数从参数形式上函数分为无参函数和有参函数。有参函数即是在在调用时,调用函数用实际参数代替形式参数,调用完返回结果给调用函数。第3章 51单片机程序设计10.6.2 函数的定义函数的定义 函数以“”开始,以“”结束。无参函数的定义
37、:返回值类型 函数名()函数体语句 如果函数没有返回值,可以将返回值类型设为void。有参函数的定义:返回值类型 函数名(形式参数表列)形式参数类型说明 函数体语句 return(返回形参名)也可以这样定义 返回值类型 函数名(类型说明 形式参数表列)函数体语句 return(返回参形名)其中形式参数表列的各项要用“,”隔开,通过return语句将需返回的值返回给调用函数。第3章 51单片机程序设计10.6.3 函数的调用函数的调用 函数调用的形式为:函数名(实际参数表列);实参和形参的数目相等类型一致,对于无参函数当然不存在实际参数表列。函数的调用方式有三种:函数调用语句:即把被调函数名作为
38、调用函数的一个语句;如fun1()。被调函数作为表达式的运算对象,如 result=2*get(a,b)此时get函数中的a,b应为实参,其以返回值参予式中的运算。被调函数作为另一个数的实际参数 如 m=max(a,get(a,b);函数get(a,b)作为函数max()的一个实际参数。第3章 51单片机程序设计10.6.4对被调函数的说明对被调函数的说明 如果被调函数出现在主调函数之后,在主调函数前应对被调函数作以说明,形式为:返回值类型 被调函数名(形参表列);如果被调函数出现在主调函数之前,可以不对被调函数说明。下面以一个简单例子来说明int fun1(a,b)int a,b;int c
39、;c=a+b;return(c);main()int d,0u=3,v=2;d=2*fun(u,v);上例被调函数在主调函数前,不用说明。第3章 51单片机程序设计int fun1(a,b);main()int d,u=3,v=2;d=2*fun1(u,v);int fun1(a,b);int a,b;int c;c=a+b;return(c);上例中被调函数在主调函数后,在前面对被调函数进行说明。第3章 51单片机程序设计10.7 变量使用变量使用 1.定位变量 经常访问的数据对象放入在片内数据RAM中,这可在任一种模式(COMPACT/LARGE)下用输入存贮器类型的方法实现。访问片内RA
40、M要比访问片外RAM快得多。在片内RAM由寄存器组、位 数据区、栈和其它由用户用“data”类型定义的变量共享。由于片内RAM容量的限制(128 256字节,由使用的处理器决定),必须权衡利弊以解决访问效率和这些对象的数量之间的矛盾。2.只要有可能,使用局部函数变量 编译器总是尝试在寄存器里保持局部变量。这样,将索引变量(如FOR和WHILE循环中计数变 量)声明为局部变量是最好的,这个优化步骤只为局部变量执行。使用“unsigned char/int”的对象通常能获得最好的结果。第3章 51单片机程序设计3.尽可能使用最小数据类型 MCS-51系列单片机是8位机,因此对具有“char”类型的
41、对象的操作比“int”或“long”类型的对象方便得多。建议编程者只要能满足要求,应尽量使用最小数据类型。C51编译器直接支持所有的字节操作,因而如果不是运算符要求,就不作“int”类型的转换,这可用一个乘积运算来说明,两“char”类型对象的乘积与8XX51操作码“MUL AB”刚好相符。如果用整型完成同样的运算,则需调用库函数。4.只要有可能,使用“unsigned”数据类型 8XX51单片机的CPU不直接支持有符号数的运算。因而C51编译必须产生与之相关的更多的代码以解决这个问题。如果使用无符号类型,产生的代码要少得多。第3章 51单片机程序设计二、程序设计阶段二、程序设计阶段1方案制订
42、阶段方案制订阶段l 制订技术开发要求l 制订实现方案,进行技术准备l 评估整个项目开发需要的各方面资源l 评估并确定开发周期第3章 51单片机程序设计2 程序设计阶段程序设计阶段p 程序框架的划分p 各个模块功能的细分p 系统资源的分配p 算法的设计p 程序流程图的绘制第3章 51单片机程序设计3 代码编写阶段代码编写阶段避免笔误,遵守规范u向前兼容原则u相互兼容原则第3章 51单片机程序设计4 程序调试阶段程序调试阶段验证前面的工作,把程序调通(保证程序在各种可能的状态下都能按预期的要求工作)。测试 解决BUG第3章 51单片机程序设计5 程序维护阶段程序维护阶段程序交付后,根据要求进行升级
43、或BUG消除的阶段 养成良好的编程习惯 自觉加强版本管理第3章 51单片机程序设计三、编程思路三、编程思路1 程序基本结构l初始化程序l主程序循环体第3章 51单片机程序设计2 模块化程序结构模块化程序结构第3章 51单片机程序设计3 模块的事件驱动模块的事件驱动p 由于程序是按顺序执行各个模块,而有些模块可能在本次循环中不具备执行的条件。p 可用事件驱动的机制,加快主程序的循环速度,提升整个系统的性能p 给每个模块设置“使能标志”,通过该标志来触发模块第3章 51单片机程序设计4 调度机制调度机制 顺序调度机制:缺点某些重要模块无法得到及时响应 优先调度机制:可让优先级高的模块获得更多更及时
44、的执行机会,缺点是排在末位的模块可能被阻塞第3章 51单片机程序设计5 中断与前后台中断与前后台u轮询调度机制可以应对一般的任务,但遇到紧急事件还是无法保证及时响应,因此引入中断。u把实时性高的时间放在中断中响应,实时性低的任务交给主程序(后台)调度。u极端情况:无中断,自己变现调度程序;中断丰富,全用中断实现。第3章 51单片机程序设计四、如何看代码四、如何看代码p 善用原理图“顺藤摸瓜”大法:顺着程序的流程一边看一边画原理图,一遍看完后,原理图出来了,程序的大体设计思想和设计结构也就凸现出来了。p 建立RAM分配表“按图索骥”大法:将所有的RAM的功能登记下来,当你再看到程序对某个已经登记过的RAM单元操作时,就能猜出大概的功能来。p 模块化“庖丁解牛”大法:看一个8K的大程序是很累人的,而看8个1K的小程序则似乎容易些。缝隙在哪里呢?就在“JMP”、“RET”之类指令的后面。第3章 51单片机程序设计高明者了解他人的编程思想,中庸者学习他人的编程技巧,蠢笨者为了抄袭盗版,无耻者为了解密篡改。