单片机系统设计声光报警器

摘要

本次设计利用单片机、光学传感器、ADC、蜂鸣器等设计了一个声光报警装置。

采用PCF8591接收光照强度,并发送到数码管的后四位进行动态刷新显示,实现动态监测光强;

当光强超出安全范围(自行设定的光强上下阈值)时,实现报警功能,报警分为声光两部分,蜂鸣器发出声音(警笛鸣叫),流水灯实现警灯闪烁。

还有按键功能,按键S7选中光强上限,按键S6选中光强下限,S5\S4对光强上/下限进行修改:加10/减10功能;同时在数码管的前四位显示光强上限及光强下限的数值。

以及掉电保存,当关闭电源,重新打开后,可记忆光强上下限上次修改后的数值,采用AT24C02(EEPROM)进行掉电保存。

代码

AT2402.c

#include "AT24C02.h"

void delay_24(unsigned int i)
{
	while(i--)
		;
}
void write_24C02(unsigned char adrr,unsigned char dat)//单字节写入
{
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(adrr);
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_Stop();
}


unsigned char read_24C02(unsigned char adrr)//单字节读出
{
	unsigned char dat;
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(adrr);
	IIC_WaitAck();
	
	IIC_Start();
	IIC_SendByte(0xa1);
	IIC_WaitAck();
	dat=IIC_RecByte();
	IIC_SendAck(1);
	IIC_Stop();
	return dat;
}

main函数

#include "iic.h"
#include<STC15.h>
#include<intrins.h>
#include"AT24C02.h"


sbit HC138_A=P2^5;
sbit HC138_B=P2^6;
sbit HC138_C=P2^7;

//按键定义
sbit key_max=P3^0;	   //s7
sbit key_min=P3^1;	   //s6
sbit key_add=P3^2;     //s5
sbit key_sub=P3^3;     //s4

unsigned int light_max=200;
unsigned int light_min=50;

unsigned char key4_last=1;
unsigned char dis_buff[4];
unsigned char dis_buff0[4];
unsigned char dis_buff1[4];


