单片机原理及应用笔记:C51流程控制语句与项目实践

时间:2024-10-30 08:40:59

作者介绍

周瑞康,男,银川科技学院,计算机人工智能学院,2022级计算机科学与技术8班本科生,单片机原理及应用课程第八组。

指导老师:王兴泽

电子邮箱2082545622@qq.com

前言:

本篇文章是参考《单片机原理及应用(c语言版)第2版》杨居义·编著教材编写的笔记

由周瑞康,王征,汪泽祥,杨立娟,韩旭同学共同完成此篇章,其中杨立娟,韩旭同学负责C51的顺序结构C51的选择结构相关知识。汪泽祥同学负责C51的循环结构。王征同学负责项目实践。周瑞康同学负责以上内容排版整合。

项目12:C51流程控制语句与项目实践

C语⾔的三种基本结构指的是顺序结构、选择结构、循环结构,基本上所有的程序执行过程都可以拆分为这三种结构或者这三种结构的组合。这三种结构是构建任何C语言程序的基础,它们可以相互嵌套和组合,以实现复杂的程序逻辑。

  1. 顺序结构

顺序结构的特点是程序的执行流程是直线型的,即程序从第一条语句开始,从上到下按顺序逐条执行,直到最后一条语句结束,过程中没有任何分支或跳转。

    2.选择结构

通过某个给定条件进行判断,条件为真或假时分别执行不同的程序内容,选择结构分条件语句和开关语句两种。

     

​​​​​​     ​2.1if语句(条件语句)

主要包括if语句和switch语句。If语句在单片机c语言中是极为常用的语句,用来判断某些变量(信号)达到预期的值后,再执行满足条件的指令,或者执行不满足条件的指令。If 语句的基本形式有三种:

  1. 直接的if语句;

if (condition) {

    // 当条件为 true 时执行的代码

}

if……else……语句;

在需要根据条件执行不同操作时,if-else 语句提供了更好的结构。当第一个条件为 false 时,程序会执行 else 块中的代码。

if (condition) {

    // 当条件为 true 时执行的代码

} else {

    // 当条件为 false 时执行的代码

}

if的嵌套形式;

如果程序需要处理多个条件,else if 语句可以帮助实现更复杂的逻辑结构。else if 语句允许在多个条件中进行选择。

