原理图:Altium Designer
仿真版本:proteus7.8
程序编译器:keil 4
设计编号:C0039
功能介绍:
1、单片机采用内置AD的51系列单片机,型号为STC89c52;
2、温度采集采用DS18B20传感器;
3、火灾烟雾检测采用MQ-2传感器,此传感器输出量也为模拟量,需接到单片机的AD端口上进行采集;
4、防盗检测采用HC-SR501热释电红外感应传感器,通过配合板载设防开关进行防盗的检测;
5、报警部分分为板载蜂鸣器鸣笛报警和GSM短信报警功能,GSM采用SIM800模块,当温度,烟雾浓度,防盗触发时GSM短信模块发送报警短信到指定的手机号码上。
6、手机可以发送指令关闭继电器或打开继电器,给单片机打电话会回复短信单片机检测的当前温度。
资料下载链接(可点击)
仿真图(提供源文件):
原理图(提供源文件):
PCB(源文件):
程序(提供源文件源码):
#include <main.h>
void Waring_Processing(void)
{
//温度超标//烟雾超标
if((Temperature >= Temp_H) ||( MQ_Value>= MQ_2))
{
BEEP_Cnt = 55;
if(SMS_Enable_Time == 0)
{
SMS_States_Register |= (1 << SMS_TXD_ENA);
SMS_Enable_Time = 30; //30秒内只发一条短信
SMS_Retry = 3;
SMS_Type = 0;
}
}
}
void main(void)
{
alarm_1 = 0;
EEPROM_Init();
LcmInit();
DS18B20_Init();
Time0_Init();
UART0_Init();
KEY_Init();
EA = 1;
while(1)
{
Waring_Processing();
KEY_Processing();
UART0_Processing();
SMS_Processing();
DS18B20_Processing();
ADC0832_Processing();
IR_Processing();
EEPROM_Processing();
}
}
/*
DS1820/DS18B20 数字温度传感器通用程序库
说明:该模块化程序库包含了数字温度传感器DS1820/DS18B20测温所需的相关
函数。可以作为各种测温程序的底层硬件驱动使用。
要使用该库函数,需要将本文件(18x20.c)添加进工程,并在需要调用
测温相关函数的文件开头处包含"18x20.h"
注意,本程序适用的晶振频率范围为8-14MHz(指令周期1us左右)。
如果时钟频率差别较大,需要修改Delay10()函数,使之大约10us左右,
并修改Delay15()函数,使之大约15us左右。
*/
//
// VCC
// MCU=89x51/52 --- 长线时DQ脚要上拉
// +---------------+ |
// | | | 数字温度传感器
// | | +---+------------------+
// | | | |
// | P3.7 |<----->| DS18B20 / DS1820 |
// | | DQ | |
// | | +----------------------+
// | | |
// | | |
// | | |
// +---------------+ ---
// GND
#include <18X20.h>
sbit DQ=P3^7; /* DS18B20数据引脚定义 */
bit TEMP_EA;
#define DISABLE_INT; TEMP_EA=EA; EA=0; /*关闭中断的宏定义*/
#define RESTORE_INT; EA=TEMP_EA; /*恢复中断的宏定义*/
/****************************************************************************
* 名 称:Delay10()
* 功 能:延迟10us
* 入口参数:无
* 出口参数:无
* 说 明: 指令周期1us时,延迟恰好10us,晶振改变延迟时间也会随之改变
****************************************************************************/
void Delay10()
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_(); // 6个NOP + 3周期LCALL(调用该函数) +1周期RET(返回)
_nop_(); // = 10个指令周期
}
/****************************************************************************
* 名 称:Delay15()
* 功 能:延迟15us
* 入口参数:无
* 出口参数:无
* 说 明: 指令周期1us时,延迟恰好15us,晶振改变延迟时间也会随之改变
****************************************************************************/
void Delay15()
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_(); // 11个NOP + 3周期LCALL(调用该函数) +1周期RET(返回)
_nop_(); // = 15个指令周期
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
/****************************************************************************
* 名 称:Delay30x()
* 功 能:延迟30us的倍数(会差几个周期)
* 入口参数:Time:30us的倍数
* 出口参数:无
* 范 例: Delay30x(3); //延迟90us左右
****************************************************************************/
void Delay30x(unsigned char Time)
{ if(Time==0) return; //Time=0次,不执行
for(;Time>0;Time--) //循环Time次
{
Delay15(); //每次延迟15us,加上循环,大约28us。
}
}
/****************************************************************************
* 名 称:OW_Reset()
* 功 能:向1-Wire总线上发送一个复位指令。
* 入口参数:无
* 出口参数:1:表示复位操作成功
0:表示复位操作失败
****************************************************************************/
bit OW_Reset(void)//复位
{ unsigned char i;
DISABLE_INT; // 时序要求严格,不允许中断
DQ = 0; //pull DQ line low
Delay30x(30); // leave it low for 480~960us (700uS)
DQ = 1; // allow line to return high
Delay30x(2); // wait for presence 15~60uS ( 56uS)
for(i=0;i<30;i++)
{
if (DQ==0)
{
while(!DQ) {};// 复位成功,等待复位结束
RESTORE_INT;
return(1); // 并返回1,表示有器件
}
Delay15(); // 不成功,可能是1820反应慢,重试30次
}
RESTORE_INT;
return(0);// 到达240uS等待最大值,放弃.返回0,表示无器件
}
/****************************************************************************
* 名 称:OW_ReadByte()
* 功 能:从 1-wire 总线上读取一个字节。
* 入口参数:无
* 出口参数:读回的1字节数据
****************************************************************************/
unsigned char OW_ReadByte(void)
{
unsigned char i;
unsigned char value = 0;
for (i=8;i>0;i--) // 读取8比特循环8次,组成1字节
{
DISABLE_INT; // 时序要求严格,不允许中断
value>>=1;
DQ = 0; // 将DQ脚拉低,表示写比特时序开始
_nop_();
_nop_(); // 保持低,1uS以上 (3uS)
DQ = 1; // 将DQ脚拉高
Delay10(); // 延迟1uS~15uS (取10uS)
if(DQ) value|=0x80;// 读取DQ的值
Delay30x(5); // wait for rest of timeslot
RESTORE_INT; // 恢复中断
}
return(value);
}
/****************************************************************************
* 名 称:OW_WriteByte()
* 功 能:向 1-WIRE 总线上写一个字节。
* 入口参数:Val:写入的1字节数据
* 出口参数:无
****************************************************************************/
void OW_WriteByte(unsigned char Val)
{
unsigned char i;
for (i=8; i>0; i--) // 写入8比特循环8次,共计1字节
{
DISABLE_INT; // 时序要求严格,不允许中断
DQ = 0; // 将DQ脚拉低保持1uS以上 (3uS)
DQ = Val&0x01; // 先发低字节
Delay30x(3); // 保持数据 60~120uS (取85uS)
DQ = 1; // DQ拉高
Val=Val>>1; // 取下一比特
Delay15(); // 比特间延迟1us以上(取15us)
RESTORE_INT; // 恢复中断
}
}
/****************************************************************************
* 名 称:DS1820_Conv()
* 功 能:向18B20发指令:开始温度测量与转换。
* 入口参数:无
* 出口参数:无
* 说 明: 该命令发出后,必须等待至少500-700ms才能测量完毕,之后才能读取数据。
****************************************************************************/
void DS1820_Conv()
{
OW_Reset(); // 复位18B20
OW_WriteByte(0xCC); // Skip ROM(不进行序列号识别)
OW_WriteByte(0x44); // 开始转换
}
/****************************************************************************
* 名 称:DS1820_GetFamily()
* 功 能:读取18x20的家族代码。
* 入口参数:无
* 出口参数:读回的家族号。
* 说 明: 0x10表示DS1820,0x28表示DS18B20,更多系列请参照官方数据手册
****************************************************************************/
unsigned char DS1820_GetFamily()
{ unsigned char FamilyID;
OW_Reset(); // 复位18B20
OW_WriteByte(0x33); // 发出获取家族代码命令
FamilyID=OW_ReadByte(); // 读取家族号
return(FamilyID); // 返回
}
/****************************************************************************
* 名 称:DS1820_GetTemp()
* 功 能:读取18x20的温度测量结果。注意要在DS1820_Conv()命令至少之后700ms以
后调用,才能读取准确的温度值。
* 入口参数:无
* 出口参数:温度数值,保留1位小数。
返回0x8001表示未检测到器件
返回0x8002表示无法识别的器件
* 范 例: 返回123表示12.3度;-345表示-34.5度,依此类推
****************************************************************************/
int DS1820_GetTemp()
{
unsigned char tempH,tempL,Family;
if(OW_Reset()==0) return(0x8001);// 若复位不成功说明无器件,返回0x8001
Family=DS1820_GetFamily(); // 读取1820的家族代码
OW_Reset(); // 复位,结束读取家族代码的操作
OW_WriteByte(0xCC); // Skip ROM(不进行序列号识别)
OW_WriteByte(0xBE); // 发出读取数据的指令
Delay30x(5); // 略延迟
tempL=OW_ReadByte(); // 读取温度转换结果_低8位
tempH=OW_ReadByte(); // 读取温度转换结果_高8位
if (Family==0x28) // 如果是DS18B20系列
{
return ((tempH*256+tempL)*(long)625/1000);//计算温度,保留1位小数
}
else if(Family==0x10) // 如果是DS1820系列(比18B20更老的型号)
{
return ((tempH*256+tempL)*5);//计算温度,保留1位小数
}
else return(0x8002); //其它型号无法识别 返回0x8002
}
void DS18B20_Init(void)
{
DS1820_GetTemp(); //读取上次测温结果
// PutTemp(1,3,Temperature);
//LED_DisplayDecimal(Temperature,1); //显示测温结果,保留1位小数
DS1820_Conv(); //发送下一次测温开始命令
DS1820_GetTemp(); //读取上次测温结果
// PutTemp(1,3,Temperature);
//LED_DisplayDecimal(Temperature,1); //显示测温结果,保留1位小数
DS1820_Conv(); //发送下一次测温开始命令
DS1820_GetTemp(); //读取上次测温结果
// PutTemp(1,3,Temperature);
//LED_DisplayDecimal(Temperature,1); //显示测温结果,保留1位小数
DS1820_Conv(); //发送下一次测温开始命令
}
volatile int Temperature;
void DS18B20_Processing(void)
{
if(Time0_2s_Flag) //2ms累加500次共计1秒
{
Time0_2s_Flag = 0; //以下代码每隔2秒执行一次
Temperature = DS1820_GetTemp(); //读取上次测温结果
PutTemp(1,3,Temperature);
//LED_DisplayDecimal(Temperature,1); //显示测温结果,保留1位小数
DS1820_Conv(); //发送下一次测温开始命令
}
}
ADC0832驱动程序
#include <ADC0832.H>
unsigned char Get_AD_Result(bit CH)
{
unsigned char i;
unsigned char dat;
ADC0832_CS=1; //一个转换周期开始
ADC0832_CLK=0; //为第一个脉冲作准备
ADC0832_CS=0; //CS置0,片选有效
ADC0832_DIO=1; //DIO置1,规定的起始信号
ADC0832_CLK=1; //第一个脉冲
ADC0832_CLK=0; //第一个脉冲的下降沿,此前DIO必须是高电平
ADC0832_DIO=1; //DIO置1, 通道选择信号
ADC0832_CLK=1; //第二个脉冲,第2、3个脉冲下沉之前,DI必须跟别输入两位数据用于选择通道,这里选通道RH0
ADC0832_CLK=0; //第二个脉冲下降沿
ADC0832_DIO=CH; //DI置0,选择通道0
ADC0832_CLK=1; //第三个脉冲
ADC0832_CLK=0; //第三个脉冲下降沿
ADC0832_DIO=1; //第三个脉冲下沉之后,输入端DIO失去作用,应置1
ADC0832_CLK=1; //第四个脉冲
for(i=0;i<8;i++) //高位在前
{
ADC0832_CLK=1; //第四个脉冲
ADC0832_CLK=0;
dat<<=1; //将下面储存的低位数据向右移
dat|=(unsigned char)ADC0832_DIO; //将输出数据DIO通过或运算储存在dat最低位
}
ADC0832_CS=1; //片选无效
return dat; //将读书的数据返回
}
volatile unsigned char MQ_Value;
void ADC0832_Processing(void)
{
if(Time0_1s_Flag2)
{
Time0_1s_Flag2 = 0;
MQ_Value = Get_AD_Result(0);
PutNum(2,3,MQ_Value);
}
}
按键扫描函数
#include <KEY.H>
volatile unsigned char KEY_Value = 0;
void KEY_Init(void)
{
P1 |= 0X20;
P3 |= 0X24;
}
unsigned char KEY_Read(void)
{
unsigned char a;
a = (P1 & 0x20) + ((P3&0x24)>>1);
return a;
}
void KEY_Scan(void) //每20m调用一次
{
unsigned char KEY_Data;
static unsigned char KEY_Cont = 0;
static unsigned char KEY_Counter = 0;
static unsigned char KEY_States = 0;
static unsigned char KEY_Wait = 0;
KEY_Data = KEY_Read();
KEY_Value = KEY_Data & (KEY_Data ^ KEY_Cont);
KEY_Cont = KEY_Data;
if(KEY_Cont && (KEY_Cont != 0x08)) //连续按下禁止SET连续触发
{
if(KEY_Wait > 25) //500ms进入连续触发
{
if(KEY_Counter >= 2) //每秒触发 25 = 1000/20/2
{
KEY_Counter = 0;
KEY_Value = KEY_Cont;
}
else
{
KEY_Counter++;
}
}
else
{
KEY_Wait++;
}
}
else
{
KEY_States = 0;
KEY_Wait = 0;
}
if(KEY_Value)
{
switch(KEY_Value)
{
case 0x00: KEY_Value = KEY_NOP; break;
case 0x20: KEY_Value = KEY_SET; break;
case 0x10: KEY_Value = KEY_UP; break;
case 0x02: KEY_Value = KEY_DOW; break;
default: KEY_Value = KEY_NOP; break;
}
}
}
volatile unsigned int Temp_H = 150;
volatile unsigned char MQ_2 = 80;
void KEY_Processing(void)
{
//按键扫描
if(Time0_20ms_Flag)
{
Time0_20ms_Flag = 0;
KEY_Scan();
}
if(KEY_Value == KEY_SET)
{
KEY_Value = KEY_NOP;
}
else if(KEY_Value == KEY_UP)
{
KEY_Value = KEY_NOP;
PutNum(2,5,2);
LcmClearTXT();
PutStr(0,0,"设置温度报警");
PutStr(1,0,"温度:");
while(1)
{
if(Time0_100ms_Flag)
{
Time0_100ms_Flag = 0;
PutTemp(1,3,Temp_H);
}
//按键扫描
if(Time0_20ms_Flag)
{
Time0_20ms_Flag = 0;
KEY_Scan();
}
if(KEY_Value == KEY_SET)
{
KEY_Value = KEY_NOP;
if(Temp_H <990)
Temp_H++;
}
else if(KEY_Value == KEY_UP)
{
KEY_Value = KEY_NOP;
break;
}
else if(KEY_Value == KEY_DOW)
{
KEY_Value = KEY_NOP;
if(Temp_H > 1)
Temp_H--;
}
}
LcmClearTXT();
PutStr(0,0,"设置烟雾报警");
PutStr(2,0,"烟雾:");
while(1)
{
if(Time0_100ms_Flag)
{
Time0_100ms_Flag = 0;
PutNum(2,3,MQ_2);
}
//按键扫描
if(Time0_20ms_Flag)
{
Time0_20ms_Flag = 0;
KEY_Scan();
}
if(KEY_Value == KEY_SET)
{
KEY_Value = KEY_NOP;
if(MQ_2 <250)
MQ_2++;
}
else if(KEY_Value == KEY_UP)
{
KEY_Value = KEY_NOP;
break;
}
else if(KEY_Value == KEY_DOW)
{
KEY_Value = KEY_NOP;
if(MQ_2 > 1)
MQ_2--;
}
}
LcmInit();
EEPROM_Save_Flag = 1;
}
else if(KEY_Value == KEY_DOW)
{
KEY_Value = KEY_NOP;
}
}
资料清单(提供资料清单所有文件):