C语言程序设计及仿真调试课件.ppt

上传人:牧羊曲112 文档编号:3865189 上传时间:2023-03-25 格式:PPT 页数:96 大小:3.04MB
返回 下载 相关 举报
C语言程序设计及仿真调试课件.ppt_第1页
第1页 / 共96页
C语言程序设计及仿真调试课件.ppt_第2页
第2页 / 共96页
C语言程序设计及仿真调试课件.ppt_第3页
第3页 / 共96页
C语言程序设计及仿真调试课件.ppt_第4页
第4页 / 共96页
C语言程序设计及仿真调试课件.ppt_第5页
第5页 / 共96页
点击查看更多>>
资源描述

《C语言程序设计及仿真调试课件.ppt》由会员分享,可在线阅读,更多相关《C语言程序设计及仿真调试课件.ppt(96页珍藏版)》请在三一办公上搜索。

1、第五章 单片机的C语言程序设计及仿真调试,disable,任课教师:刘忠国山东大学课程中心网站:http:/stc15系列单片机器件手册等keil vision软件下载及指导手册(Helpvision Help)http:/Software Cx51 编译器用户手册:Cx51编译器-对传统和扩展的8051微处理器的优化的C编译器和库参考,2,第五章 单片机的C语言程序设计及仿真调试,本章学习目标掌握单片机C语言程序中的常用功能掌握Keil C的程序设计掌握IAP15W4K58S4单片机C语言程序调试过程,3,第五章 单片机的C语言程序设计及仿真调试,5.1 C51程序的基本语法5.1.1 关键

2、字 5.1.2 C51程序的一般结构5.1.3 数据类型 5.1.4 运算符和表达式5.2 Keil C51程序的语句5.2.1 表达式语句 5.2.2 条件语句5.2.3 开关语句 5.2.4 循环语句5.2.5 goto、break、continue和return语句 5.3 函数 5.3.1 函数的定义与调用 5.3.2 Keil C51函数5.4 Keil C51库函数5.5 预处理命令5.6 单片机C语言程序框架,4,汇编语言和C语言的选择问题,设计规模较小的嵌入式应用系统时,可以使用汇编语言。因为代码一般不长,且较简单。当程序比较复杂,且没有很好的注释时,使用汇编语言编写的程序,可

3、读性和可维护性会很差,代码的可重用性也比较低。使用C语言编程,编写简单、直观易读、便于维护、通用性好。在控制任务比较复杂或者具有大量运算的系统中,C语言优势明显。由于模块化,用C语言编写的程序具有很好的可移植性。,5,5.1 C51程序的基本语法,1标准C语言(ANSI C)的关键字(1)数据类型关键字 1)基本数据类型 void、char、int、float、double 2)类型修饰关键字 short、long、signed、unsigned 3)复杂类型关键字 struct、union、enum、typedef、sizeof 4)存储级别关键字 auto、static、register、

4、extern、const、volatile,5.1.1 关键字,6,5.1.1 关键字,(2)流程控制关键字1)跳转结构 return、continue、break、goto2)分支结构 if、else、switch、case、default3)循环结构 for、do、while2Keil C51编译器支持的关键字 bit、sbit、sfr、sfr16、data、bdata、idata、pdata、xdata、code、interrupt、reentrant、using,7,预处理命令/以#开头的命令,用于包含头文件、定义常数等全局变量声明/全局变量虽然方便传递参数,但不宜多函数1的声明.函数

5、n的声明void main(void)/主函数 局部变量声明/局部变量只能在所定义的函数内部引用 可执行语句 函数调用 无限循环,5.1.2 C51程序的一般结构,8,/一般函数的定义函数1(形式参数声明)局部变量声明可执行语句.函数n(形式参数声明)局部变量声明可执行语句,5.1.2 C51程序的一般结构,9,/中断函数的实现void ISRname(void)interrupt n/n为中断号 局部变量声明 可执行语句,注意如下几点:(1)所有函数以花括号“”开始,以花括号“”结束,包含在“”内的部分称为函数体。花括号必须成对出现,如果一个函数内有多对花括号,则最外层的花括号为函数体的范围