unsigned char seg_code[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char table[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
unsigned char mode=0;
unsigned char flag=0;


void delay(unsigned char k)
{
	unsigned char i,j;
	for(;k>0;k--)
		for(i=0;i<10;i++)
			for(j=0;j<48;j++);
}				
void led(void)
{
   unsigned char i;
   HC138_C=1;
   HC138_B=0;
   HC138_A=0;
 if(mode==1)
 {
   for(i=0;i<3;i++)
   {
   P0=0x00;
   delay(60000);
   delay(60000);
   P0=0xff;
   delay(60000);
   delay(60000);
   }
   for(i=0;i<=8;i++)
   {
   P0=0xff<<i;
   delay(60000);
   delay(60000);
   }
   for(i=0;i<=8;i++)
   {
   P0=~(0xff<<i);
   delay(60000);
   delay(60000);
   }
}
}			  
unsigned char PCF8591_Read()
{
	unsigned char temp;
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	temp=IIC_RecByte();
	IIC_SendAck(1);
	IIC_Stop();
	return temp;
}
void PCF8591_Init()
{
	 IIC_Start();
	 IIC_SendByte(0x90);
	 IIC_WaitAck();
	 IIC_SendByte(0x01);
	 IIC_WaitAck();
	 IIC_Stop();
}
void display()
{
	unsigned char i;
	unsigned int dat=1;
	for(i=0;i<4;i++)
	{
		P0=0x00;
		P2=(P2&0x1f)|0xc0;
		P2=(P2&0x1f)|0x00;

		P0=seg_code[dis_buff[i]];
		P2=(P2&0x1f)|0xe0;
		P2=(P2&0x1f)|0x00;

		P0=0x01<<(7-i);
		P2=(P2&0x1f)|0xc0;
		P2=(P2&0x1f)|0x00;

		delay(1);
	}
}

void display_max()
{
	unsigned char i;
	unsigned int dat=1;
	for(i=0;i<4;i++)
	{
		P0=0x00;
		P2=(P2&0x1f)|0xc0;
		P2=(P2&0x1f)|0x00;

		P0=seg_code[dis_buff0[i]];
		P2=(P2&0x1f)|0xe0;
		P2=(P2&0x1f)|0x00;

		P0=0x01<<(3-i);
		P2=(P2&0x1f)|0xc0;
		P2=(P2&0x1f)|0x00;

		delay(1);
	}
}
void display_min()
{
	unsigned char i;
	unsigned int dat=1;
	for(i=0;i<4;i++)
	{
		P0=0x00;
		P2=(P2&0x1f)|0xc0;
		P2=(P2&0x1f)|0x00;

		P0=seg_code[dis_buff1[i]];
		P2=(P2&0x1f)|0xe0;
		P2=(P2&0x1f)|0x00;

		P0=0x01<<(3-i);
		P2=(P2&0x1f)|0xc0;
		P2=(P2&0x1f)|0x00;

		delay(1);
	}
}

void sys_init(void)
{
	P0=0xff;
	P2=(P2&0x1f)|0x80;
	P2=(P2&0x1f)|0x00;

	P0=0x00;
	P2=(P2&0x1f)|0xa0;
	P2=(P2&0x1f)|0x00;	
}
void baojing(void)
{
	if(mode==1)
	{
		
		P0=0x40;
		P2=0xa0;
		P2=0x00;
	}
	else
		{
		P0=0x00;
		P2=0xa0;
		P2=0x00;
		}
}
void keyscan(void) //按键函数
{
    if(key_max==0) //
	{
	   delay(10);
	   if(key_max==0)
	   {
	      flag=0;
		  while(!key_max)
			 {
			    display_max();
				display();
			 }
		}
	}
	if(key_min==0) //
	{
	   delay(10);
	   if(key_min==0)
	   {
	      flag=1;
		  while(!key_min)
			 {
			    display_min();
				display();
			 }
		}
	}
	if(key_add==0)
	{
	   delay(10);
	   if(key_add==0 && flag==0)
	   {
		  light_max=light_max+10;
		  write_24C02(0x00,light_max);//单字节写入
		  delay(10);
		  while(!key_add)
			 {
			    display_max();
				display();

			 }
		}
	   if(key_add==0 && flag==1)
	   {
		  light_min=light_min+10;
		  write_24C02(0xa0,light_min);//单字节写入
	      delay(10);
		  while(!key_add)
			 {
			    display_min();
				display();

			 }
		}
	}
	if(key_sub==0) 
	{
	   delay(10);
	   if(key_sub==0 && flag==0)
	   {
		  light_max=light_max-10;
		  write_24C02(0x00,light_max);//单字节写入
		  delay(10);
		  while(!key_sub)
			 {
			    display_max();
				display();

			 }
		}
	   if(key_sub==0 && flag==1)
	   {
		  light_min=light_min-10;
		  write_24C02(0xa0,light_min);//单字节写入
	      delay(10);
		  while(!key_sub)
			 {
			    display_min();
				display();
				
			 }
		}
	}

} 


void main()
{
	unsigned char light_val;
	sys_init();
	PCF8591_Init();
   	light_max=read_24C02(0x00);//单字节读出
    light_min=read_24C02(0xa0);
	while(1)
	{

	    keyscan();
		light_val=PCF8591_Read();
		if(light_val>=light_max||light_val<=light_min)
			{
			mode=1;
			}
		else
			mode=0;
	  baojing();
	  led();
		dis_buff[3]=light_val/1000;
		dis_buff[2]=light_val%1000/100;
		dis_buff[1]=light_val%100/10;
		dis_buff[0]=light_val%10;

		dis_buff0[3]=light_max/1000;
		dis_buff0[2]=light_max%1000/100;
		dis_buff0[1]=light_max%100/10;
		dis_buff0[0]=light_max%10;

        dis_buff1[3]=light_min/1000;
		dis_buff1[2]=light_min%1000/100;
		dis_buff1[1]=light_min%100/10;
		dis_buff1[0]=light_min%10;
		display();

	}
}

 iic.c

#include "reg52.h"
#include "intrins.h"
#include "iic.h"

#define DELAY_TIME 5

//#define SlaveAddrW 0xA0
//#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
	IIC_Delay(DELAY_TIME);
	da <<= 1;
	if(SDA) da |= 1;
	SCL = 0;
	IIC_Delay(DELAY_TIME);
    }
    return da;    
}
  1. 设计任务

