草庐IT

51单片机智能家居环境检测 烟雾温度GSM短信提示报警器(原理图+程序+仿真+PCB)

BT-BOX 2023-04-09 原文

原理图: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;
		
	}

}

资料清单(提供资料清单所有文件):

有关51单片机智能家居环境检测 烟雾温度GSM短信提示报警器(原理图+程序+仿真+PCB)的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby - 在 Ruby 中编写命令行实用程序 - 2

    我想用ruby​​编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序

  4. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  5. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  6. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  7. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  8. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  9. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  10. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby​​文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否

随机推荐