6、。为了增加程序的可读性,应采用缩进方式书写。,5.1.2 C51程序的一般结构,10,注意如下几点:(2)建议一行写一条语句,每条语句最后必须以一个分号“;”结尾。(3)每个变量必须先定义后引用。在函数内部定义的变量为局部变量,又称为内部变量,只有定义它的那个函数才能使用。在函数外部定义的变量为全局变量,又称为外部变量,在定义它的那个程序文件中的函数都可以使用。(4)程序语句的注释放在双斜杠“/”之后,或者放在“/*.*/”之内。,5.1.2 C51程序的一般结构,11,1常量和变量常量包括整形常量、浮点型常量、字符型常量(如a:单引号字符)及字符串常量(双引号单个或多个字符,如 a,Happ

7、y)等。变量是一种在程序执行过程中其值不断变化的量。使用一个变量之前,必须先进行定义。,5.1.3 数据类型 1常量和变量,2数据类型(1)基本数据类型基本数据类型是不可以再分解为其他类型的数据类型。如char(字符型)、int(整型)、long(长整型)、float(浮点型)等。,12,2数据类型(2)构造数据类型构造数据类型是根据已定义的一个或多个数据类型用构造的方法来定义的。,5.1.3 数据类型 2数据类型,在C语言中,构造类型有以下几种:数组类型结构类型联合类型,13,(3)指针类型指针是一种特殊的,具有重要作用的数据类型。用来表示某个量在内存中的地址。,5.1.3 数据类型 2数据

8、类型,(4)空类型函数调用后并不需要向调用者返回函数值,这种函数可以定义为“空类型”。其类型说明符为void。,14,C51编译器除了支持上述数据类型外,还支持以下几种扩充数据类型:(1)bit:位类型。bit型变量的位地址由编译器分配。(2)sfr:特殊功能寄存器,用来控制中断、定时器、计数器、串口、I/O及其他部件。(3)sfr16:16位特殊功能寄存器。(4)sbit:位寻址。,5.1.3 数据类型 2数据类型,bit与sbit的用法区别:定义的bit型变量的位地址在00H7FH之间,具体地址值不定,由编译器随机分配。sbit位寻址:该数据类型用一个指定的变量作为基地址 然后用其位的位置

9、来得到一个实际的位地址。,15,(1)bit:位类型。可以定义一个位变量,但不能定义位指针,也不能定义位数组。C51程序中,函数参数和返回值也可以是位变量。例:bit finish_flag=0;bit testfunc(bit var1,bit var2).return(0);,5.1.3 数据类型 2数据类型,所有bit型变量的都被定位在8051片内RAM的可位寻址区20H2FH,共16个字节,所以最多只能声明128个bit型位变量。,16,(2)sfr:字节寻址。语法如下:sfr sfr_name=int_constant;如 sfr P0=0 x80;0 x80为P0口的地址,“=”后

10、为常数,且这个常数必须在特殊功能寄存器的地址范围内,即0 x80到0 xFF之间。,5.1.3 数据类型 2数据类型,(3)sfr16:字寻址如sfr16 DPTR=0 x82;指定DPTR的地址DPL=0 x82,DPH=0 x83。(4)sbit:位寻址。用于定义可位寻址变量。可定义8051片内RAM的可寻址位,或特殊功能寄存器的可寻址位。,17,5.1.3 数据类型 2数据类型,(4)sbit:位寻址。定义可位寻址变量。定义片内RAM的可寻址位,或特殊功能寄存器的可寻址位。C51编译器提供了存储类型bdata,bdata存储类型变量位于片内RAM的可位寻址区,可字节寻址,或位寻址,因此b

11、data型变量可用sbit指定其中任意位为可位寻址变量。需注意:使用bdata和sbit定义的变量必须是全局变量,并且用sbit定义为位寻址变量时要求基址对象的存储器类型必须为bdata(特殊功能寄存器除外)。,sbit声明方法:sbit bitname=bdata型变量或sfr_name bit_number;其中,sfr_name 是已定义SFR的名字,bit_number是位号,其数值取决于基址对象的数据类型,对char和SFR 而言是(07),对int型而言是(015),对long型而言是(031)。,18,5.1.3 数据类型 2数据类型,sbit声明方法:sbit bitname=

