单片机应用技术项目教程(微课版)
上QQ阅读APP看书,第一时间看更新

1.4 任务3 声光报警器

工作任务

利用C语言控制程序,从单片机P2.0引脚上输出报警信号,并对P1.0引脚上的LED进行闪烁控制,实现声光报警器设计、运行与调试。

1.4.1 声光报警器电路设计

按照任务要求,声光报警器电路将由单片机最小系统、声音控制电路和LED电路构成,如图1-32所示。

图1-32 声光报警器电路

其中,声音控制电路由放大驱动电路和扬声器构成。放大驱动电路由PNP三极管VT1和电阻R3构成,VT1的基极经电阻R3接到P2.0引脚。

在声光报警器电路中,添加的元器件有AT89C52单片机(修改为STC89C52)、CRYSTAL(晶振)、CAP(电容)、CAP-ELEC(电解电容)、RES(电阻)、BUTTON(按键)、LED-RED(红色发光二极管)、SPEAKER(扬声器)以及2N5771(PNP三极管)等。

声光报警器Proteus仿真电路的设计过程与任务1基本一样,这里只给出不同的设计过程,不再赘述具体设计过程了。

1.4.2 声光报警器程序设计

1. 声光报警器功能实现分析

声光报警器是在单片机P2.0引脚上输出脉冲方波,方波经放大后,驱动扬声器进行声音报警,声音的频率高低由延时长短来控制。同时,声光报警器还通过P1.0引脚输出脉冲方波,控制该引脚所接的LED进行闪烁报警。

声光报警器的功能实现过程如下。

(1)在P2.0和P1.0引脚输出低电平。

(2)延时。

(3)在P2.0和P1.0引脚输出高电平。

(4)延时。

(5)重复第一步(循环),这样就可以实现声光报警器功能。

2. 声光报警器程序设计

从以上分析可以得出,声光报警器的C语言程序如下:

#include <reg52.h>          //包含reg52.h头文件 
sbit SPK=P2^0;              //定义SPK 是P2.0 位对应的引用符号 
sbit LED=P1^0;              //定义LED 是P1.0 位对应的引用符号 
void  Delay()               //延时函数 
{ 
    unsigned char i, j; 
     for (i=0;i<255;i++) 
         for (j=0;j<255;j++); 
} 
void main() 
{  
while(1) 
     { 
         SPK = 0;              //P2.0=0,输出低电平 
         LED = 0;              //P1.0=0,LED 点亮 
         Delay();              //延时 
         SPK = 1;              //P2.0=1,输出高电平 
         LED = 1;              //P1.0=1,LED 熄灭 
         Delay(); 
   } 
} 

完成声光报警器程序设计后,生成“声光报警器.hex”文件。

3. 声光报警器Proteus仿真运行调试

(1)运行Proteus软件,打开声光报警器Proteus仿真电路。

(2)加载Keil生成的“声光报警器.hex”文件。

(3)单击仿真工具栏的“运行”按钮50421-00-038-1,单片机全速运行程序。

通过编辑区的声光报警器电路图,观察声光报警器是否与设计要求相符。同时还可以通过P2.0和P1.0引脚的电平变化状态,间接分析声光报警器的工作规律。

【技能训练1-2】开关控制声光报警器

任务3只是通过C语言控制程序来完成声光报警器设计。如果需要通过开关来控制声光报警器工作,并要求报警信号以1kHz信号100ms、500Hz信号200ms交替进行,该如何实现呢?

1. 单片机输入输出

单片机最小系统常见的输入部件有开关、按钮、键盘、鼠标等,输出部件有指示灯LED、数码管、显示器等;执行部件有继电器、电磁阀等。

2. 开关控制声光报警器电路设计

开关控制声光报警器电路由单片机最小系统、输入电路和输出电路三部分组成。其中,单片机最小系统由AT89C52单片机、晶振电路和上电复位电路构成,输入电路是开关电路,输出电路是声光报警电路。

在图1-32的基础上,添加一个开关(SWITCH)。开关一个引脚接地,另一个引脚接P3.0引脚,同时经上拉电阻接+5V电源,如图1-33所示。

图1-33 开关控制声光报警器电路

3. 开关控制声光报警器程序设计

根据开关控制声光报警器电路的设计和功能要求,在开关控制下,通过P2.0和P1.0引脚输出报警信号,报警信号按1kHz信号100ms、500Hz信号200ms交替进行。开关合上,声光报警器开始工作;开关断开,声光报警器停止工作。参考程序如下:

#include <reg52.h> 
#include <INTRINS.H>        //因为使用空操作,所以要包含INTRINS.H 头文件 
sbit SPK=P2^0;  
sbit LED=P1^0;  
sbit SW=P3^0;  
unsigned char count; 
void delay500(void)         //延时500us,即0.5ms 
{  
      unsigned char i;  
      for(i=250;i>0;i--)  
       {  
           _nop_();  
       }  
} 
void  main() 
{ 
       while(1) 
     { 
   if(SW==0)                 //判断开关是否闭合,SW为0 表示开关闭合 
         {  
            for(count=200;count>0;count--)      //1KHz 信号100ms 
              {  
                   SPK=~SPK; 
     LED=~LED;  
                    delay500();  
              }  
              for(count=200;count>0;count--)    //500Hz信号200ms 
              {  
                  SPK=~SPK; 
    LED=~LED;  
                  delay500();  
              }  
         } 
     } 
} 

1.4.3 C语言程序的基本构成

随着单片机开发技术的不断发展,目前已有越来越多的人从使用汇编语言开发转变到使用高级语言开发,其中以C语言为主。市场上几种常见的单片机均有其C语言开发环境。本节以最为流行的STC89C52单片机为例,来学习单片机的C语言编程技术。

1. C语言程序的构成

