原理圖:Altium Designer
仿真版本:proteus7.8
程序編譯器:keil 4
設(shè)計(jì)編號:C0039
功能介紹:
1、單片機(jī)采用內(nèi)置AD的51系列單片機(jī),型號為STC89c52;
2、溫度采集采用DS18B20傳感器;
3、火災(zāi)煙霧檢測采用MQ-2傳感器,此傳感器輸出量也為模擬量,需接到單片機(jī)的AD端口上進(jìn)行采集;
4、防盜檢測采用HC-SR501熱釋電紅外感應(yīng)傳感器,通過配合板載設(shè)防開關(guān)進(jìn)行防盜的檢測;
5、報警部分分為板載蜂鳴器鳴笛報警和GSM短信報警功能,GSM采用SIM800模塊,當(dāng)溫度,煙霧濃度,防盜觸發(fā)時GSM短信模塊發(fā)送報警短信到指定的手機(jī)號碼上。
6、手機(jī)可以發(fā)送指令關(guān)閉繼電器或打開繼電器,給單片機(jī)打電話會回復(fù)短信單片機(jī)檢測的當(dāng)前溫度。
資料下載鏈接(可點(diǎn)擊)
仿真圖(提供源文件):
原理圖(提供源文件):
PCB(源文件):
程序(提供源文件源碼):
#include <main.h>
void Waring_Processing(void)
{
//溫度超標(biāo)//煙霧超標(biāo)
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秒內(nèi)只發(fā)一條短信
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 數(shù)字溫度傳感器通用程序庫
說明:該模塊化程序庫包含了數(shù)字溫度傳感器DS1820/DS18B20測溫所需的相關(guān)
函數(shù)??梢宰鳛楦鞣N測溫程序的底層硬件驅(qū)動使用。
要使用該庫函數(shù),需要將本文件(18x20.c)添加進(jìn)工程,并在需要調(diào)用
測溫相關(guān)函數(shù)的文件開頭處包含"18x20.h"
注意,本程序適用的晶振頻率范圍為8-14MHz(指令周期1us左右)。
如果時鐘頻率差別較大,需要修改Delay10()函數(shù),使之大約10us左右,
并修改Delay15()函數(shù),使之大約15us左右。
*/
//
// VCC
// MCU=89x51/52 --- 長線時DQ腳要上拉
// +---------------+ |
// | | | 數(shù)字溫度傳感器
// | | +---+------------------+
// | | | |
// | P3.7 |<----->| DS18B20 / DS1820 |
// | | DQ | |
// | | +----------------------+
// | | |
// | | |
// | | |
// +---------------+ ---
// GND
#include <18X20.h>
sbit DQ=P3^7; /* DS18B20數(shù)據(jù)引腳定義 */
bit TEMP_EA;
#define DISABLE_INT; TEMP_EA=EA; EA=0; /*關(guān)閉中斷的宏定義*/
#define RESTORE_INT; EA=TEMP_EA; /*恢復(fù)中斷的宏定義*/
/****************************************************************************
* 名 稱:Delay10()
* 功 能:延遲10us
* 入口參數(shù):無
* 出口參數(shù):無
* 說 明: 指令周期1us時,延遲恰好10us,晶振改變延遲時間也會隨之改變
****************************************************************************/
void Delay10()
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_(); // 6個NOP + 3周期LCALL(調(diào)用該函數(shù)) +1周期RET(返回)
_nop_(); // = 10個指令周期
}
/****************************************************************************
* 名 稱:Delay15()
* 功 能:延遲15us
* 入口參數(shù):無
* 出口參數(shù):無
* 說 明: 指令周期1us時,延遲恰好15us,晶振改變延遲時間也會隨之改變
****************************************************************************/
void Delay15()
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_(); // 11個NOP + 3周期LCALL(調(diào)用該函數(shù)) +1周期RET(返回)
_nop_(); // = 15個指令周期
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
/****************************************************************************
* 名 稱:Delay30x()
* 功 能:延遲30us的倍數(shù)(會差幾個周期)
* 入口參數(shù):Time:30us的倍數(shù)
* 出口參數(shù):無
* 范 例: Delay30x(3); //延遲90us左右
****************************************************************************/
void Delay30x(unsigned char Time)
{ if(Time==0) return; //Time=0次,不執(zhí)行
for(;Time>0;Time--) //循環(huán)Time次
{
Delay15(); //每次延遲15us,加上循環(huán),大約28us。
}
}
/****************************************************************************
* 名 稱:OW_Reset()
* 功 能:向1-Wire總線上發(fā)送一個復(fù)位指令。
* 入口參數(shù):無
* 出口參數(shù):1:表示復(fù)位操作成功
0:表示復(fù)位操作失敗
****************************************************************************/
bit OW_Reset(void)//復(fù)位
{ unsigned char i;
DISABLE_INT; // 時序要求嚴(yán)格,不允許中斷
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) {};// 復(fù)位成功,等待復(fù)位結(jié)束
RESTORE_INT;
return(1); // 并返回1,表示有器件
}
Delay15(); // 不成功,可能是1820反應(yīng)慢,重試30次
}
RESTORE_INT;
return(0);// 到達(dá)240uS等待最大值,放棄.返回0,表示無器件
}
/****************************************************************************
* 名 稱:OW_ReadByte()
* 功 能:從 1-wire 總線上讀取一個字節(jié)。
* 入口參數(shù):無
* 出口參數(shù):讀回的1字節(jié)數(shù)據(jù)
****************************************************************************/
unsigned char OW_ReadByte(void)
{
unsigned char i;
unsigned char value = 0;
for (i=8;i>0;i--) // 讀取8比特循環(huán)8次,組成1字節(jié)
{
DISABLE_INT; // 時序要求嚴(yán)格,不允許中斷
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; // 恢復(fù)中斷
}
return(value);
}
/****************************************************************************
* 名 稱:OW_WriteByte()
* 功 能:向 1-WIRE 總線上寫一個字節(jié)。
* 入口參數(shù):Val:寫入的1字節(jié)數(shù)據(jù)
* 出口參數(shù):無
****************************************************************************/
void OW_WriteByte(unsigned char Val)
{
unsigned char i;
for (i=8; i>0; i--) // 寫入8比特循環(huán)8次,共計(jì)1字節(jié)
{
DISABLE_INT; // 時序要求嚴(yán)格,不允許中斷
DQ = 0; // 將DQ腳拉低保持1uS以上 (3uS)
DQ = Val&0x01; // 先發(fā)低字節(jié)
Delay30x(3); // 保持?jǐn)?shù)據(jù) 60~120uS (取85uS)
DQ = 1; // DQ拉高
Val=Val>>1; // 取下一比特
Delay15(); // 比特間延遲1us以上(取15us)
RESTORE_INT; // 恢復(fù)中斷
}
}
/****************************************************************************
* 名 稱:DS1820_Conv()
* 功 能:向18B20發(fā)指令:開始溫度測量與轉(zhuǎn)換。
* 入口參數(shù):無
* 出口參數(shù):無
* 說 明: 該命令發(fā)出后,必須等待至少500-700ms才能測量完畢,之后才能讀取數(shù)據(jù)。
****************************************************************************/
void DS1820_Conv()
{
OW_Reset(); // 復(fù)位18B20
OW_WriteByte(0xCC); // Skip ROM(不進(jìn)行序列號識別)
OW_WriteByte(0x44); // 開始轉(zhuǎn)換
}
/****************************************************************************
* 名 稱:DS1820_GetFamily()
* 功 能:讀取18x20的家族代碼。
* 入口參數(shù):無
* 出口參數(shù):讀回的家族號。
* 說 明: 0x10表示DS1820,0x28表示DS18B20,更多系列請參照官方數(shù)據(jù)手冊
****************************************************************************/
unsigned char DS1820_GetFamily()
{ unsigned char FamilyID;
OW_Reset(); // 復(fù)位18B20
OW_WriteByte(0x33); // 發(fā)出獲取家族代碼命令
FamilyID=OW_ReadByte(); // 讀取家族號
return(FamilyID); // 返回
}
/****************************************************************************
* 名 稱:DS1820_GetTemp()
* 功 能:讀取18x20的溫度測量結(jié)果。注意要在DS1820_Conv()命令至少之后700ms以
后調(diào)用,才能讀取準(zhǔn)確的溫度值。
* 入口參數(shù):無
* 出口參數(shù):溫度數(shù)值,保留1位小數(shù)。
返回0x8001表示未檢測到器件
返回0x8002表示無法識別的器件
* 范 例: 返回123表示12.3度;-345表示-34.5度,依此類推
****************************************************************************/
int DS1820_GetTemp()
{
unsigned char tempH,tempL,Family;
if(OW_Reset()==0) return(0x8001);// 若復(fù)位不成功說明無器件,返回0x8001
Family=DS1820_GetFamily(); // 讀取1820的家族代碼
OW_Reset(); // 復(fù)位,結(jié)束讀取家族代碼的操作
OW_WriteByte(0xCC); // Skip ROM(不進(jìn)行序列號識別)
OW_WriteByte(0xBE); // 發(fā)出讀取數(shù)據(jù)的指令
Delay30x(5); // 略延遲
tempL=OW_ReadByte(); // 讀取溫度轉(zhuǎn)換結(jié)果_低8位
tempH=OW_ReadByte(); // 讀取溫度轉(zhuǎn)換結(jié)果_高8位
if (Family==0x28) // 如果是DS18B20系列
{
return ((tempH*256+tempL)*(long)625/1000);//計(jì)算溫度,保留1位小數(shù)
}
else if(Family==0x10) // 如果是DS1820系列(比18B20更老的型號)
{
return ((tempH*256+tempL)*5);//計(jì)算溫度,保留1位小數(shù)
}
else return(0x8002); //其它型號無法識別 返回0x8002
}
void DS18B20_Init(void)
{
DS1820_GetTemp(); //讀取上次測溫結(jié)果
// PutTemp(1,3,Temperature);
//LED_DisplayDecimal(Temperature,1); //顯示測溫結(jié)果,保留1位小數(shù)
DS1820_Conv(); //發(fā)送下一次測溫開始命令
DS1820_GetTemp(); //讀取上次測溫結(jié)果
// PutTemp(1,3,Temperature);
//LED_DisplayDecimal(Temperature,1); //顯示測溫結(jié)果,保留1位小數(shù)
DS1820_Conv(); //發(fā)送下一次測溫開始命令
DS1820_GetTemp(); //讀取上次測溫結(jié)果
// PutTemp(1,3,Temperature);
//LED_DisplayDecimal(Temperature,1); //顯示測溫結(jié)果,保留1位小數(shù)
DS1820_Conv(); //發(fā)送下一次測溫開始命令
}
volatile int Temperature;
void DS18B20_Processing(void)
{
if(Time0_2s_Flag) //2ms累加500次共計(jì)1秒
{
Time0_2s_Flag = 0; //以下代碼每隔2秒執(zhí)行一次
Temperature = DS1820_GetTemp(); //讀取上次測溫結(jié)果
PutTemp(1,3,Temperature);
//LED_DisplayDecimal(Temperature,1); //顯示測溫結(jié)果,保留1位小數(shù)
DS1820_Conv(); //發(fā)送下一次測溫開始命令
}
}
ADC0832驅(qū)動程序
#include <ADC0832.H>
unsigned char Get_AD_Result(bit CH)
{
unsigned char i;
unsigned char dat;
ADC0832_CS=1; //一個轉(zhuǎn)換周期開始
ADC0832_CLK=0; //為第一個脈沖作準(zhǔn)備
ADC0832_CS=0; //CS置0,片選有效
ADC0832_DIO=1; //DIO置1,規(guī)定的起始信號
ADC0832_CLK=1; //第一個脈沖
ADC0832_CLK=0; //第一個脈沖的下降沿,此前DIO必須是高電平
ADC0832_DIO=1; //DIO置1, 通道選擇信號
ADC0832_CLK=1; //第二個脈沖,第2、3個脈沖下沉之前,DI必須跟別輸入兩位數(shù)據(jù)用于選擇通道,這里選通道RH0
ADC0832_CLK=0; //第二個脈沖下降沿
ADC0832_DIO=CH; //DI置0,選擇通道0
ADC0832_CLK=1; //第三個脈沖
ADC0832_CLK=0; //第三個脈沖下降沿
ADC0832_DIO=1; //第三個脈沖下沉之后,輸入端DIO失去作用,應(yīng)置1
ADC0832_CLK=1; //第四個脈沖
for(i=0;i<8;i++) //高位在前
{
ADC0832_CLK=1; //第四個脈沖
ADC0832_CLK=0;
dat<<=1; //將下面儲存的低位數(shù)據(jù)向右移
dat|=(unsigned char)ADC0832_DIO; //將輸出數(shù)據(jù)DIO通過或運(yùn)算儲存在dat最低位
}
ADC0832_CS=1; //片選無效
return dat; //將讀書的數(shù)據(jù)返回
}
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);
}
}
按鍵掃描函數(shù)
#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調(diào)用一次
{
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)) //連續(xù)按下禁止SET連續(xù)觸發(fā)
{
if(KEY_Wait > 25) //500ms進(jìn)入連續(xù)觸發(fā)
{
if(KEY_Counter >= 2) //每秒觸發(fā) 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,"設(shè)置溫度報警");
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,"設(shè)置煙霧報警");
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;
}
}
資料清單(提供資料清單所有文件):