12、bdata型变量或sfr_name bit_number;其中,sfr_name 是已定义SFR的名字,bit_number是位号,其数值取决于基址对象的数据类型,对char和SFR 而言是(07),对int型而言是(015),对long型而言是(031)。如:unsigned char bdata flag;/flag为bdata型无符号字符变量 int bdata ibase;/定义ibase为bdata整型变量 使用sbit可位寻址变量如下:sbit flag0=flag0;/定义flag0为flag的第0位 sbit mybit15=ibase15;/mybit15为ibase的第15

13、位 sbit CY=PSW7;/定义CY为PSW的第7位 sbit P00=P00;/定义P0.0口线的名称是P00,19,sbit可以有下面声明方法:方法1:sbit bitname=sfr_namebit_number;其中,sfr_name必须是已定义的SFR的名字,bit_number是位号(07)。如:sbit CY=PSW7;/定义CY为PSW的第7位。方法2:sbit bitname=sfr_addressbit_number;其中,sfr_address是SFR所在的地址(0 x800 xff),bit_number是位号(07)。如:sbit OV=0 xD02;/定义PSW

14、中的OV位方法3:sbit bitname=bit_address;其中,bit_address是位地址。如:sbit EA=0 xAF;/第0 xAF位为EA,5.1.3 数据类型 2数据类型,20,Keil C51编译器支持的数据类型如表5-1所示。,表5-1 Keil C51编译器支持的数据类型,5.1.3 数据类型 2数据类型,21,3存储器类型,表5-2 Keil C51编译器支持的存储器类型,对变量定义格式:数据类型 存储器类型 变量名表;,5.1.3 数据类型 3存储器类型,例如:unsigned char data buffer;,22,存储类型的指定:变量或参数的存储类型可由

15、存储模式指定缺省类型,也可由关键字code、data、idata、xdata、pdata直接声明指定。例如:unsigned char data buffer;data buffer;/没有指定数据类型,默认为int型unsigned char code numtab16=0 xC0,0 xF9,0 xA4,0 xB0,0 x99,0 x92,0 x82,0 xFB,0 x80,0 x90,0 x88,0 x83,0 xC6,0 xA1,0 x86,0 x8E;/定义LED显示字模(参见137页)unsigned char xdata arr1044;,5.1.3 数据类型 3存储器类型,对变

16、量定义格式:数据类型 存储器类型 变量名表;,23,5.1.3 数据类型 3.存储器类型,数据存储类型的指定:变量或函数参数存储类型可由存储模式(Small,large,Compact)(Options for Target Target 1.选项)指定缺省存储类型;在small模式下,函数参数和局部变量位于由data定义的单片机片内数据RAM(007FH)中;在compact模式下,函数参数和局部变量位于pdata定义的扩展数据RAM中(访问用MOVX Ri)。在large模式下,函数参数和局部变量位于xdata定义的扩展数据RAM中(访问用MOVX DPTR),数据,存储模式(Small,

17、large,Compact),24,在Xtal(MHz)右侧框输入6,其余按默认设置。,4-3 汇编语言程序调试,Project窗口,选中Target 1,并单击右键,出现浮动菜单。浮动菜单中选中 Options for Target Target 1.选项。,出现Options for Target Target 1 对话框界面。在该界面中,点击Target标签。在该标签界面中,按下面设置参数:,在此设置使用晶振的频率,针对目标硬件设置工具选项,Memory Model右侧下拉选择:Small,Compact,large 的存储模式。,25,4关于指针数据类型指针变量的值是一个地址,这个地址

18、不仅可以是变量的地址,也可以是其他数据结构的地址。Keil C51编译器支持两种指针类型:一般指针(Generic Pointer)和存储器指针(Memory Specific Pointer,指定存储区指针)。一般指针的声明和使用均与标准C相同,同时还可以说明指针的存储类型(见下页)。char*s;/*string ptr*/int*numptr;/*int ptr*/,5.1.3 数据类型 4关于指针数据类型,26,一般指针的声明和使用均与标准C相同,同时还可以说明指针的存储类型。char*s;/*string ptr*/int*numptr;/*int ptr*/可用存储类型标识符指定一

19、个通用指针的存储区如:char*xdata strptr;/*generic ptr stored in xdata*/int*data numptr;/*generic ptr stored in data*/long*idata varptr;/*generic ptr stored in idata*/这些例子指向可能保存在任何存储区中的变量 但是 指针分别保存在xdata、data和idata中。,5.1.3 数据类型 4关于指针数据类型,27,一般指针用3个字节存放:存储器类型,存储器地址高8位偏移量和低8位偏移量。char data*str;/str指向data区中char型数据