(1)C语言程序由一个或多个函数构成。最简单的程序只有一个main函数,如任务1的“点亮一个LED”C语言程序。在一个C语言程序中必须有一个且仅有一个main函数。除了main函数,还可以有其他函数,由于这些函数是由用户根据需要自行设计的,因此称为自定义函数,如任务2的“LED闪烁”C语言程序中的Delay()函数。另外,在C语言程序中,由C语言本身提供的函数称为库函数。

那么,库函数和用户自定义函数有什么区别呢?简单地说,任何使用Keil C语言开发的人,都可以直接调用C语言的库函数而不需要为这个函数编写任何代码,只需要包含具有该函数说明的相应的头文件即可;而自定义函数则是完全个性化的,是用户根据需要编写的。Keil C提供了100多个库函数供开发人员直接使用。

一个C语言程序总是从main函数开始执行,而不管物理位置上main()函数放在什么地方。在“LED闪烁”C语言程序中,main()放在了最后,事实上这也是最常用的一种方式。

(2)一个函数由以下两部分组成。

①函数首部,即函数的第一行。包括函数名、函数类型、函数属性、函数参数(形参)名、参数类型。

如:void Delay()。

函数名后面必须跟一对圆括号,即便没有任何参数也必须如此。

②函数体,即函数首部下面的大括号“{}”内的部分。如果一个函数内有多个大括号,则最外层的一对“{}”为函数体的范围。函数体一般包括:

声明部分:定义所用到的变量,如void Delay()中的unsigned char i, j;。

执行部分:由若干个语句组成。

在某些情况下也可以没有声明部分,甚至既没有声明部分,也没有执行部分,如:

void Delay() 
{} 

这是一个空函数,什么也不执行,但它是合法的。

在编写程序时,可以充分利用空函数。比如主程序需要调用一个延时函数,可是具体延时多少,怎么延时,暂时还不清楚,就可以先把主程序的框架结构定义好,编译通过了再说。至于里面的细节,可以在以后慢慢填写,这样在主程序中就可以调用它了。

2. 标识符

变量名、常数名、数组名、函数名、文件名与类型名等统称为标识符。C语言规定标识符只能由字母、数字和下划线3种字符组成,且第1个字符必须为字母或下划线,如“1A”在编译时便会有错误提示。要注意的是,C语言中的大写字母与小写字母被认为是不同的字符,即Sum与sum是两个不同的标识符。

标识符可以分为预定义标识符和用户标识符。标准库函数的名字,如printf、sqrt、pow与sin等,还有预编译处理命令,如define与include等,都属于预定义标识符。而用户标识符则是由用户根据需要定义的标识符。如用户定义的变量名a、b、sum与x1等,用户定义的函数名f1、rep、facto与sort等。

标识符命名应当简单,含义清晰,有助于理解程序。标准的C语言并没有规定标识符的长度,但是各个C编译系统有自己的规定,在Keil C编译器中,只将标识符的前32位作为有效标识。

3. 关键字

关键字是编程语言保留的特殊标识符,它们具有固定的名称和含义,在程序编写中,不允许标识符与关键字同名。在Keil C中除了支持ANSI C标准的32个关键字,还根据51单片机的特点扩展了相关的关键字。

在Keil C的文本编辑器中编写C程序,系统会把保留字以不同颜色显示,默认颜色为蓝色。

1.4.4 C语言基本语句

C语言程序由一个或多个函数组成,而函数又由若干个语句组成。语句则由一些基本字符和定义符按照C语言的语法规定组成,每个语句以分号结束,分号是C语句的必要组成部分。C语言的语句可分为以下5种类型:表达式语句、函数调用语句、控制语句、复合语句和空语句。

1. 表达式语句

表达式语句是由一个表达式加一个分号构成的,其作用是计算表达式的值或改变变量的值。它的一般形式是:

表达式;

即在表达式末尾加上分号,就变成了表达式语句。最典型的表达式语句是:在赋值表达式后加一个分号构成赋值语句。例如:

a=3

是一个赋值表达式,而

a=3;

是一个赋值语句。

2. 函数调用语句

一个函数调用加一个分号就构成了函数调用语句,其作用是完成特定的功能。函数调用语句的一般形式是:

函数名(参数列表);

例如:

mDelay(100);  //调用延时函数,参数是100 

3. 控制语句

控制语句用于完成一定的控制功能,以实现程序的各种结构。C语言有9种控制语句,可分为以下3类。

(1)条件判断语句:if语句、switch语句。

(2)循环语句:for语句、while语句、do-while语句。

(3)转向语句:break语句、continue语句、goto语句、return语句。

4. 复合语句

复合语句用一对大括号将若干条语句括起来,也称为分程序,在语法上相当于一条语句。例如:

main() 
{…… 
   {t=x; 
    x=y; 
    y=t;}    //复合语句 
} 

5. 空语句

只有一个分号的语句称为空语句。它的一般形式是:

;

空语句是什么操作也不执行,常作为循环语句中的循环体,表示循环体什么也不做。

由于C语言程序的书写格式是自由的,所以一个语句可写在一行上,也可分写在多行内。一行内可以写一个语句,也可以写多个语句。缩进没有具体要求,但是建议读者按一定的规范来写,可以给后期维护带来方便。

注释内容可以单独写在一行,也可以写在一个语句之后。可以采用/ *……* /的形式为C程序的任何一部分作注释,从“/ *”开始,到“* /”为止的内容都将被认为是注释,所以在书写时特别是修改源程序时要特别注意。Keil C也支持C++风格的注释,即“//”后面的语句也认为是注释,例如:

P1_0=!P1_0;  //P1.0 引脚输出取反 

这种风格的注释只对本行有效,书写也比较方便,所以在只需要一行注释的时候,我们往往采用这种格式。