利用单片机、光学传感器、ADC、蜂鸣器等设计一个声光报警装置。系统功能可以分为基础功能和发挥部分,基础功能必须实现,扩展功能可自行选择。

  1. 功能要求

    基础功能:

  1. 该声光报警器能够测量光照强度,并通过数码管显示。
  2. 当光照强度超过安全范围,报警器发出声光报警,警灯闪烁(用流水灯模拟),警笛鸣叫(用蜂鸣器模拟)。
  3. 安全范围有上下限,均可通过按键修改。

扩展功能:

  1. 报警光强参数可以用EEPROM保存,系统开机后从EEPROM读取参数配置系统,参数通过按键修改后,应保存到EEPROM
  2. 能够将最近100次测量结果保存到EEPROM中,保存方法可以设为自动保存和手动保存,自动保存为每隔一段时间自动记录光强,手动保存为通过按键保存,测量结果可以通过按键调出查看。
  3. 配置实时时钟,记录测量结果时同时记录系统时间。
  4. 系统参数设定、测量结果查看等,用LCD作为显示部件。

  1. 系统设计框图

  1. 系统概述

将声光报警器的设计分为5个模块,光度传感模块、数码管显示模块、流水灯模块、蜂鸣器模块、按键功能模块及断电保存的EEPROM的读写模块。分步编写程序后整合,最终实现声光报警器的程序设计。

  1. PCF8591

PCF8591是一款单芯片、单电源、低功耗8位CMOS数据采集设备

具有四个模拟输入、一个模拟输出和一个串行12c总线接口。

三个地址引脚AO, A1和A2用于编程硬件地址,允许使用多达8个设备连接到12c总线而不需要额外的硬件。

地址、控制和数据通过两路双向12c总线串行地传送到和从设备。

该装置的功能包括模拟输入多路复用、片上跟踪和保持功能、8位模数转换和8位数模转换。最大转换速率由12c总线的最大速度给出。

标志

引脚

描述

AIN0

1

模拟输入通道1(A/D转换器)

AIN1

2

模拟输入通道2(A/D转换器)

AIN2

3

模拟输入通道3(A/D转换器)

AIN3

4

模拟输入通道4(A/D转换器)

A0

5

硬件地址

A1

6

硬件地址

A2

7

硬件地址

Vss

8

负电源电压

SDA

9

IIC数据输入/输出

SCL

10

IIC时钟

OSC

11

振荡器input output

EXT

12

振荡器输入的外部和内部开关

AGND

13

模拟地

Vref

14

参考电压输入

AOUT

15

模拟输出(D/A转换器)

Vdd

16

正极

D/A转换过程:

IIC开始信号->PCF8591地址写->等待PCF8591回应->控制字节->等待PCF8591回应->DAC的值->等待PCF

D/A转换过程:

IIC开始信号->PCF8591地址写->等待PCF8591回应->控制字节->等待PCF8591回应->DAC的值->等待PCF8591回应->DAC的值

A/D转换过程:

IIC开始信号->地址读->等待PCF8591回应->PCF8591->主机回应->继续读->主机回应…->直到想停止AD转换了->不回应了->直接停止信号

蓝桥杯板子上面PCF8591的地址为:

写地址为:0x90

读地址为:0x91


2、AT24C02

AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息。
存储介质:E2PROM
通讯接口:I2C总线
容量:256字节

应用电路:

引脚:

引脚

功能

A0-A2

地址输入

SDA

串行数据

SCL

串行时钟输入

WP

写保护

NC

No Connect

GND

3、I2C总线

I2C总线介绍:

1、I2C总线(Inter IC bus)是由Philips公司开发的一种通用数据总线。

2、两根通信线:SCL(Serial Clock串行时钟线)、SDA(Seriak Data串行数据线)。

3、同步、半双工,带数据应答。

I2C电路规范:

1、所有I2C设备的SCL连在一起,SDA连在一起

2、设备的SCL和SDA均要配置成开漏输出模式

3、SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右

开漏输出和上拉电阻的共同作用实现了“线与”的功能,此设计主要是为了解决多机通信互相干扰的问题

I2C时序结构:

  • 起始条件:SCL高电平期间,SDA从高电平切换到低电平
  • 终止条件:SCL高电平期间,SDA从低电平切换到高电平

  • 发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

  • 接收一个字节:SCL低电平期间,从机将数据位依次放到SDA总线上(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

  • 发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
  • 接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

  1. AT24C02(EEPROM)掉电保存

写模块

void write_24C02(unsigned char adrr,unsigned char dat)//单字节写入

{

        IIC_Start();

        IIC_SendByte(0xa0);

        IIC_WaitAck();

        IIC_SendByte(adrr);

        IIC_WaitAck();

        IIC_SendByte(dat);

        IIC_WaitAck();

        IIC_Stop();

}

读模块

unsigned char read_24C02(unsigned char adrr)//单字节读出

{

        unsigned char dat;

        IIC_Start();

        IIC_SendByte(0xa0);

        IIC_WaitAck();

        IIC_SendByte(adrr);

        IIC_WaitAck();

       

        IIC_Start();

        IIC_SendByte(0xa1);

        IIC_WaitAck();

        dat=IIC_RecByte();

        IIC_SendAck(1);

        IIC_Stop();

        return dat;

}

  1. 采集光强信息

light_val=PCF8591_Read();

unsigned char PCF8591_Read()

{

        unsigned char temp;

        IIC_Start();

        IIC_SendByte(0x91);

        IIC_WaitAck();

        temp=IIC_RecByte();

        IIC_SendAck(1);

        IIC_Stop();

        return temp;

}

void PCF8591_Init()

{

         IIC_Start();

         IIC_SendByte(0x90);

         IIC_WaitAck();

         IIC_SendByte(0x01);

         IIC_WaitAck();

         IIC_Stop();

}

  1. 数码管显示模块

void display()

{

        unsigned char i;

        unsigned int dat=1;

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

        {

                 P0=0x00;

                 P2=(P2&0x1f)|0xc0;

                 P2=(P2&0x1f)|0x00;

                 P0=seg_code[dis_buff[i]];

                 P2=(P2&0x1f)|0xe0;

                 P2=(P2&0x1f)|0x00;

                 P0=0x01<<(7-i);

                 P2=(P2&0x1f)|0xc0;

                 P2=(P2&0x1f)|0x00;

                 delay(1);

        }

}

  1. 声光报警模块

光模块

void led(void)

{

   unsigned char i;

   HC138_C=1;

   HC138_B=0;

   HC138_A=0;

 if(mode==1)

 {

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

   {

    P0=0x00;

    delay(60000);

    delay(60000);

    P0=0xff;

    delay(60000);

    delay(60000);

   }

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

   {

    P0=0xff<<i;

    delay(60000);

    delay(60000);

   }

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

   {

    P0=~(0xff<<i);

    delay(60000);

    delay(60000);

   }

}

}

蜂鸣器模块

void baojing(void)

{

        if(mode==1)

        {

                

                 P0=0x40;

                 P2=0xa0;

                 P2=0x00;

        }

        else

                 {

                 P0=0x00;

                 P2=0xa0;

                 P2=0x00;

                 }

}

                          

  1. 按键功能模块

void keyscan(void) //按键函数

{

    if(key_max==0) //光强上限

        {

           delay(10);

           if(key_max==0)

           {

              flag=0;

                  while(!key_max)

                          {

                             display_max();

                                 display();

                          }

                }

        }

        if(key_min==0) //光强下限

        {

           delay(10);

           if(key_min==0)

           {

              flag=1;

                  while(!key_min)

                          {

                             display_min();

                                 display();

                          }

                }

        }

        if(key_add==0)         //10

        {

           delay(10);

           if(key_add==0 && flag==0)

           {

                  light_max=light_max+10;

                  write_24C02(0x00,light_max);//单字节写入

                  delay(10);

                  while(!key_add)

                          {

                             display_max();

                                 display();

                          }

                }

           if(key_add==0 && flag==1)

           {

                  light_min=light_min+10;

                  write_24C02(0xa0,light_min);//单字节写入

              delay(10);

                  while(!key_add)

                          {

                             display_min();

                                 display();

                          }

                }

        }

        if(key_sub==0)          //10

        {

           delay(10);

           if(key_sub==0 && flag==0)

           {

                  light_max=light_max-10;

                  write_24C02(0x00,light_max);//单字节写入

                  delay(10);

                  while(!key_sub)

                          {

                             display_max();

                                 display();

                          }

                }

           if(key_sub==0 && flag==1)

           {

                  light_min=light_min-10;

                  write_24C02(0xa0,light_min);//单字节写入

              delay(10);

                  while(!key_sub)

                          {

                             display_min();

                                 display();

                                

                          }

                }

        }

}

烧写hex文件,单片机数码管的后四位动态刷新显示了光照强度,实现动态监测光强;

当光强超出安全范围(自行设定的光强上下阈值)时,开始报警,蜂鸣器发出声音(警笛鸣叫),流水灯实现(警灯闪烁)。

按下按键S7选中光强上限,按键S6选中光强下限,并在数码管的前四位显示光强上限及光强下限的数值。按下S5对光强上/下限(通过上一次按下S7或S6进行判断)进行加10修改,并显示;按下S4对光强上/下限(通过上一次按下S7或S6进行判断)进行减10修改,并显示对应的光强上/下限参数及实时光照强度。

实现掉电保存,当关闭电源并重新打开后,系统记忆上次修改后的光照强度上/下限的参数。

功能测试成功。

 本实验成功利用单片机、光学传感器、ADC、蜂鸣器等设计了一个声光报警装置。实现声光报警器的程序设计,实现了基础功能的1、2、3及拓展功能的1。

采用PCF8591接收光照强度,并发送到数码管的后四位进行动态刷新显示,实现动态监测光强;当光强超出安全范围(自行设定的光强上下阈值)时,实现报警功能,报警分为声光两部分,蜂鸣器发出声音(警笛鸣叫),流水灯实现警灯闪烁。还有按键功能,按键S7选中光强上限,按键S6选中光强下限,S5\S4对光强上/下限进行修改:加10/减10功能;同时在数码管的前四位显示光强上限及光强下限的数值。以及掉电保存,当关闭电源,重新打开后,可记忆光强上下限上次修改后的数值,采用AT24C02(EEPROM)进行掉电保存。

通过多次的功能测试及程序修改,最后完成实验。

本次实验中也遇到了一些困难,当实现掉电保存功能时,由于  light_max=read_24C02(0x00); light_min=read_24C02(0xa0);//单字节读出

write_24C02(0x00,light_max); write_24C02(0xa0,light_min);//单字节写入

时没有插入到程序的正确位置,导致无法实现掉电保存,经过思考,多次修改位置,最后实现。

  • 20
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值