20、int xdata*pow;/pow指向外部RAM的int型整数这种指针存放时,只需1(或2)个字节就够了,因只需存放偏移量。,存储器指针(指定存储区指针),说明时即指定了存储类型,例如:,4.关于指针数据类型,存放数据的存储器类型,存储器类型是在编译时需要的,既已指出,所以指针只需存偏移量即可,参考:Keil Help:Cx51 Compiler Users GuideLanguage Extensions Pointers,28,5.1.3 数据类型 4.关于指针数据类型,象一般指针一样 可指定一个存储器指针的保存存储区,即在指针声明前加存储类型标识符,例如:unsigned char x

21、data*pt;/pt本身依存储模式存放unsigned char xdata*data pt;/pt被保存在内部RAM中unsigned char xdata*xdata pt;/pt被保存在外部RAM中上面的语句都声明pt为指向保存在外部RAM中unsigned char数据的指针,但pt本身的保存位置却不同。,存储器指针,29,运算符是告诉编译程序执行特定算术或逻辑操作的符号,表达式则是由运算符及运算对象所组成的具有特定含义的一个式子。在任意一个表达式的后面加一个分号“;”就构成了一个表达式语句。C51程序就是由多个表达式语句构成的语句集合。运算符可以分为赋值运算符、算术运算符、关系运算

22、符、逻辑运算符、位运算符、复合赋值运算符、逗号运算符、条件运算符、指针和地址运算符、强制类型转换运算符等。,5.1.4 运算符和表达式,30,1赋值运算符符号“=”为赋值运算符,它的作用是将一个数据的值或表达式的值赋给一个变量。利用赋值运算符将一个变量与一个表达式连接起来的式子成为赋值表达式,在赋值表达式的后面加一个分号“;”便构成了赋值语句。,5.1.4 运算符和表达式 1赋值运算符,31,2算术运算符算术运算符用于各类数值运算。包括加(+)、减或取负值(-)、乘(*)、除(/)、取余(或称模运算,%)、自增(+)、自减(-)共七种。在除法运算中,如果是两个整数相除,其结果为整数,舍去小数部

23、分。用算术运算符将运算对象连接起来的式子就是算术表达式。,5.1.4 运算符和表达式 2算术运算符,32,计算一个算术表达式的值时,要按照运算符的优先级高低顺序进行。算术运算符中,取负值(-)的优先级最高,其次是乘法(*)、除法(/)和取余(%)运算符,加法(+)和减法(-)运算符的优先级最低。需要时,可在算术表达式中必要的地方采用圆括号来改变优先级,括号的优先级最高。在使用自增(+)运算符和自减(-)运算符时,要注意运算符的位置。例如,+i和i+的意义完全不同,前者为在使用i之前先使i加1,而后者则是在使用i之后再使i加1。在实际应用中,尽可能使用后者的方式,即i+的形式。,5.1.4 运算

24、符和表达式 2算术运算符,33,3关系运算符关系运算符用于比较运算。包括大于()、小于(=)、小于等于(=)、等于(=)和不等于(!=)六种。前四种关系运算符具有相同的优先级,后两种关系运算符也具有相同的优先级;但前四种的优先级高于后两种。用关系运算符将两个表达式连接起来即构成关系表达式。,5.1.4 运算符和表达式 3关系运算符,34,4逻辑运算符逻辑运算符包括与(&)、或(|)、非(!)3种,用于对包含关系运算符的表达式(称为条件)进行合并或取非运算。关系运算符和逻辑运算符通常用来判别某个或某些条件是否满足,条件满足时结果为1,条件不满足时结果为0。,5.1.4 运算符和表达式 4逻辑运算

25、符,35,与运算符(&)表示2个条件同时满足时(即2个条件都为真时),返回结果才为真。或运算符(|)用于检查2个条件中是否有1个为真的运算符,只要有1个条件为真,运算结果就为真。逻辑非运算符(!)表示对表达式的值取反。上述几种运算符的优先级依次为(由高到低):逻辑非算术运算符关系运算符逻辑与逻辑或。,5.1.4 运算符和表达式 4逻辑运算符,36,5位运算符语言提供了6种位运算符:按位与(&)、按位或(|)、按位异或()、取反()、左移()。位运算符的优先级从高到低依次为:按位取反()左移()和右移()按位与(&)按位异或()按位或(|)。,5.1.4 运算符和表达式 5位运算符,其功能是参与

