当前位置:文档之家› 第四章 单片机流程控制

第四章 单片机流程控制

第四章 Cx51的流程控制C语言是结构化编程语言,结构化语句有若干模块组成,每个模块中包含着若干个基本结构,每个基本结果中可以又若干调语句。

归纳起来,C语言又三种基本结构:1)顺序结构;2)选择结构;3)循环结构。

一、选择控制语句C51 的选择语句主要有if 语句和switch/case 语句。

1、 if 语句1)基本结构 if(表达式) {语句}表达式为真执行花括号中的语句,否则跳过花括号中的语句。

如果没有花括号,执行紧随其后的一句。

2)C51 提供三种形式的if 语句:① if(表达式){语句;}② if(表达式){语句1;} else {语句2;}③ if(表达式1){语句1;}else if(表达式2){语句2;}else if(表达式3){语句3;}此外,如果一个if 语句中又含有一个或多个if 语句,则称为if 语句嵌套。

在if 语句嵌套中应注意if 与else 的对应关系,else 总是与它前面最近的一个if 语句相对应。

例1:某浮点数的范围在0.000~9999 之间,试编写一个函数返回浮点数的小数点位置。

根据小数点的位置,即可在实际的单片机系统中显示出小数。

解:此题的基本思路是根据浮点数的4 种取值范围给出4 种不同的返回值,可以约定当定浮点数的大小在0.000~9.999、10.00~99.99、100.0~999.9、1000~9999 之间时,分别返回0、1、2 和3。

参考程序如下:int ftochar(float valp){int dotno=0;if(valp<10.0) dotno=0;else if((valp>=10.0)&&(valp<100.0)) dotno=1;else if((valp>=100.0)&&(valp<1000.0)) dotno=2;else if(valp>=1000.0) dotno=3;return dotno;}//代码长度298也可以这样编:int ftochar(float valp){int dotno=0;if(valp>=10.0) dotno=1;if(valp>=100.0) dotno=2;if(valp>=1000.0) dotno=3;return dotno;}//代码长度227自己体会例2:if(P1_1!=0) {P1_1=0;}例3:if(P1&0xf0)!=0xf0) {……}//检查P1高4位中是否有0 2、 switch/case 语句switch/case 是C51 的多分支选择语句,它的一般形式如下:switch(表达式){case 常量表达式1:语句1; break;case 常量表达式2:语句2; break;⋯⋯case 常量表达式n:语句n; break;default :语句n+1;}switch 括号中的表达式的值与某一case 后面的常量表达式的值相同时,就执行它后面的语句(可以是复合语句),遇到break 语句则退出switch 语句。

若所有的case 中的常量表达式的值都没有与表达式的值相匹配时,就执行default 后面的语句。

每一个case 的常量表达式必须是互不相同的,否则将出现混乱局面。

各个case 和default 出现的次序,不影响程序的执行结果。

如果在case 语句中遗忘了break 语句,则程序执行了本行之后,不会按规定退出switch语句,而是将执行后续的case 语句。

例1、 AT89C51 单片机的P1.0 和P1.1 引脚接有两只按键,其4 种逻辑组合分别点亮由P2.0~P2.3 控制的4 只LED(高电平点亮),试编程实现此功能。

解:参考程序如下#include <at89x51.h>void main(){data unsigned char a;do{a=P1;a=a&0x03; //,读低2位P2=P2&0xf0;//P2低4位置0,关LED switch (a){Case 0:P2=P2|0x01;break;Case 1:P2=P2|0x02;break;Case 2:P2=P2|0x04;break;Case 3:P2=P2|0x08;}}while(1);//注意while(1)}二、循环语句循环程序主要有“当型”循环和“直到型”循环两种,C51 对此提供了4 种实现方法。

1、基于 if 和goto 构成的循环采用if 和goto 可以构成“当型”循环程序,其格式如下:loop:if(表达式){语句;goto loop;}loop 是语句标号,或称为标识符,原则上任何一条语句都可以有标号,标号和语句用“:”号分开。