if (condition1) {

    // 如果 condition1 为 true,则执行这段代码

} else if (condition2) {

    // 如果 condition1 为 false 且 condition2 为 true,则执行这段代码

} else if (condition2) {

    // 如果 condition1 为 false 且 condition2 为 true,则执行这段代码

else {

    // 如果以上条件均为 false,则执行这段代码

}

​​​​​​     2.2switch语句(开关语句)

 if语句比较适合于从两者之间选择。当要实现从多种选一时,采用switch…case多分支开关语句,可使程序变得更为简洁。

Switch(表达式)

{

Case  常量表达式1:/*如果常量表达式1满足,则执行语句1*/

语句1;

break;  /*执行完语句1后,使用break跳出switch结构*/

Case  常量表达式2: /*如果常量表达式2满足,则执行语句2*/

语句2;

break;  /*执行完语句2后,使用break跳出switch结构*/

:

:

Case  常量表达式n: /*如果常量表达式n满足,则执行语句n*/

语句n;

break;  /*执行完语句n后,使用break跳出switch结构*/

default:  /*条件都不满足时,执行语句n+1*/

语句n+1;

}

当switch括号中表达式的值与某一个case后面的常量表达式的值相等时,就执行它后面的语句,然后因遇到break而退出switch语句。

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

每个case的常量表达式必须是互不相同的,否则出现对表达式的同一个值有两种以上的选择。

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

注意:对于Switch语句,需要注意两点:一是常量表达式的值必须是整型或字符型;二是最好使用“break”。

实例:

void main(void)

{unsigned char i;

i=2;

Switch(i)

{

Case 0: P0=0xff ;  /*如果i=0,则执行“P0=0xff”*/

break;

Case 1:P1=0xff;

break;

Case 2:P2=0xff;   /*常量表达式2满足,则执行“P2=0xff”*/

break;  /*执行完后,跳出switch结构*/

default:P1=0x00;  /*当所有的case中的常量表达式的值都没有与表达式的值相匹配时,就执行default后面的语句*/

}

}

3.C51的循环结构

循环结构是结构化程序设计的3种基本结构之一,因此掌握循环结构的概念是程序设计,尤其是C程序设计最基本的要求。

在C51语言中,实现循环的语句主要有3种。

(1)While语句的一般形式

While(表达式)

{语句;/*循环体*1}

While语句的语义是:计算表达式的值,当值为真(非0)时,执行循环体语句,否则,跳出循环体,执行后续操作。

使用while语句应注意以下几点:

●While语句中的表达式一般是关系表达式或逻辑表达式,只要表达式的值为真(非0)即可继续循环。

●循环体如包含一个以上的语句,则必须用“{}”括起来,组成复合语句。

●While循环体中,应有让循环最终能结束的语句,否则将造成死循环。一直运行直至关机。

实例:

while(1)

{}

这个语句的作用就是无限循环,一直运行直至关机。

实例:用while求1到10的和,程序如下:

void main(void)

{

unsigned char i,sum;

sum=0;

i=1;

while(i<=10)

{

sum=sum+i

i++;

}

PO=sum;  //将结果送P0口显示

}

(2)do…while语句的一般形式

do

{语句;}   /*循环体*/

while(表达式);

do…while循环语句的执行过程如下:首先执行循环体语句一次,再判断表达式的值。如果表达式的值为真(非0值),则重复执行循环体语句,直到表达式的值变为假(0值)时循环结束。对于这种结构,在任何条件下,循环体语句至少会被执行一次。注意:

●do是C语言关键字,必须和while联合使用;

● while(表达式)后的分号“;”不能少,它表示整个循环语句的结束。

实例:用do…while求1到10的和,程序如下:

    void main(void)

{

unsigned char i,sum;

sum=0;

i=1;

do{

sum=sum+i;  /*注意{}不能省,否则跳不出循环体*/

i++;

}

while(i<=10);/1分号“;”不能少

PO=sum;  //将结果送P0口显示

}

(3)for语句的一般形式

For  (初始化表达式;条件表达式;增量表达式)

{语句;}  /*循环体*/

For 循环语句结构可使程序按指定的次数重复执行

一个语句或一组语句。for循环语句的执行过程如下:

●初始化表达式;

●求解条件表达式。若其值为“真”,则执行for后面的语句;如果其值为“假”,那么跳过for循环语句;

●若条件表达式为“真”,则执行指定的语句后,执行增量表达式;

●执行for后面的语句。

4.项目实践

任务12-2-1:用按键S控制P1口8只LED显示状态

任务实现

(1)分析:先设置一个变量i,当i=1时,LED1发光;当i=2时,LED1、LED2发光;当i=3时,LED1、LED2、LED3发光;...;当i=8时,LED1~LED8都发光。由“switch”语句根据i的值来实现LED发光。i值的改变可以通过按键S来控制,每按下S按键一次,i自增1,当增加到9时,将其值重新置为1。

(2)程序设计

#includesreg51.h> //包含单片机寄存器的头文件

sbit S=P3^0; 1/定义按键S接入P3.0引脚

/*********************************

函数功能:延时约150ms

**********************************/

Void delay(void)

{

Unsigned char i,j;

for(i=0;i<200;i++)

for(j=0;j<250;j++)

       }

/*********************************

函数功能;主函数

**********************************/

void main(void)

{

unsigned chari;

i=0;  //初始化

while(1)  //无限循环

{

if(S==0) //判断S按键是否被按下,如果S=0被按下

{

delay();  150ms延时,消除键盘抖动

if(S==0)  /*再判断S按键是否被按下,如果S=0确被按下*/

i++;  //自增1

if(i==9) //如果i=9,将其值重新置为1

i=1;

}

switch(i)  //7使用多分支语句

{

case1:P1=0xfe;  //LED1发光

break;  //退出switch语句

case2:P1=0xfc; //LED1、LED2发光

break;  //退出switch语句

case3:P1=0xf8;  //LED1、LED2、LED3发光

break;  //退出switch语句

case4:P1=0xf0;  //LED1、LED2、LED3、LED4发光

break;  //退出switch语句

case5:P1=0xe0;  //LED1、LED2、LED3、LED4、LED5发光

break;  //退出switch语句

case6:P1=0xc0;  //LED1、LED2、LED3、LED4、LED5、LED6发光

break;  //退出switch语句

case7:P1=0x80;  //LED1、LED2、LED3、LED4、LED5、LED6、LED7发光

break;  //退出switch语句

case8:P1=0x00;  //LED1~LED8发光

break;  //退出switch语句

defauit:  //默认值,关闭所有LED

P1=0xff;}

}

             }

任务12-2-2:用for语句实现蜂鸣器发出1kHZ音频

任务实现

(1)分析:设单片机晶振频率为12MHz,则机器周期为1μs。只

要让单片机的P1.0引脚的电平信号每隔音频的半个周期取反一次即可发出1KHz音频。音频的周期为T=1/1000Hz=0.001s,即1000μs,半个周期为1000μs/2=500μs,即在P1.0引脚上每500μs取反一次即可发出1KHz音频。而延时500μs需要消耗机器周期数N=500μs /3=167,即延时每循环167次,就可让P1.0引脚上取反一次就可以得到1KHz音频。

(2)程序设计

#include<reg51.h>  //包含单片机寄存器的头文件

sbit sound=P1^0;   //将sound位定义为p1.0引脚

/**********************************************

函数功能:延时以形成约1KHz音频

/**********************************************

            void delay500us(void)

{

unsigned char i;

for(i=0;i<167;i++)

;

}

/**********************************************

函数功能:延时1000μs以形成一个周期约500Hz音频

/**********************************************

void delay1000us(void)

{

unsigned int i;

for(i=0;i<333;i++)

;

}

/**********************************************

函数功能:发声1s时间的控制

/**********************************************

void sound1s(void)

{

unsigned int i;

for(i=0;i<1000;i++)

{

sound = 0;

delay500us();

sound = 1;

delay500us();

}

}

/**********************************************

函数功能:发声0.5s时间的控制

/**********************************************

void soundBans(void)

{

unsigned char i;

for(i=0;i<250;i++)

{

sound=0;

delay1000us();

sound=1;

delay1000us();

}

}

(4)实践探索——用单片机开发版来实现

          由于开发板蜂鸣器连接在P2.4引脚,因此只需要修改代码”sbit sound=P2^4”就可以了。

小结:消耗机器周期数的计算(近似值):

(1)一重循环

for(i=0;i<n;i++)    //n必须为无符号字符型数据

消耗机器周期数为:

N=3×n

式中:N为消耗机器周期数;n为需要设置的循环次数(n必须为无符号字符型数据)。

(2)二重循环

for(i=0;i<n;i++)    //n必须为无符号字符型数据

for(i=0;i<m;i++)   //m必须为无符号字符型数据消耗机器周期数为:

N=3×n×m

任务12-2-3:用while语句控制P1口8只LED的显示状态

任务实现

(1)分析

设计一个用while语句实现P1口8只LED显示状态的程序,根据要求在while语句循环中设置一个变量i,当i小于0x64(十进制数100)时,将i的值送P1口显示,并i自增1,当i等于0×64时,就跳出while循环。

(2)程序设计

#include<reg51.h>  //包含单片机寄存器的头文件

/**********************************************

函数功能:延时约150ms

/**********************************************

void delay(void)

{

unsigned char i,j;

for(i=0;i<200;i++)

for(j=0;j<250;j++)

;

}

/**********************************************

函数功能:主函数

/**********************************************

void main(void)

{

unsigned char i;

while(1)  //无限循环

{

i=0;  //将i置为0,即初始化

while(i<0x64)  //i小于100时执行循环体

{

P1=i;

delay;

i++;  //i自增1

}

}

}

任务12-2-4:用do…while语句控制P1口8只LED的显示状态

任务实现

(1)分析:只要在循环体中按照点亮次序依次点亮,再将循环条件设置为死循环即可。现在来讨论点亮LED的控制码。LED1发光的控制码为0xfe;LED1、LED2发光的控制码为0xfc;LED1、LED2、LED3发光的控制码为0xf8......LED1~LED8都发光的控制码为0x00;LED1发光的控制码为0xfe;LED1、LED2发光的控制码为0xfc...依次循环。

(2)程序设计

#include<reg51.h>

void delay(void)

{

unsigned char i,j;

for(i=0;i<200;i++)

for(j=0;j<200;j++)

;

}

void main(void)

{

do

{

P1=0xfe;  //LED1点亮

delay();  //延时

P1=0xfc;  //LED1、LED2点亮

delay();  //延时

P1=0xf8;  //LED1、LED2、LED3点亮

delay();  //延时

P1=0xf0;  //LED1~LED4点亮

delay();  //延时

P1=0xe0;  //LED1~LED5点亮

delay();  //延时

P1=0xc0;  //LED1~LED6点亮

delay();  //延时

P1=0x80;  //LED1~LED7点亮

delay();  //延时

P1=0x00;  //LED1~LED7点亮

delay();  //延时

}while(1);

}