26、运算的两数各对应的二进位进行如下运算:,37,(1)按位与运算按位与运算符“&”是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的2个二进位均为1时,结果位才为1,否则为0。(2)按位或运算按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的2个二进位有1个为1时,结果位就为1。,5.1.4 运算符和表达式 5位运算符,38,(3)按位异或运算按位异或运算符“”是双目运算符。其功能是参与运算的两数各对应的二进位相异或。当2个对应的二进位相异时,结果为1。(4)求反运算求反运算符“”为单目运算符,具有右结合性。其功能是对参与运算的数的各二进位按位求

27、反。,5.1.4 运算符和表达式 5位运算符,39,(5)左移运算左移运算符“”是双目运算符。其功能是把“”左边的运算数的各二进位全部右移若干位,“”右边的数指定移动的位数。对于有符号数,右移时,符号位将随同移动。当为正数时,最高位补0;为负数时,符号位为1,最高位补1。,5.1.4 运算符和表达式 5位运算符,40,6复合赋值运算符在赋值运算符“=”之前加上其他二目运算符可构成复合赋值运算符。构成复合赋值表达式的一般形式为:变量 双目运算符=表达式它等效于:变量=变量 运算符 表达式复合赋值运算符有:+=,-=,*=,=,%=,=,&=,=,=,|=。,5.1.4 运算符和表达式 6复合赋值

28、运算符,41,7逗号运算符逗号运算符用于把若干表达式组合成一个表达式(称为逗号表达式)。程序运行时,对于逗号表达式的处理,是从左至右依次计算出各个表达式的值,而整个逗号表达式的值是最右边表达式的值。例如:int a1,a2,b=2,c=7,d=5;/第1行a1=(+b,c-,d+3);/第2行,a1的值为8a2=+b,c-,d+3;/第3行,a2的值为4,5.1.4 运算符和表达式 7逗号运算符,42,8条件运算符条件运算符(?:)是一个三目运算符,用于条件求值。它要求有三个运算对象,使用它可以将三个表达式连接构成一个条件表达式。条件表达式的一般形式为:逻辑表达式?表达式1:表达式2其功能是,

29、首先计算逻辑表达式的值,当逻辑表达式的值为真(非0值)时,将表达式1的值作为整个条件表达式的值;当逻辑表达式的值为假(0值)时,将表达式2的值作为整个条件表达式的值。,5.1.4 运算符和表达式 8条件运算符,43,9指针和地址运算符变量的指针就是该变量的地址,而存放变量地址的变量称为指针变量。为表示指针变量和它所指向的变量地址之间的关系,C语言有运算符:取内容(*)和取地址(&),其运算的一般形式分别为:变量=*指针变量指针变量=&目标变量取内容(*)运算的含义是将指针变量所指向的目标变量的值赋给等号(=)左边的变量;取地址(&)运算的含义是将目标变量的地址赋给等号(=)左边的指针变量。,5

30、.1.4 运算符和表达式 9指针和地址运算符,44,unsigned char*txp;unsigned char txbuffer50;txp=txbuffer;,例,使用指针可以进行外部扩展I/O口的访问。在C51中有两种方法访问外部I/O端口。方法1:使用自定义指针。由于片外I/O端口与片外存储器统一编址,所以可以定义xdata类型的指针访问外部I/O端口。例如,某单片机应用系统中,使用8255(见第1版8.3节)扩展I/O端口,采用线选法对8255进行地址译码,单片机的P2.7(A15)接8255的片选引脚,因8255的命令口地址为7FF3H,PA口地址为7FF0H,PB口地址为7FF

31、1H,PC口地址为7FFF2H。访问8255的C程序如下:,5.1.4 运算符和表达式 9指针和地址运算符,45,8255因目前停产较少用,本版教材不再介绍(用法见第1版8.3节),方法1:使用自定义指针访问外部扩展I/O口,写端口程序:char xdata*com8255;/定义指向外部存储区(片外I/O端口)的指针 com8255=0 x7ff3;/使指针指向8255的控制口(命令口)地址7FF3H*com8255=0 x81;/输出命令字81H到命令口寄存器/81H:PA,PB口都是模式0,直接输出,PC口直接输入以上C程序相当于下面的汇编语言程序:MOV DPTR,#7FF3H MOV