采用if 和goto 也可以构成“直到型”循环程序,其格式如下:loop:{语句;if(表达式)goto loop;}goto 语句为无条件转向语句,它的一般形式是:goto 语句标号;按照软件工程的有关思想,在程序设计中应避免使用或尽量少使用goto,以提高程序的可读性。

有时候使用goto语句非常方便,2、基于while 语句构成的循环while 语句只能用来实现“当型”循环,其一般格式如下:while(表达式){语句;//可以是复合语句}while 语句首先计算表达式的值;若其值为非0,则执行内嵌语句,若其值为0,则退出while 循环。

例1:串行通信时,每发送1帧,需要等待发送完,经常用下面语句:while(TI==0);//注意后面的“;”TI=0;例2、对于仪器,开电源后一直工作,可以用下面的语句:while(1) { 程序}3、基于do-while 语句构成的循环do-while 语句只能用来实现“直到型”循环,其一般格式是:do{语句;//可以是复合语句} while (表达式);do-while 语句的特点是先执行内嵌的语句;再计算表达式,如果表达式的值为非0,则继续执行内嵌的语句,直到表达式的值为0 时结束循环。

例1:实型数组sample 存有10 个采样值,编写一个函数返回其平均值(即平均值滤波程序)。

解:参考程序如下:float avg(float *sample){float sum=0;char no=0;do{sum += sample[no];no++;} while(no<10);return (sum/10);}4、基于for 语句构成的循环for 语句的一般形式为:for (表达式1;表达式2;表达式3){语句;}它的执行过程是:首先求解初始化表达式1;其次求解表达式2,判断是否满足循环条件,若其值非0,则执行内嵌语句,如无花括号,执行紧随其后的一句语句;否则退出循环;最后求解尺度增量表达式3,并回到第2 步。

在for 语句中,可以没有表达式1、表达式2 或表达式3,若三个表达式都没有,则相当于一个死循环。

如果其后紧跟一个“;”,则为空循环,常用于延时;例1、求自然数1~100 的累加和,并用printf( )函数通过单片机的串口显示在终端上。

(12MHz晶振)解:参考程序如下:#include<at89x52.h>#include<stdio.h>main( ){int sum=0;int n;SCON = 0x50; /* 如用Keil C 进行模拟调试或使用printf( ),必须初始化SCON*/TMOD = TMOD|0x20; // 定时器T1 工作在方式2,用作波特率控制TH1 = 0xe6; // 9600bps 对应T1 的时间常数为0xe6TL1 =0xe6;TR1 = 1; // 启动T1TI = 1; //启动发送,以发送第一个字符for (n=1;n<=100;n++){sum=sum+n;printf("%d ",sum);}}(求和输出)例2:for(;;){语句}//无限循环语句,直到关机例3:for(t=0;t<sum;t++);//在程序中延时(for循环)例4:延时子程序及延时时间计算(延时程序)#include<at89x51.h>#include<intrins.h>void relay(unsigned int x){unsigned char j;while(x--){for(j=0;j<199;j++)_nop_();}}main(){unsigned int x=10;relay(x);}C:0x0000 02001A LJMP C:001A3: void relay(unsigned int x)4: {5: unsigned char j;6: while(x--)查延时时间:将晶振频率设置的和实际使用频率相同,用执行到光标处,从进入延时前,记下register中sec的时间t1,然后运行到延时结束,记下时间t2,延时时间t=t2-t1 (演示)该方法叫软件延时,最大的缺点是延时时占用了CPU,不能执行其他程序,因此不适合做时钟,时钟要用定时器。

编程例:while(1){ if(P0_4==0){for(i=0;i<200;i++);//防键盘抖动while(P0_4==0);celiang();//调测量函数,}if(P2_2==0){for(i=0;i<200;i++);if(P2_2==0)xiaoyan();//调用传感器校验……………} }C:0x0003 EF MOV A,R7 (1)C:0x0004 1F DEC R7 (1)C:0x0005 AA06 MOV R2,0x06 (2)C:0x0007 7001 JNZ C:000A (2)C:0x0009 1E DEC R6 (1)C:0x000A 4A ORL A,R2 (1)。

相关主题