版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、4.1 C51程序的结构特点4.2 C51语法根底 4.3 C51的数据类型、存储类型及常量与变量 4.4 C51对单片机主要资源的定义4.5 C51的根本运算4.6 C51的构造数据类型4.7 C51的流程构造语句4.8 C51的函数4.9 指针4.10 C51程序设计举例实训四:单片机控制流水灯(C51程序)实训五:计数器的C51程序设计与制作小结习题与思考题4.1 C51程序的结构特点 4.1.1 C语言与汇编语言的比较 单片机的C51编程与汇编语言编程相比,具有以下优点。1对单片机的指令系统不要求有任何的了解,就可以用C语言直接编程操作单片机。2存放器分配、不同存储器的寻址以及数据类型
2、等细节完全由编译器自动管理。3程序有标准的结构,可分成不同的函数,可使程序结构化。4库中包含许多标准函数,具有较强的数据处理能力,使用十分方便。5具有方便的模块化编程技术,使已编好的程序很容易移植。4.1.2 C51程序的结构特点 举例: 设单片机AT89C51的P1.0口接有一个发光二极管,如图4-1所示。试用C51编程使该发光二极管间隔1s亮灭闪动。LEDVccAT89C51 P1.0R1图4-1 驱动发光二极管#include /包含51系列单片机头文件#define uint unsigned int /宏定义sbit led1 = P10; /声明单片机P1口的第一位void del
3、aymsuint; /声明延时子函数void main () /主函数 While1 /大循环 led1= 0; /*点亮接在P1.0引脚上的LED*/ delayms1000; /延时1秒 led1= 1; /*关闭接在P1.0引脚上的LED*/ delayms1000; /延时1秒 void delaymsuint xms/延时x毫秒子函数 uint i,j; fori=xms;i0;i-/*i=xms即延时约xms毫秒*/ forj110;j;j-; 由以上例子可看出C51程序结构具有以下特点:1C 语言程序是由函数构成的。2一个函数由两部份组成。函数首部,即函数的第一行。函数体,即函数
4、首部下面的大括号“内的局部。函数体一般包括:a声明局部:在这局部中定义所用到的变量,如“sbit led1 = P10;。b执行局部:由假设干个语句组成。3一个C语言程序,总是从main ()函数开始执行的,而不管物理位置上这个main ()放在什么地方。4C语言源程序的前面几行通常是以“#开头的预处理命令。预处理命令包括文件包含include命令、宏define命令以及条件编译命令等。5C 语言区分大小写。如将“include写成“INCLUDE就会编译出错。6C 语言书写的格式自由,可以在一行写多个语句,也可以把一个语句写在多行。7每个语句和资料定义的最后必须有一个分号“;,分号“;是C语
5、句的必要组成局部,即语句结束标志。但预处理命令、函数头和花括号“之后不能加分号“;。8可以用/*/的形式为C程序的任何一局部作注释。 C51也支持C+风格的注释,即用“/引导的后面的语句是注释。例如: P1_0 = !P1_0; /取反P1.0 这种风格的注释,只对本行有效,所以不会出现上面的问题,而且书写也比较方便。因此,程序在只需要一行注释的时候,建议采用这种格式。9一个C语言源程序可以由一个或多个源文件组成。4.2 C51语法根底 4. 2. 1 C语言词汇1标识符 在程序中使用的变量名、函数名、标号等统称为标识符。C语言规定,标识符只能是字母AZ,az、数字09、下划线_组成的字符串,
6、并且第一个字符必须是字母或下划线。标准C语言不限制标识符的长度,但它受各种版本的C语言编译系统限制,同时也受到具体机器的限制。在标识符中,大小写是有区别的。标识符虽然可由程序员随意定义,但标识符是用于标识某个量的符号。标识符不能使用系统保存的关键字。2关键字也叫保存字数据类型关键字。用于定义或说明变量、函数或其他数据结构的类型。主要有char,double,float,int,long,short,signed,struct,union,unsigned,void,enum等12个。控制语句关键字。用于表示一个语句的功能。主要有break,case,continue,default,do,el
7、se,for,goto,if,return,switch,while等12个。存储类型关键字。用于说明变量或函数的存储类型。主要有auto,extern,register,static等4个。预处理命令关键字。用于表示一个处理命令。主要有include、define等2个。其他关键字。主要有const,sizeof,typedef,volatile等4个。3运算符 C语言中含有相当丰富的运算符。如强制类型转换运算符、算术运算符、关系运算符、逻辑运算符以及位运算符等。运算符与变量、函数一起组成表达式,表示各种运算功能。运算符由一个或多个字符组成。4分隔符 逗号分隔符。 空格分隔符。4. 2. 2
8、 编译预处理 编译预处理命令概念:计算机将C语言编译为机器语言时进行的预处理。这些命令只在编译时有效,不是计算机运行的可执行语句。编译预处理命令以“#开头,末尾不加分号,包括头宏命令、文件包含命令、条件编译命令等。 1宏命令 作用:用标识符来代表一个字符串,系统在编译之前自动将标识符替换为字符串。主要用于定义常量。宏定义的标识符常量一般用大写字母,以便与变量相区别。 定义形式:#define 标识符 字符串 例如:#define PI 3.14 /*后续程序中所有的PI都用3.14代替。即但凡出现PI的地方即表示3.14,这样做有利于阅读程序和修改程序。*/2文件包含 文件包含:指在一个文件中
9、将另一个文件的全部内容包含进来,通常用来将程序中用到的系统函数、宏标识符、自定义函数等的文件包含进来。被包含的文件也叫头文件以“.h为扩展名的文件。 格式:#include或#include“文件名在Keil C51中常用的包含文件头文件有以下三种: reg51.h头文件。reg51.h是对51子系列单片机的特殊功能存放器进行定义的头文件,使用汇编语言中的特殊功能存放器名称,将各个特殊功能存放器定义为该存放器的直接地址,在C语言中可以通过存放器名称直接对这些存放器进行操作,特殊功能存放器名称全部使用大写。reg51.h没有对单片机的四个输入输出端口进行位定义,如果程序中需要对并行端口进行位操作
10、,可以使用regx51.h。对于52系列单片机,相应的头文件为reg52.h或regx52.h。stdio.h头文件。stdio.h是标准输入输出库函数头文件。该库函数文件是定义计算机键盘输入与计算机屏幕显示的库函数,单片机本身无需这些库函数,但为了方便利用计算机调试程序,需要包含该头文件。常用的标准输入、输出库函数有以下两种:aprintf格式控制,输出列表;。该函数按指定格式在屏幕上显示对应输出项的值。bscanf格式控制,地址列表;。该函数接收计算机键盘输入的数据并赋值给对应的变量。例如: int x=3;char y3=“abc; printf“x=%d,y=%3sn,x,y; sca
11、nf“%d,%cn,&x,&y; printf“x=%d,y=%3sn,x,y;其中,格式控制必须包含在一对双引号内,包括格式说明符%d、普通字符x=,y=和转义控制符n三种类型。格式说明符前必须用百分号“%。常用的格式说明符的含义如表4-1所示。表4-1 常用格式字符的含义格式字符说明附加格式字符说明d带符号的十六进制数m数据长度s字符串n截取字符的个数c一个字符f小数形式的实数nn位小数 常用的转义控制符有两个:n:换行。r:回车。他的前必须用反斜杠“。 再如,在计算机屏幕上打印99乘法口诀表。参考程序如下所示:/*cfb.c*/#include /包含51系列单片机头文件#include
12、 /包含根本输入、输出头文件void cominit() /设置定时器、串行通信函数 SCON=0 x50; /设置串行口控制存放器 TMOD|=0 x20; /设置定时器方式存放器 TH1=0 xf3; /设置定时器1T1高8位的初值 TR1=1; /启动定时器1 TI=1; /置位发送标志位void main(void) /主函数 unsigned int i,j; /定义无符号整型变量i与j cominit(); /调用设置定时器、串行通信函数 for(i=1;i=9;i+) /外循环 for(j=1;j=i;j+) /内循环printf(%dX%d=%d ,j,i,i*j); /计算机
13、屏幕上打印一行乘法口诀表printf(n); /换行打印 在keil C51中,为了借助计算机键盘与屏幕调试程序,需要模拟单片机串行口与计算机键盘与计算机屏幕进行通信。因而需要设置定时器/计数器与串行通信,“void cominit()函数就是为此目的而写的。程序调试运行结果如下所示: 1X1=1 1X2=2 2X2=4 1X3=3 2X3=6 3X3=9 1X4=4 2X4=8 3X4=12 4X4=16 1X5=5 2X5=10 3X5=15 4X5=20 5X5=25 1X6=6 2X6=12 3X6=18 4X6=24 5X6=30 6X6=36 1X7=7 2X7=14 3X7=21
14、 4X7=28 5X7=35 6X7=42 7X7=49 1X8=8 2X8=16 3X8=24 4X8=32 5X8=40 6X8=48 7X8=56 8X8=64 1X9=9 2X9=18 3X9=27 4X9=36 5X9=45 6X9=54 7X9=63 8X9=72 9X9=81 用户自定义标题文件。用户将自己常用的宏定义、条件编译、图片代码、数据表格等组成一个文件,然后在各个源程序中用“#include命令包含进来,无需重复定义。4.3 C51的数据类型、存储类型及常量与变量 4.3.1 C51的数据类型 C51的数据类型大体上可以分为根本数据类型、构造数据类型和空类型等三种。其中
15、根本数据类型又可分为位型、无符号字符型、有符号字符型、无符号整型、有符号整型、无符号长整型、有符号长整型、浮点型及双精度实型等九种类型。它们的符号、长度、值域等如表4-2所示。表4-2 C51的数据类型数据类型数据类型名称长度/bit长度/Byte表示数的范围bit或sbit位型10,1unsigned char无符号字符型810255signed char有符号字符型81-128+127unsigned int无符号整型162065535signed int有符号整型162-32768+32767unsigned long无符号长整型32404294967295(0232-1)signed
16、long有符号长整型324-2147483648+2147483647(-231231-1)float单精度实型(浮点型)3243.4e -383.4e+38(相当于6位有效数字)double双精度实型6481.7e-381.7e+38(相当于10位有效数字)4.3.2 C51的数据存储类型(1)数据存储类型 C51允许将变量或常量定义成不同的存储类型,以使单片机访问不同的存储空间。主要包括片内直接寻址型、片内位寻址型、片内间接寻址型、片外分页寻址型、片外间接寻址型以及代码型等六种类型,它们和单片机的不同存储区相对应。如表4-3所示。表4-3 C51存储类型与MCS-51单片机存储空间的对应关
17、系存储类型存储类型名称长度/bit长度/Byte值域范围与MCS-51单片机存储空间的对应关系data片内直接寻址型810255直接寻址片内低128字节数据存储器RAMbdata片内位寻址型813247按位或字节寻址片内RAM的20H2FH地址空间idata片内间接寻址型810255间接寻址片内RAM的00HFFH地址空间pdata片外分页寻址型810255分页寻址256字节片外RAM,对应MOVX Rixdata片外间接寻址型162065535寻址64K字节片外RAM,对应MOVX DPTRcode代码型162065535寻址64K字节ROM,对应MOVC DPTR (2)变量存储类型定义举
18、例变量的存储类型通常与数据类型一起使用。先说明数据类型,再说明存储类型。现举例如下:char data var1; /字符型变量var1被定义为data型,被分配在片内RAM中的低128字节中。bit bdata flags; /位变量flags被定义为bdata型,定位在片内RAM中的位寻址区。float idata x,y,z; /*浮点型变量x、y和z被定义为idata存储类型,定位在片内RAM中,并只能用间接寻址方式进行访问。*/unsigned int pdata dimension; /*无符号整型变量dimension被定义为pdata型,定位在片外数据存储区,相当于用MOVX
19、Ri访问。*/unsigned char xdata vector1044; /*无符号字符型三维数组变量vector1044 被定义为xdata存储类型,定位在片外RAM中,占据1044=160个字节,相当于用MOVX DPTR访问。*/ 3存储模式如果在变量定义时略去存储类型标志符,那么由编译器如Keil C51自动默认存储类型。默认的存储类型进一步由SMALL、COMPACT和LARGE存储模式指令限制。存储模式的有关说明如表4-4所示。表4-4 存储模式及说明存储模式模式名称说 明SMALL小模式参数及局部变量放入可直接寻址的片内存储器(最大128字节,默认存储类型是data),因此访
20、问十分方便。另外所有对象,包括栈,都必须嵌入片内RAM。栈长很关键,因为实际栈长依赖于不同函数的嵌套层数。COMPACT一般模式(中模式)参数及局部变量放入分页片外存储区(最大256字节,默认存储类型是pdata),通过寄存器R0和R1间接寻址,栈空间位于内部数据存储器中。LARGE大模式参数及局部变量直接放入片外数据存储区(最大64KB字节,默认存储类型是xdata),使用数据指针DPTR来进行寻址。用此数据指针访问的效率低,尤其是对二个或多个字节的变量,这种数据类型的访问机制直接影响代码的长度,另一个不便之处在于这种数据指针不能对称操作。4.3.3 常量与变量1常量在程序运行过程中,其值不
21、能被改变的量称为常量,如数字、字符等。每种数据类型的数值都有常量。字符型常量用单引号括起来,字符串常量用双引号括起来,十六进制数常量用“0 x+数值表示。直接常量也叫字面常量。如12、0、0 xCE、A、“GUI ZHOU等。符号常量。符号常量即是用一个标识符来代替一个常量。符号常量通常用前面介绍的宏命令define来定义。如:#define tscr_init 0 x40#define tmodh_init 0#define tmodl_init 250也可通过const关键字来定义的符号常量。 定义形式:数据类型 const 标识符=数字 如:int const PI=3; 区别:用def
22、ine定义的常量不占任何存储空间,在编译时直接用对应的数据代替其常量名称参与运算。而用const定义的常量那么会占去单片机ROM区的内存,占去的空间大小为其定义数据类型所占空间的大小,如上面定义的PI常量占2个字节的空间。2变量 在程序运行过程中,其值可以被改变的量称为变量。每个变量都必须有变量名,变量名是标识符,必须满足用户标识符的要求。变量必须先定义后使用,定义变量的目的是说明变量的数据类型,以便为变量分配相应的存储单元。在程序使用变量前最好给变量赋初值,不赋初值的数值型变量其初值为0。变量在定义的同时可以赋初值。如: static int x,y=2,j=5; float sum; 以上
23、两条语句定义了x、y、j三个静态整型变量和一个浮点型变量sum,并且给变量y赋初值2,j赋初值5,没有给变量x赋初值,其初值默认为0。其中的存储类型在需要特别声明的时候才需要,否那么可以省略。同类变量可以共用一个数据类型说明符,各个变量之间用逗号隔开,最后以分号结束。这三个整型变量x、y、j在后面的程序中可以存放整型数据。浮点型变量sum可以存放一个浮点型数据的值。4.4 C51对单片机主要资源的定义 4.4.1 使用关键字定义特殊功能存放器SFR SFR及其可位寻址的位是通过关键字sfr和sbit来定义的,这种方法与标准C不兼容,只适用于C51。1用sfr定义特殊功能存放器SFR的字节地址格
24、式:sfr 存放器变量名称=地址值;功能:将右边的地址赋值给左边的存放器变量名称。举例:asfr PSW = 0 xD0; /定义程序状态字存放器PSW的地址为D0H bsfr SCON = 0 x98; /定义串行口控制存放器SCON的地址为98H csfr P0 = 0 x80; /定义P0口的地址为80H dsfr TMOD = 0 x89; /定义定时器/计数器方式控制存放器TMOD的地址为89H 2用sbit定义特殊功能存放器SFR的位地址格式:sbit的用法有三种格式,分别介绍如下。asbit 位变量名称=位地址值;bsbit 位变量名称=SFR名称变量位地址值;csbit 位变量
25、名称=SFR地址值变量位地址值;功能:将右边的位地址赋值给左边的位变量名称。举例:asbit CY = 0 xD7; /定义进位标志CY的地址为D7H bsbit AC = PSW6; /定义辅助进位标志AC为PSW的第6位,其中PSW 必须先用sfr 定义好 csbit RS0 = 0 xD03; /定义RS0的地址为D3H即D0H单元的第3位注意:用sfr和sbit定义的SFR必须位于函数外,一般放在程序的开头。 4.4.2 通过头文件访问特殊功能存放器SFR 头文件:以“.h为扩展名的文件。C51编译器给出的头文件已经给出了MCS-51单片机中的SFR及其可位寻址位的定义。并且Keil
26、C51编译器将这些头文件按单片机的不同生产公司、不同型号分别存放在Keil C51的INC子目录下,在程序中只需引用这些头文件即可实现对SFR的访问和控制。头文件通常有reg51.h,reg52.h,math.h,ctype.h,stdio.h,stdlib.h,absacc.h,intrins.h等八个。但常用的却只有reg51.h或reg52.h,math.h等二个。reg51.h或reg52.h是定义51单片机或52单片机特殊功能存放器和位存放器的,这两个头文件中大局部内容是一样的,52单片机比51单片机多一个定时器T2,因此,reg52.h中也就比reg51.h多几行定义T2的内容。m
27、ath.h是定义常用数学运算的,比方求绝对值、求方根、求正弦或余弦等,该头文件中包含有各种数学运算函数,当我们需要使用时可以直接调用它的内部函数。在代码中引用头文件,其实际意义就是将这个头文件中的全部内容放到引用头文件的位置,从而免去我们每次编写同类程序时都要将头文件中的语句重复编写。翻开reg51.h,其全部内容见教材所示。举例如下:#include /使用的单片机为AT89C51mainTL0 = 0 xb0; /访问定时器0,设置时间常数TH0 = 0 x3c;TR0 = 1; /启动定时器04.4.3 扩展I/O端口或片外RAM的直接访问 扩展的片外RAM或I/O端口需要用户自己先定义
28、后才能在语句或函数中使用。现举例如下:#include /*包含头文件absacc.h,其内部将XBYTE定义为一个指针,指向外部数据存储器RAM的零地址单元*/#define PA XBYTE0 xffec /将PA定义为外部I/O口,地址为0 xffecmain () PA = 0 x3a; /将数据3AH写入地址为0 xffec的存储单元或I/O端口 4.4.4 定义和使用位变量 C51使用关键字“bit来定义位变量。格式:bit 变量名称;功能:将变量名称定义为位型变量。例:bit lock; /将lock定义为位变量 bit dirention; /将dirention定义为位变量函
29、数既可以有bit类型的参数,也可以有bit类型的返回值。例如: bit funcbit b0,bit b1 bit a; return (a); 4.5 C51的根本运算 4.5.1 C51的算术运算1根本的算术运算符+:加法运算符。-:减法运算符。*:乘法运算符。/:除法或求模运算符。%:取余运算符。2自增、自减运算符+:自增运算符。 -:自减运算符。例如:+ j、j +、- j、j-注意:+和-运算符只能用于变量,不能用于常量和表达式。+ j表示先加1,再取值;而j +表示先取值,再加1。自减运算也是如此。3算术表达式和运算符的优先级与结合性算术表达式就是用算术运算符和括号将运算对象连接起
30、来的式子。例如:(2a+3b* c/d。C51规定了算术运算符的优先级为先乘除和取模,后加减,括号最优先。C语言中各运算符的结合性分为两种,即左结合性自左至右和右结合性自右至左。算术运算符均为左结合性,即先左后右。例如表达式xyz,那么y应先与“号结合,执行xy运算,然后再执行z的运算。这种自左至右的结合方向就称为“左结合性。而自右至左的结合方向称为“右结合性。最典型的右结合性运算符是赋值运算符。如x=y=z,由于“=的右结合性,应先执行y=z,再执行x=y=z运算。不同数据类型间的转换。其一是自动类型转换,即在程序编译时,由C编译器自动进行数据类型转换。其二是使用强制类型转换运算符。语句形式
31、为:类型说明符表达式。功能:把表达式的运算结果强制转换成类型说明符所表示的类型。例如:int a,b; / a、b为整数(double) (a+b); /将a+b强制转换成double数据类型4.5.2 C51的关系运算1关系运算符及其优先级关系运算符也叫比较运算符,C51提供了以下6种关系运算符。:小于运算符。 =:大于等于运算符。=:小于等于运算符。 = =:等于运算符。:大于运算符。 ! =:不等于运算符。在以上运算符中,、=、=这四个运算符的优先级相同,处于高优先级;= =和! =这两个运算符的优先级也相同,处于低优先级。此外,关系运算符的优先级低于算术运算符的优先级,而高于赋值运算符
32、的优先级。2关系表达式关系表达式:用关系运算符将运算对象连接起来的式子。如:ab、(a=4)(b=3)等。关系表达式的值为逻辑值,其结果只能是真和假两种值之一。C51中用1表示真,用0表示假。4.5.3 C51的逻辑运算1逻辑运算符及其优先级逻辑运算是对变量进行逻辑与运算、或运算及非运算。&:逻辑与运算符。|:逻辑或运算符。!:逻辑非运算符。其中非运算的优先级最高,而且高于算术运算符;或运算的优先级最低,低于关系运算符,但高于赋值运算符。2逻辑运算表达式逻辑运算表达式:用逻辑运算符将运算对象连接起来的式子。例如:(ab)|c&!d,表示a大于b的值跟c与d非的值相或。逻辑表达式的值与关系表达式
33、的值一样,也是逻辑量,即真或假。4.5.4 C51的位运算位运算的操作对象只能是整形和字符型数据,而不能是实型数据。&:按位与运算符,两个字符或整数按位进行逻辑与运算。例如:var3 = var1 & var2。|:按位或运算符, 两个字符或整数按位进行逻辑或运算。例如:var3 = var1 | var2。:按位异或运算符,两个字符或整数按位进行逻辑异或运算。例如:var3 = var1 var2。:按位取反运算符,两个字符或整数按位进行逻辑非运算。例如:var1 = var2。:左移运算符,字符或整数按位进行逻辑左移运算。例如:var1 = var2:右移运算符,字符或整数按位进行逻辑右移
34、运算。例如:var1 = var26。4.5.5 C51的赋值运算1赋值运算符赋值符号“=完成的操作即为赋值运算,它是右结合性,且优先级最低。2赋值表达式将一个变量与表达式用赋值号连接起来就构成赋值表达式。形式如下:变量名=表达式功能:将“=右边表达式的值赋给“=左边的一个变量。例如:a = (b = 4) + (c = 6),该表达式的值为10,变量a的值也为10。3赋值的类型转换规那么在赋值运算中,当赋值运算符“=两侧的类型不一致时,系统自动将右边表达式的值转换成左侧变量的类型,再赋给该变量。转换规那么如下。实型数据赋给整型变量时,舍弃小数局部。整型数据赋给实型变量时,数值不变,但以IEE
35、E浮点数形式存储在变量中。长字节整型数据赋给短字节整形变量时,实行截断处理。如将long型数据赋给int型变量时,将long型数据的低两字节数据赋给int型变量,而将long型数据的高两字节的数据丢弃。短字节整型数据赋给长字节整型变量时,进行符号扩展。如将int型数据赋给long型变量时,将int型数据赋给long型变量的低两字节,而将long型变量的高两字节的每一位都设为int型数据的符号值。4复合赋值运算符赋值符号前加上其它运算符即构成复合运算符。+=,=,*=,/=,%=,&=,|=,=,=。其功能是先进行加、减、乘、除、取余、与、或、异或、左移以及右移运算后再进行赋值操作。例如:a +
36、= b; /等价于a = (a + b),赋值表达式加上分号即“a + = b;也叫赋值语句x *= a+b; /等价于x = x * (a + b)a &= b; /等价于a = (a & ba= 4; /等价于a = (a 联合元素。例如:对于前面定义的联合变量a、b、c,下面的引用方法都是正确的:a.fval /* 引用联合变量a中float型元素fval */b.ival /* 引用联合变量b中int型元素ival */csval /* 引用联合变量c中char型元素sval */注意:在引用联合元素时,要注意联合变量用法的一致性。因为联合类型中定义的各个不同类型的元素都可以分时地赋给
37、变量,而所读取变量的值是最近放入的某一元素的值,因此在表达式中对它进行处理时,必须注意其类型与表达式所要求的类型保持一致,否那么将导致程序运行出错。不能只引用联合变量。例如,下面的写法就是错误的:printf(“%f,a);因为变量a可能是float、int和char三种类型,分别占用不同长度的内存区域,假设在引用时仅写联合变量名a,系统将难以确定究竟应该输出哪一个联合元素的值。正确的写法应为:printf(“%f,a. ival; 联合类型的数据可以采用同一个内存段来存放几种不同类型元素的值,但是在每一瞬时只能存放其中一种类型的元素,而不能同时存放几种。换句话说,每一瞬时只有一个元素在起作用
38、。起作用的是联合中最后一次存放的元素,如果存入了一个新的元素,那么上次存入的元素就自动失去作用。例如,对于以下语句:a.fval = 100.25;a.ival = 200;a.sval = 10;在执行以上三条赋值语句之后,只有a.sval是有效的,而a. ival和a.fval都已失去作用。因此在引用联合变量时一定要十分注意当前在联合变量中存放的究竟是哪一个元素。不能直接对联合变量进行赋值,也不能在定义联合变量时对它进行初始化。4.7 C51的流程控制语句 4.7.1 选择控制语句有if语句和switch/case语句,用于设计分支结构程序1if语句 if 语句是用来判定所给定的条件是否满
39、足,再根据判定的结果真或假来决定执行给出的两种操作之一。C51提供了三种形式的if 语句。形式1。格式: if (表达式) 语句;功能:如果表达式的结果为真,那么执行语句,否那么不执行。形式2。格式: if (表达式) 语句1; else 语句2;功能:如果表达式的结果为真,那么执行语句1,否那么执行语句2。形式3。格式:if (表达式1) 语句1;else if (表达式2) 语句2;else if (表达式3) 语句3;else if (表达式m) 语句m;else 语句n;功能:这是if语句的嵌套,即一个if语句中又包含有一个或多个if语句。主要用于多分支选择程序。在if语句的嵌套中应注
40、意if与else的对应关系,else总是与它前面最近的一个if语句相对应。 【例4.1】 某浮点数的范围在0.0009999之间,试编写一个函数返回浮点数的小数点位置。解:此题的根本思路是根据浮点数的4种不同取值范围给出4种不同的返回值。可以约定浮点数的大小在0.0009.999、10.0099.99、100.0999.9、10009999之间时,分别返回0、1、2和3。参考程序如下:int ftochar (float valp) int dotno = 0; if (valp10.00) dotno = 0; else if (valp= 10.0) & (valp100.0) dotno
41、 = 1; else if (valp= 100.0) & (valp1000.0) dotno = 2; else if (valp= 1000.0) dotno = 3;return dotno;根据小数点的位置,即可在实际的单片机系统中显示出浮点数或小数。2switch/case语句用于直接处理多分支选择switch/case语句的一般形式如下:switch (表达式)case 常量表达式1:语句1;break;case 常量表达式2:语句2;break;case 常量表达式n:语句n;break;default:语句n+1;说明:当switch后面括号内的“表达式的值与某一个case后
42、面的常量表达式的值相等时,就执行此case 后面的语句可以是复合语句,遇到break语句就退出switch语句。假设所有的case中的常量表达式的值都没有与表达式的值匹配时,就执行default 后面的语句。【例4.2】 AT89C51单片机的P1. 1和P1. 0引脚接有两只按键,其4种逻辑组合分别点亮由P2.0P2.3控制的4只LED高电平点亮,试编程实现此功能。解:参考程序如下:#include /包含AT89x51系列单片机的头文件void main () char a;do a = P1; a = a&0 x03; /屏蔽掉P1口的高6位 P2 = P2&0 xf0; /开始4只LE
43、D全熄 switcha case 0:P2 =P2|0 x01;break; case 1:P2 =P2|0 x02;break; case 2:P2 =P2|0 x04;break; case 3:P2 =P2|0 x08; while1; /循环继续读取按键4.7.2 循环控制语句 循环程序可分为“当型循环程序和“直到型循环程序两种类型,这与其它语言的循环程序一样。在C51语言中,用来构成循环控制的语句有:while语句、do-while语句、for语句以及if和goto语句等。1基于while语句构成的循环采用while语句构成循环结构的一般格式如下:while (条件表达式) 内部语句
44、; /内部语句可以是复合语句,也可以为空 意义:当条件表达式的结果为真非0值时,程序就重复执行后面的内部语句,一直执行到条件表达式的结果变为假0值时为止。也就是说,这种循环结构是先检查条件表达式所给出的条件,再根据检查的结果断定是否执行后面的内部语句。如果条件表达式的结果一开始就为假,那么后面的内部语句一次也不会执行。因此属于“当型循环。图4-4为while语句的执行过程。 假条件表达式内部语句真图4-4 while语句的执行过程【例4.3】 使用while语句计算自然数1100的累加和,并用printf ()函数通过单片机的串口显示在终端上。解:参考程序如下:#include /*包含根本输
45、入输出头文件stdio.h*/真内部语句条件表达式假图4-5 do-while语句循环结构的流程图void main () int i, sum = 0; i = 1; while (i=100) /*复合语句循环体开始*/ sum = sum+i; i+; /*复合语句循环体结束* /printf (“1+2+100 = %dn, sum );while (1);2基于do-while语句构成的循环do-while语句只能用来实现“直到型循环,其一般格式如下:do 内部语句; /可以是复合语句 while条件表达式;意义:先执行给定的循环体语句,然后再检查条件表达式的结果。当条件表达式的值为
46、真非0值时,那么重复执行循环体语句,直到条件表达式的值变为假0值时为止。因此,用do-while语句构成的循环结构在任何条件下,循环体语句至少会被执行一次,这就是“直到型循环。图4-5给出了这种循环结构的流程图。真内部语句条件表达式假图4-5 do-while语句循环结构的流程图【例4.4】 实型数组sample存有10个采样值,编写一个函数返回其平均值(即平均值滤波程序)。解:参考程序如下:float avg (float *sample) float sum = 0; char no = 0; do sum += sampleno; no +; while (no10); return (
47、sum/10); 假初值设定表达式内部语句更新表达式循环条件表达式真图4-6 for语句的执行过程示意图3基于for语句构成的循环采用for语句构成循环结构的一般格式如下:for初值设定表达式;循环条件表达式;更新表达式 内部语句; /可以是复合语句 意义:先计算出初值设定表达式的值作为循环控制变量的初值,再检查循环条件表达式的结果,当满足条件时就执行循环体语句并计算更新表达式,然后再根据更新表达式的计算结果来判断循环条件是否满足,只有一直进行到循环条件表达式的结果为假0值时才退出循环体。各表达式之间必须用分号“;进行分隔。for语句的执行过程如图4-6所示。【例4.5】 使用for语句计算自
48、然数1100的累加和,并用printf ()函数通过单片机的串口显示在终端上。解:参考程序如下:#include#includeint getsum(void);void main()SCON = 0 x50; /如果用Keil C进行模拟调用或使用printf (),必须初始化SCONTMOD = TMOD|0 x20; /定时器T1工作方式2,用做波特率控制TH1 = 0 xfd; /9600bps对应T1的时间常数为0 xfdTL1 = 0 xfd;TR1 = 1; /启动T1TI = 1; /启动发送,以发送第一个字符printf (“%dn, getsum ();do while (
49、1);int getsum (void)int sum = 0;int n;for (n =1;n=100;n +) sum = sum+n; return (sum);4基于if和goto构成的循环“当型循环。采用if和goto可以构成“当型循环程序,其格式如下:loop:if (条件表达式) 内部语句; /可以是复合语句 goto loop; 说明:loop是语句标号,实质是带冒号“:的标识符,原那么上任何一条语句都可以有标号,标号和语句之间用冒号“:分隔。其执行过程是首先判断条件表达式的值,当条件表达式的值为真非0值时,那么执行内部语句,遇到goto loop语句时那么无条件返回loop
50、处继续判断条件表达式的值。直到条件表达式的值为假0值时才退出循环。需注意的是,条件表达式中条件变量的值必须在内部语句中进行改变,否那么就成为死循环程序。“直到型循环。采用if和goto也可以构成“直到型循环程序,其格式如下:loop: 内部语句; /可以是复合语句 if (条件表达式) goto loop; 说明:首先执行内部语句即循环体,再判断条件表达式的值。假设条件表达式的值为真非0值时,那么执行goto loop语句,无条件返回loop处继续执行内部语句即循环体。当条件表达式的值为假0值时就退出循环。显然,条件表达式的值不能一直为真非0值,否那么就成为死循环程序。goto语句。goto语
51、句是一个无条件转向语句,它的一般形式为:goto 语句标号;前已述及,语句标号是一个带冒号“:的标识符,将goto语句和if语句相结合使用,就可以构成“当型循环或“直到型循环结构。【例4.6】 使用goto语句跳出循环结构。 本程序采用循环结构来求一个整数的等差数列,该数列满足条件:头四个数的和值为26,积值为880。该数列的公差应为正整数,否那么将产生负的项,此外该数列的首项数必须小于5,且其公差也应小于5,否那么头四项的和值将大于26。解:参考程序如下:#includevoid main () int a,b,c,d,i; for (a =1;a5;+ a) for (d =1;d5;+
52、d) b = a + (a + d) + (a + 2 * d) + (a + 3 * d); c = a * (a + d) * (a + 2 * d) * (a + 3 * d); if (b = = 26 & c = = 880) goto pt; pt: for (i =0;i=10;+ i) printf (“%d, a + i * d); printf (“n); while (1);continue语句。 在循环结构中还可以使用一种中断语句continue,它的功能是结束本次循环,即跳过循环体中下面尚未执行的语句,把程序流程转移到当前循环语句的下一个循环周期,并根据循环控制条件决
53、定是否重复执行该循环体。continue语句的一般格式为:continue; continue语句通常和条件语句一起用在由while、do-while和for语句构成的循环结构中,它也是一种具有特殊功能的无条件转移语句,但与goto、break语句不同,continue语句并不跳出循环体,而只是根据循环控制条件确定是否继续执行循环语句。【例4.7】 利用continue语句把1020之间不能被3整除的数输出。解:参考程序如下:#includevoid main () int n; for (n =10;a=20;n + ) if (n%3 = = 0) continue; printf (“%
54、d,n); while (1);4.8 C51的函数 4.8.1 函数的分类与定义1函数的分类主函数main ()。关于主函数main (),我们应该很熟悉了。下面再简要介绍其格式和特点。格式:void main () /*注意:后面没有分号*/ 总程序从这里开始执行; 其他语句; 特点:无返回值,无参数。 无返回值表示该函数执行完后不返回任何值,上面main前面的void表示“空,即不返回值的意思。无参数表示该函数不带任何参数,即main后面的括号中没有任何参数,只写“( )就可以了,也可以在括号里写上void,表示空的意思,如void main (void)。普通函数。a标准库函数。b用户
55、自定义函数。2函数的定义函数定义的一般形式为: 函数类型 函数名 (形式参数列表) 形式参数说明 局部变量定义; 函数体语句; 其中,“函数类型说明了自定义函数返回值的类型。返回值的类型可以是根本数据类型如int、char、float、double等,也可以是指针类型。当函数没有返回值时,那么使用标识符void进行说明。假设没有指定函数的返回值类型,那么默认返回值为整型类型。一个函数只能有一个返回值,该返回值是通过函数中的return语句获得的。“函数名是用标识符表示的自定义函数的名字,它必须是一个合法的标识符。“形式参数列表中列出的是在主调用函数与被调用函数之间传递数据的形式参数,形式参数的
56、类型必须加以说明。形式参数可以是根本数据类型的数据、指针类型数据、数组等。在没有调用函数时,函数的形式参数和函数内部的变量未被分配内存单元,即它们是不存在的。如果定义的是无参数函数,可以没有形式参数,但圆括号不能省略。“局部变量定义是对在函数内部使用的局部变量进行定义。局部变量是定义在函数内部的变量,编译器只在定义该变量的函数范围内给其分配存储空间。一旦调用结束,即刻释放所分配的内存单元。不同函数中的局部变量可以同名,但编译器会给它们分配不同的存储空间。形式参数也是一种局部变量。如果将变量定义在主函数之前,那么成为全局变量。在其他函数中不加定义即可使用全局变量,各个函数对全局变量的赋值都会引起
57、全局变量内容的变化,因为各个函数修改的是同一个存储单元的内容。对同一名称变量,如果在某一函数中有对该变量的定义静态变量除外,那么该变量在这个函数中成为局部变量,而在该函数之外是全局变量。“函数体语句是为完成该函数的特定功能而设置的各种语句。在函数体中可以根据用户自己的需要,设置各种不同的语句。这些语句应能完成所需要的功能。【例4.8】 定义一个计算整数的正整数次幂的函数。解:参考程序如下:int power (x,n) int x,n; int i,p; p =1; for (i = 1;i= n;+ i) p = p * x; return (p);这里定义了一个返回值为整型的函数power
58、 (),它有两个形式参数:x,n。形式参数的作用是接受从主调用函数传递过来的实际参数的值。上例中形式参数x和n被说明为int类型。大括号以内的局部是自定义函数的函数体。上例中在函数体内定义了两个局部变量i和p,它们均为整型数据。需要注意的是,形式参数的说明与函数体内局部变量的定义是完全不同的两个局部,前者应写在大括号的外面,而后者是函数体的一个组成局部,必须写在大括号里面。3返回语句return 返回语句用于终止函数的执行,并控制程序返回到调用该函数时所处的位置。返回语句有两种格式:return (变量或表达式); 或者 return; 如果return语句后边带有变量或表达式,那么要计算该变
59、量或表达式的值,并将该变量或表达式的值作为该函数的返回值返回到主调用函数中去。函数返回值的类型就是该函数的类型,因此在定义一个函数时,函数本身的类型应与return语句中变量或表达式的值的类型一致。如果函数的类型与return语句中变量或表达式的值的类型不一致,那么以函数的类型为准。对于数值数据可以自动进行转换,即函数的类型决定返回值的类型。 假设使用不带表达式的第2种形式,那么被调用函数返回主调用函数时,函数值不确定。一个函数的内部可以含有多个return语句,但程序仅执行其中的一个return语句而返回主调用函数。 如果不需要被调用函数返回一个确定的值,那么可以不要return语句。在这种
60、情况下,当程序执行到最后一个界限符“处时,就自动返回主调用函数。对于不需要有返回值的函数,可以将该函数定义为void类型空类型。 4.8.2 函数的调用1函数的调用形式 C语言程序中函数是可以互相调用的。所谓函数调用就是在一个函数体中引用另外一个已经定义了的函数,前者称为主调用函数,后者称为被调用函数。 函数调用的一般形式如下:函数名 (实际参数列表); “函数名指出被调用的函数。 “实际参数列表中可以包含多个实际参数,各个参数之间必须用逗号隔开。实际参数的作用是将它的值传递给被调用函数中的形式参数。因此,函数调用中的实际参数与函数定义中的形式参数必须在数量、类型以及顺序上严格保持一致,以便将
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026上海复旦大学高分子科学系招聘科研助理-行政-湾谷岗位1人备考题库及答案详解(新)
- 2026湖北教师招聘统考枣阳市城区4人备考题库带答案详解(完整版)
- 2026年近代物理研究所劳务派遣招聘备考题库及答案详解一套
- 2026江苏徐州市中心医院招聘高层次卫生人才31人备考题库及答案详解(夺冠)
- 2026山东省水利工程试验中心有限公司工作人员招聘6人备考题库及1套参考答案详解
- 2026浙江杭州塘韵联村科技发展有限公司招聘工作人员2人备考题库含答案详解(培优a卷)
- 2026江苏赫尔斯镀膜技术有限公司招聘2人备考题库含答案详解(完整版)
- 2026四川泸州发展控股集团有限公司及部分旗下企业第一批次招聘34人备考题库含答案详解(达标题)
- 2026上海复旦大学高分子科学系招聘科研助理-行政-湾谷岗位1人备考题库附答案详解(研优卷)
- 2026四川天府演艺集团有限公司招聘1人备考题库及答案详解(名师系列)
- 2026年株洲市荷塘区社区工作者招聘笔试参考题库及答案解析
- 车间火灾应急指南
- 2026年北京市西城区高三一模地理试卷(含答案)
- 其他地区2025年昌都市政府系统急需紧缺人才引进招聘11人笔试历年参考题库附带答案详解(5卷)
- 2026广东广州铁路运输法院合同制审判辅助人员招聘3人笔试参考题库及答案解析
- 第三单元 认识国家制度 单元行动与思考 课件-2025-2026学年统编版道德与法治八年级下册
- 2025年湖南省农业信贷融资担保有限公司员工招聘笔试历年典型考点题库附带答案详解
- 2026广东省水利水电第三工程局有限公司校园招聘笔试历年典型考点题库附带答案详解
- 2026年银行网点运营经理招聘面试题库及答案解析
- 雨课堂学堂在线学堂云《Age of Sustainable Development(SDG Academy)》单元测试考核答案
- 下肢深静脉血栓介入护理指南
评论
0/150
提交评论