32、 A,#81H MOVX DPTR,A,具体命令介绍见见第1版8.3节:并行接口扩展方法,309页图8-52,46,方法1:使用自定义指针访问外部扩展I/O口,读端口程序:char xdata*com8255;/定义指针 char i;com8255=0 x7FF0;/使指针指向8255的PA口地址7FF0H i=*com8255;/读PA端口内容到变量 i,47,5.1.4 运算符和表达式 9指针和地址运算符,为了方便访问外部存储器及I/O端口,在C51的absacc.h头文件做了如下定义,利用这些定义可以方便地访问外部I/O端口。#define CBYTE(unsigned char vo

33、latile code*)0)#define DBYTE(unsigned char volatile data*)0)#define PBYTE(unsigned char volatile pdata*)0)#define XBYTE(unsigned char volatile xdata*)0),volatile修饰了的变量随程序的执行其值会被改变,“易变”,方法2:使用C51预定义指针访问外部扩展I/O口,48,#define XBYTE(unsigned char volatile xdata*)0)以XBYTE为例介绍上述宏定义使用方法,XBYTE使用格式:XBYTE 地址,方法

34、2:使用C51预定义指针访问外部扩展I/O口,例如:#include#define PORTA XBYTE0 x7ff0/其中,PORTA为程序定义的I/O端口名称,内的内容/7ff0H为PORTA的地址void main(void)char a;PORTA=0 x81;/*输出81H到端口7ff0H a=PORTA;/读端口7ff0H到变量a,定义XBYTE数组的首地址是0,XBYTE 0 x7ff0的中括号内的值0 x7ff0,指出了(定义)数组XBYTE首地址的偏移地址,49,10强制类型转换运算符强制类型转换运算符的作用是将表达式或变量的类型强制转换成为括号内所指定的类型。强制类型转换

35、运算符的一般使用形式为:变量=(类型)表达式如:pxdata=(char xdata*)0 x3000;/pxdata为在xdata中定义的char类型指针变量,5.1.4 运算符和表达式 10强制类型转换运算符,50,表达式语句是最基本的一种语句。在表达式的后面加一个分号“;”就构成了表达式语句。表达式语句也可以仅由一个分号“;”构成,这种语句称为空语句。空语句不执行具体的动作。程序设计时,有时需要用到空语句。例如,使用循环语句延时程序中的循环体内可以使用空语句。,5.2 Keil C51程序的语句,5.2.1 表达式语句,51,条件语句又称为分支语句,使用关键字“if”构成。C51提供了三

36、种形式的条件语句。1if(条件表达式)语句体;,5.2.2 条件语句,52,2 if(条件表达式)语句体1;else 语句体2;,3.if(条件表达式1)语句体1;else if(条件表达式2)语句体2;,else if(条件表达式m)语句体m;Else 语句体n;,5.2.2 条件语句,53,开关语句也是一种用来实现多条件分支的语句。,case 常量表达式n:语句体n;break;default:语句体d,5.2.3 开关语句,54,switch(表达式)case 常量表达式1:语句体1;break;case 常量表达式2:语句体2;break;,1while语句利用while语句构成循环结

37、构的一般形式如下:while(条件表达式)语句体;,5.2.4 循环语句,55,2do-while语句采用do-while语句构成循环结构的一般形式如下:do 语句体;while(条件表达式);,3for语句采用for语句构成循环结构的一般形式如下:for(初值设定表达式;循环条件表达式;更新表达式)语句体;,5.2.4 循环语句,56,goto语句是一个无条件转向语句,其一般形式为:goto 语句标号;break语句也可以用于跳出循环语句,其一般形式为:break;continue是一种中断语句,其功能是中断本次循环,继续下一次循环,一般形式为:continue;return语句用于终止函数

