摘要
本次设计利用单片机、光学传感器、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;
}
利用单片机、光学传感器、ADC、蜂鸣器等设计一个声光报警装置。系统功能可以分为基础功能和发挥部分,基础功能必须实现,扩展功能可自行选择。
基础功能:
- 该声光报警器能够测量光照强度,并通过数码管显示。
- 当光照强度超过安全范围,报警器发出声光报警,警灯闪烁(用流水灯模拟),警笛鸣叫(用蜂鸣器模拟)。
- 安全范围有上下限,均可通过按键修改。
扩展功能:
- 报警光强参数可以用EEPROM保存,系统开机后从EEPROM读取参数配置系统,参数通过按键修改后,应保存到EEPROM。
- 能够将最近100次测量结果保存到EEPROM中,保存方法可以设为自动保存和手动保存,自动保存为每隔一段时间自动记录光强,手动保存为通过按键保存,测量结果可以通过按键调出查看。
- 配置实时时钟,记录测量结果时同时记录系统时间。
- 系统参数设定、测量结果查看等,用LCD作为显示部件。
将声光报警器的设计分为5个模块,光度传感模块、数码管显示模块、流水灯模块、蜂鸣器模块、按键功能模块及断电保存的EEPROM的读写模块。分步编写程序后整合,最终实现声光报警器的程序设计。
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)
- 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;
}
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();
}
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 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;
}
}
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);//单字节写入
时没有插入到程序的正确位置,导致无法实现掉电保存,经过思考,多次修改位置,最后实现。