38、的执行,并控制程序返回到调用该函数的位置。一般形式为:return(表达式);return;,5.2.5 goto、break、continue和return语句,57,两种函数:Keil C51定义的标准库函数和用户自定义函数。,5.3.1 函数的定义与调用,5.3 函数,58,函数定义的一般形式为:函数返回值类型 函数名(形式参数表)局部变量定义 函数体语句函数调用的一般形式为:变量=函数名(实际参数表),5.3.2 Keil C51函数,C51的函数声明对ANSI C作了扩展,具体包括:1、中断函数声明,中断函数通过使用interrupt关键字和中断号(031)来声明。中断号告诉编译器中

39、断服务程序入口地址。,IAP15W4K58S4单片机的中断号及中断服务程序入口地址如表5-3,59,中断服务函数的一般形式为:void 函数名(void)interrupt 中断号 using n中断函数通过使用interrupt关键字和中断号来声明。中断号告诉编译器中断服务程序的入口地址。也就是说,C51通过中断号来区分各个不同的中断,而与中断函数的名字无关。其中using n用于选择单片机不同的寄存器组,n为03的常整型数,分别选中4个不同寄存器组中的一个。Using是一个可选项,可以不用。不用时,由编译器自动选择一个寄存器组。,60/78,5.3.2 Keil C51函数 1、中断函数声

40、明,5.3.2 Keil C51函数 1、中断函数声明,例如,串行口1的中断函数(4号中断)可以声明如下:void UART1_ISR(void)interrupt 4 using 1/*中断服务程序的代码*/上述代码声明了串行口1中断服务函数。其中,interrupt 4指明是串行口1的中断,using 1指明采用工作寄存器区1区,using 1在中括号中,说明该部分可省略。其他中断函数的定义与此类似。中断函数具体是哪个中断的函数,与中断号有关,而与函数名(如UART1_ISR)无关,但一般赋予与相应中断相符合的名称。,无输入参数,无返回参数,61,5.3.2 Keil C51函数-2、指定

41、工作寄存器区,当需要指定函数中使用的工作寄存器区时,使用关键字using后跟一个0到3的数,对应着工作寄存器0到3区。例如,在下面的函数中使用了工作寄存器1区(相当于PSW.4=0,PSW.3=1):unsigned char GetKey(void)using 1/*用户程序代码*/,指定工作寄存器区,62,程序状态标志寄存器PSW(8位),RS1,RS0(PSW.4PSW.3):工作寄存器组选择控制位,其详细介绍见后续内容。OV(PSW.2):溢出标志位。指示运算过程中是否发生了溢出,在执行指令过程中自动形成。,RS1,RS0,OV,P(PSW.0):奇偶标志位 累加器ACC中1的个数为偶

42、数,P=0;否则P=1。每个指令周期都由硬件来置“1”或清“0”。在具有奇偶校验的串行数据通信中,可根据P设置奇偶校验位。,P,63,工作寄存器组的选择:,PSW寄存器中的RS1和RS0两位组合决定当前使用的工作寄存器组。可通过位操作指令修改RS1和RS0的内容,选择不同的工作寄存器组。,表3-1 工作寄存器组选择,64,5.3.2 Keil C51函数2、指定存储模式,用户可以使用small,compact 及large说明存储模式。例如:void fun1(void)small 提示:small说明的函数内部变量全部使用内部RAM。关键的、经常性的、耗时的地方可以这样声明,以提高运行速度。

43、,2、指定存储模式,65,用compact说明时,函数参数和局部变量位于pdata定义的扩展数据RAM中。用large说明时,函数参数和局部变量位于xdata定义的扩展数据RAM中。,5.3.2 Keil C51函数3、函数的重入,一个可重入函数,简单来说,就是可以被中断的函数,即可以在这个函数执行的任何时刻中断它,可重入函数可以被递归调用。递归或可重入函数在单片机系统中容易产生问题,因为单片机和PC不同,PC使用(调用)堆栈传递参数,且静态变量以外的内部变量都在堆栈中;而单片机一般使用寄存器传递参数,内部变量一般在固定的RAM中,函数重入时会破坏(覆盖)上次调用的数据。可在函数前声明函数的不

44、可重入性(不可中断性)。若声明为不可重入(中断)的,则该函数调用过程中将不可被中断。,typedef unsigned char uchar;#pragma disable/*Disable Interrupts*/uchar dfunc(uchar p1,uchar p2)return(p1*p2+p2*p1);,66,(#pragma的作用是设定编译器的状态或者指示编译器完成一些特定的动作),5.3.2 Keil C51函数3、函数的重入,可用以下两种方法解决函数的重入(及不可中断)问题:第一种方法:在相应的函数前使用“#pragma disable”声明,即只允许主程序或中断之一调用该函

45、数(函数调用后不再被中断)。第二种方法:将该函数说明为可重入的。如下:void func(param.)reentrant.;,因为单片机内部堆栈空间的限制,C51没有像大系统那样使用调用堆栈:一般在C语言中调用过程时,会把过程的参数和过程中使用的局部变量入栈。Keil C51编译后将生成一个可重入变量堆栈,然后就可以模拟通过调用堆栈传递变量的方法。,67,这样函数重入时,不用担心变量数据被覆盖的问题。,5.3.2 Keil C51函数3、函数的重入,为了提高效率,C51没有提供这种调用堆栈,而是提供一种压缩栈。每个过程被给定同一个空间,用于存放局部变量。过程中的每个变量都存放在这个空间的固定

46、位置。当递归调用这个过程时,会导致变量被覆盖。在某些实时应用中,非重入函数是不可取的。因为,函数调用时可能会被中断程序中断,而在中断程序中可能再次调用这个函数,所以C51允许将函数定义成重入函数。重入函数可被递归调用和多重调用,而不用担心变量被覆盖,因C51可模拟生成一个可重入变量堆栈 随存储模式(small,compact,large)不同,堆栈可在不同的存储器区(idata,pdata,xdata),每次函数调用时的局部变量都会被单独保存。因为这些堆栈是模拟的,重入函数一般都比较大,运行起来也比较慢。,不常使用,68,5.3.2 Keil C51函数3、函数的重入,由于一般可重入函数由主程

47、序和中断调用(即递归调用),所以通常中断程序使用与主程序不同的工作寄存器组。另外,对可重入函数,在相应的函数前面加上开关#pragma noaregs,以禁止编译器使用绝对寄存器寻址,可生成不依赖于寄存器组的代码。所以对不依赖于寄存器组的函数可被其他使用了不同的寄存器组的多个函数调用。,extern char func();#pragma NOAREGSnoaregfunc()k=func()+func();#pragma AREGSaregfunc()using 3 k=noaregfunc()+func();,不常使用,69,本征库函数是指编译时直接将固定的代码插入到当前行,而不是用汇编语

48、言中的ACALL和LCALL指令实现调用,从而大大提高函数的访问效率。非本征库函数则必须由ACALL和LCALL指令实现调用。Keil C51提供了9个本征库函数,如表5-4所示。使用本征库函数时,须在源程序中包含头文件(含有函数原型声明),即用预处理命令#include。,5.4.1 本征库函数,5.4 Keil C51库函数,70,表5-4 Keil C51编译器提供的本征库函数,5.4.1 本征库函数,71,_chkfloat_函数返回一个unsigned char值包含下面的状态信息:返回值 意义0 标准浮点数1 浮点数02+INF 正溢出3-INF 负溢出4 NaN(不是一个数)错误

49、状态,5.4 Keil C51库函数 5.4.2 字符判断转换库函数(表5-5),72,字符判断转换库函数的原型声明在头文件CTYPE.H中定义。,5.4 Keil C51库函数 5.4.2 字符判断转换库函数(表5-5),73,(续表),表5-6 输入/输出库函数,5.4 Keil C51库函数 5.4.3 输入/输出库函数(表5-6),74,表5-6 输入/输出库函数(续表),5.4 Keil C51库函数 5.4.3 输入/输出库函数(表5-6),75,输入/输出库函数的原型声明在头文件STDIO.H,通过8051内核单片机的串行口工作,若希望支持其他I/O接口,只需改动_getkey(

50、)和putchar(),库中所有其他I/O支持函数都依赖于这两个函数模块。在使用8051系列单片机的串行口之前,应先对其进行初始化。例,晶振频率11.0592MHz,若串口1通信的参数为9600,n,8,1(9600波特率,8个数据位,1个停止位,没有奇偶校验位),则初始化语句:void UartInit(void)/9600bps11.0592MHz SCON=0 x50;/8位数据,可变波特率AUXR/直接使用printf必须加入此句才能实现发送,5.4 Keil C51库函数 5.4.3 输入/输出库函数(表5-6略),76,例如:_getkey()函数的定义(在Keil安装文件夹LIB

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号