资讯详情

51单片机WIFI功能APP控制火灾报警仿真系统

最近用手机做了51单片机驱动8266APP控制火灾报警功能的板。下面给大家介绍一下,有需要的朋友可以私信。

由于时间有限,我会慢慢更新这部分。

先上整体图

手机app截图

1.功能描述。

a、使用DS18B读取温度,并在app上显示。超过26度报警,报警灯亮,蜂鸣器响,app报警灯变红。

b、使用MQ-2.阅读烟雾浓度,并在app超过40ppm报警,报警灯亮,蜂鸣器响,app报警灯变红。

c、用120度火焰传感器感受火焰app报警。检测到火焰后,报警灯亮,蜂鸣器响,app报警灯变红。

d、上电后,手动模式指示灯在板上和app同时点亮绿灯。这时,可以手动操作app上按上 下 左 右按钮,控制光源跟踪板旋转;可按水泵按钮,控制水泵继电器吸合,然后控制水泵动作。

e、在app按下手动按钮,切换到自动模式,自动模式指示灯在板上app同时点亮,为绿灯。此时,光源跟踪板自动跟踪光源旋转,可用手电筒模拟;对准光源后,打开水泵;水泵工作10s之后,自动关闭。之后,流程循环进行。

硬件设计。

直接上图。

没什么好说的,看图就行了。

3.软件设计。

#include <reg52.h> #include <stdio.h> #include "math.H" #include <intrins.h> #include "PCF8591.H"  #define uchar unsigned char  // 以后unsigned char就可以用uchar代替 #define uint  unsigned int  // 以后unsigned int 就可以用uint 代替 #define del   20//调速 #define ydl   20 //移动调节 #define  PCF8591 0x90    //PCF8591 地址   sbit temp_led=P0^0; sbit smoke_led=P0^1; sbit fire_led=P0^2; sbit auto_led=P0^3; sbit manual_led=P0^4; sbit pump=P1^0; sbit fire1=P3^3; sbit fire2=P3^4; sbit fire3=P3^5; sbit fire4=P3^6; sbit fire5=P3^7;   sbit DQ       = P1^1;     // 温度传感器的引脚 sbit ADC_CS   = P1^2;     // ADC0832的CS引脚 sbit ADC_CLK  = P1^3;     // ADC0832的CLK引脚 sbit ADC_DAT  = P1^4;     // ADC0832的DI/DO引脚 sbit Buzzer_P = P0^5;     // 蜂鸣器  bit up_flag; bit down_flag; bit left_flag; bit right_flag; bit pump_flag; bit AM_flag=0; bit Auto_start;   uchar Motor_Up[4]={0x08,0x04,0x02,0x01}; uchar Motor_Down[4]={0x01,0x02,0x04,0x08};   uchar Motor_Left[4]={0x10,0x20,0x40,0x80}; uchar Motor_Right[4]={0x80,0x40,0x20,0x10};   uchar AD_CHANNEL; uchar AD_Up,AD_Down,AD_Left,AD_Right;   uint i;  uchar dat[20];  uchar temp_flag;        // 温度报警标志位 uchar smoke_flag;        // 烟雾报警标志位 uchar fire_flag;        // 火焰报警标志位  int   temp;         // 保存温度值 uchar smoke;         // 保存烟雾值 uchar Smoke_Alarm=30;        // 烟雾报警值 int   Temp_Alarm=26;       // 温度报警值   uint time_20ms=0;//定时器计数 bit disFlag ;  //显示标志 unsigned char Recive_table[15];       /*********************************************************/ // 毫秒延迟函数,time毫秒数要延迟 /*********************************************************/ void DelayMs(uint time) {  uint a,b;  for(a=0;a<time;a  )   for(b=0;b<112;b  ); }   /*********************************************************/ // 延时15微秒 /*********************************************************/ void Delay15us(void) {  _nop_();  _nop_();  _nop_();  _nop_();  _nop_();  _nop_();  _nop_();  _nop_();  _nop_();  _nop_();  _nop_();  _nop_();  _nop_();  _nop_();  _nop_(); } /*********************************************************/ // 手动转动 /*********************************************************/ void manual_move(void) {  uchar i,j;  if(up_flag==1)//手动上转    {        for(i=0;i<ydl;i  )    {      for(j=0;j<4;j  )     {      P2=Motor_Up[j];      DelayMs(del);     }      }    }      if(down_flag==1)//手动下转   {        for(i=0;i<ydl;i  )    {      for(j=0;j<4;j  )     {      P2=Motor_Down[j];      DelayMs(del);     }      }   }      if(left_flag==1)//手动左转   {        for(i=0;i<ydl;i  )    {      for(j=0;j<4;j  )     {      P2=Motor_Left[j];      DelayMs(del);     }      }     }      if(right_flag==1)//手动右转   {        for(i=0;i<ydl;i  )    {      for(j=0;j<4;j  )     {      P2=Motor_Right[j];      DelayMs(del);     }      }   }   if(pump_flag==1)pump=0;else pump=1;    }  /*********************************************************/ // 自动转动 /*********************************************************/ void auto_move(void) {  uchar i,j;  for(i=0;i<8;i  )   {    switch(AD_CHANNEL)    {     case 0: PCF8591_ISendByte(PCF8591,0x41);     AD_Up=PCF8591_IRcvByte(PCF8591)*2;  //ADC0 模数转换1     break;            case 1: PCF8591_ISendByte(PCF8591,0x42);     AD_Down=PCF8591_IRcvByte(PCF8591)*2;  //ADC1  模数转换2     break;       case 2: PCF8591_ISendByte(PCF8591,0x43);     AD_Left=PCF8591_IRcvByte(PCF8591)*2;  //ADC2 模数转换3     break;            case 3: PCF8591_ISendByte(PCF8591,0x40);     AD_Right=PCF8591_IRcvByte(PCF8591)*2;  //ADC3  模数转换4     break;     }    if(  AD_CHANNEL>3)    {     AD_CHANNEL=0;    }   }   if((AD_Up<AD_Down)&&(AD_Down-AD_Up>25)//上转    {    for(i=0;i<ydl;i  )    {      for(j=0;j<4;j  )     {      P2=Motor_Up[j];      DelayMs(del);     }      }    }   //   if((AD_Up>AD_Down)&&(AD_Up-AD_Down>25)//下转   {    for(i=0;i<ydl;i  )    {      for(j=0;j<4;j  )     {      P2=Motor_Down[j];      DelayMs(del);     }      }   }      if((AD_Left<AD_Right)&&(AD_Right-AD_Left>25)//左转   {    for(i=0;i<ydl;i  )    {      for(j=0;j<;j++)
				{
					P2=Motor_Left[j];
					DelayMs(del);
				}		
			}
		
		}
		//
		if((AD_Left>AD_Right)&&(AD_Left-AD_Right>25))//右转
		{
			for(i=0;i<ydl;i++)
			{ 
				for(j=0;j<4;j++)
				{
					P2=Motor_Right[j];
					DelayMs(del);
				}		
			}
		}
		/
		//if((AD_Left!=0)&&(AD_Right!=0)&&(AD_Up!=0)&&(AD_Down!=0)&&((abs(AD_Left-AD_Right)<5)&&(abs(AD_Up-AD_Down)<5)))//旋转停止判断
		if(((AD_Left-AD_Right<=25)||(AD_Right-AD_Left<=25))&&((AD_Up-AD_Down<=25)||(AD_Down-AD_Up<=25)))//旋转停止判断
		{
			DelayMs(200);
			pump=0;//当旋转停止后,自动开启水泵
			DelayMs(10000);
			pump=1;//水泵开启10S后,自动关闭水泵
		}
	
}
/*********************************************************/
// 复位DS18B20(初始化)
/*********************************************************/
void DS18B20_ReSet(void)
{
	uchar i;
	DQ=0;
	i=240;
	while(--i);
	DQ=1;
	i=30;
	while(--i);
	while(~DQ);
	i=4;
	while(--i);
}


/*********************************************************/
// 向DS18B20写入一个字节
/*********************************************************/
void DS18B20_WriteByte(uchar dat)
{
	uchar ii;
	uchar btmp;
	
	for(ii=0;ii<8;ii++)
	{
		btmp=0x01;
		btmp=btmp<<ii;
		btmp=btmp&dat;
		
		if(btmp>0)		// 写1
		{
			DQ=0;
			Delay15us();
			DQ=1;
			Delay15us();
			Delay15us();
			Delay15us();
			Delay15us();
		}
		else			// 写0
		{
			DQ=0;
			Delay15us();
			Delay15us();
			Delay15us();
			Delay15us();
			DQ=1;
			Delay15us();
		}
	}
}


/*********************************************************/
// 读取温度值
/*********************************************************/
int DS18B20_ReadTemp(void)
{
	uchar j;
	int b,temp=0;	

	EA=0;
	DS18B20_ReSet();							// 产生复位脉
	DS18B20_WriteByte(0xcc);			// 忽略ROM指令
	DS18B20_WriteByte(0x44);			// 启动温度转换指令

	DS18B20_ReSet();							// 产生复位脉
	DS18B20_WriteByte(0xcc);			// 忽略ROM指令
	DS18B20_WriteByte(0xbe);			// 读取温度指令

	for(j=0;j<16;j++)							// 读取温度数量
	{						
		DQ=0;
		_nop_();
		_nop_();
		DQ=1;	
		Delay15us();
		b=DQ;
		Delay15us();
		Delay15us();
		Delay15us();
		b=b<<j;
		temp=temp|b;
	}
	
	temp=temp*0.0625;							// 合成温度值	
	
	if(temp<0)
		temp=0;
	 
	EA=1;
	return (temp);								// 返回检测到的温度值
}

/*********************************************************/
// ADC0832的时钟脉冲
/*********************************************************/
void WavePlus()
{
	_nop_();
	ADC_CLK = 1;
	_nop_();
	ADC_CLK = 0;
}



/*********************************************************/
// 获取指定通道的A/D转换结果
/*********************************************************/
uchar Get_ADC0832()
{ 
	uchar i;
	uchar dat1=0;
	uchar dat2=0;
	
	ADC_CLK = 0;				// 电平初始化
	ADC_DAT = 1;
	_nop_();
	ADC_CS = 0;
	WavePlus();					// 起始信号 
	ADC_DAT = 1;
	WavePlus();					// 通道选择的第一位
	ADC_DAT = 0;      
	WavePlus();					// 通道选择的第二位
	ADC_DAT = 1;
	
	for(i=0;i<8;i++)		// 第一次读取
	{
		dat1<<=1;
		WavePlus();
		if(ADC_DAT)
			dat1=dat1|0x01;
		else
			dat1=dat1|0x00;
	}
	
	for(i=0;i<8;i++)		// 第二次读取
	{
		dat2>>= 1;
		if(ADC_DAT)
			dat2=dat2|0x80;
		else
			dat2=dat2|0x00;
		WavePlus();
	}
	
	_nop_();						// 结束此次传输
	ADC_DAT = 1;
	ADC_CLK = 1;
	ADC_CS  = 1;   

	if(dat1==dat2)			// 返回采集结果
		return (dat1);
	else
		return 0;
} 
/*********************************************************/
// 报警判断
/*********************************************************/
void AlarmJudge(uchar dat1, int dat2)
{
/*火焰报警判断*/
	if((fire1==1)||(fire2==1)||(fire3==1)||(fire4==1)||(fire5==1))
	{
		
			fire_led=0;
			fire_flag=1;
		
	}
	else
	{
		  fire_led=1;
		  fire_flag=0;
	}
	
	/*烟雾报警判断*/
	if(dat1>Smoke_Alarm)
	{
		smoke_led=0;
		smoke_flag=1;
	}
	else
	{
		smoke_led=1;
		smoke_flag=0;
	}
	
	/*温度报警判断*/
	if(dat2>Temp_Alarm)
	{	
		temp_led=0;
		temp_flag=1;
	}
	else
	{
		temp_led=1;
		temp_flag=0;
	}

	/*蜂鸣器报警判断*/
	if((temp_flag==1)||(smoke_flag==1)||(fire_flag==1))
	{
		Buzzer_P=0;
		//Motor_P=0;
		Auto_start=1;
	}
	else
	{
		Buzzer_P=1;
		//Motor_P=1;
		Auto_start=0;
		
	}
}

/*********************************************************/
// ATK-ESP8266向上位机发送数据
/*********************************************************/

void SendDat(int temp,uchar smoke)
{
			
	dat[0]=(char)(temp%100/10)+48;//发送温度值的十位
	dat[1]=(char)(temp%10)+48;//发送温度值的个位
	dat[2]=(char)temp_flag+48;//发送温度值报警标志位
	dat[3]=(char)fire_flag+48;//发送火焰报警标志位
	dat[4]=(char)smoke_flag+48;//发送烟雾浓度报警标志位
	dat[5]=(char)(smoke%100/10)+48;//发送烟雾浓度值的十位
	dat[6]=(char)(smoke%10)+48;//发送烟雾浓度值的个位
	
}
/*********************************************************/
// 初始化串口
/*********************************************************/
void Init_uart(void) {  
	TMOD = TMOD | 0x20;    //???1?????2  8?????  
	SCON = SCON | 0x50;    //??1?????1  10????? REN=1????  
	TH1 = 0xFd;            //???1??  
	TL1 = TH1;  
	TR1 = 1;               //???1????  
	EA =1;                 //????  
	ES =1;                 //
}
 
 

/*********************************************************/
// 串口发送一个字节数据
/*********************************************************/
void Uart_SendByteData(uchar a)
{
	SBUF = a;
	while(TI==0);
	TI=0;
	
}
/*********************************************************/
// 串口发送字符串
/*********************************************************/

void Uart_SendStrData(uchar *s)
{
	while(*s!='\0')
	{
		Uart_SendByteData(*s);
		s++;
	}
		
}
 
/*********************************************************/
// ATK-ESP8266初始化
/*********************************************************/
void Init_ESP01S(){   
	DelayMs(50);  
	Uart_SendStrData("AT+CIPMUX=1\r\n");            // ?????
	DelayMs(5);   
	Uart_SendStrData("AT+CIPSERVER=1,8080\r\n");      // ?????,??8080??
	DelayMs(5);
}
 
/*********************************************************/
// 定时器0初始化
/*********************************************************/
void Init_Timer0(void)
{
    TMOD |= 0x01;	  //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
    TH0=(65536-20000)/256;		  //重新赋值 20ms
    TL0=(65536-20000)%256;
    EA=1;            //总中断打开
    ET0=1;           //定时器中断打开
    TR0=1;           //定时器开关打开
}
/*********************************************************/
// 定时器0定时20ms
/*********************************************************/
void Timer0_isr(void) interrupt 1
{
    TH0=(65536-20000)/256;		  //重新赋值 20ms
    TL0=(65536-20000)%256;

    time_20ms++;
    if(time_20ms%5==0)//定时时间到
    {     
			disFlag=1;//标志位置位			 
    }
}
/*********************************************************/
// 主程序
/*********************************************************/ 
void main(){
	
	Init_Timer0();
	Init_uart();
	Init_ESP01S();    
	
	
	while(DS18B20_ReadTemp()==85)						// 等待传感器初始化完成
	{
		DelayMs(10);
	}
	
	
	while(1)
	{
		
		smoke=Get_ADC0832();				// 获取烟雾的浓度值
		smoke=smoke/2.2;							// 调整浓度值,使其在0-100之间变化
		if(smoke>100)smoke=99;
	
		
		
		temp=DS18B20_ReadTemp();	// 读取温度值
		
		AlarmJudge(smoke,temp);			// 报警判断
		
		
	
		if(AM_flag==1)
		{
			manual_led=1;
			auto_led=0;
			if(Auto_start==1)auto_move();			
		}
		else
		{
			manual_led=0;
			auto_led=1;
			manual_move();			
		}
		
		
		
		//sprintf(dat,"%d%d%d%d%d%d",temp,(int)temp_flag,(int)fire_flag,(int)smoke_flag,(int)smoke);
		SendDat(temp,smoke);

		if(disFlag==1)
		{
		
			disFlag=0;
			Uart_SendStrData("AT+CIPSEND=0,7\r\n");
			DelayMs(5);	
			Uart_SendStrData(dat);
			DelayMs(5);						
		}
		
	}
}
/*********************************************************/
// 接收数据中断服务程序
/*********************************************************/		
void UART_Interrupt(void) interrupt 4
{
    
    if(RI == 1)   
    {
        RI = 0;     //清除串口接收标志位
	      Recive_table[i]=SBUF;
	      if(Recive_table[0]=='+')
				{
					i++;
				}
				else
				{
					i=0;
				}
				if(i==10)
				{
					i=0;
					switch(Recive_table[9])//+IPD,0,1:0
						{
							case '1':{up_flag = 1;break;}
							case '2':{down_flag = 1;break;}
							case '3':{left_flag = 1;break;}
							case '4':{right_flag = 1;break;}
						  case '5':{AM_flag=1;break;}//自动标志位,AM_flag=1
							case '6':{AM_flag=0;break;}//手动标志位,AM_flag=0
							case '7':{pump_flag=1;break;}//
							case '9':{up_flag = 0;down_flag = 0;left_flag = 0;right_flag = 0;pump_flag=0;break;}						
												
						}
         }
			 }
		 }


对于程序,我不做全部解释,有疑问的朋友可以私信或者评论。

我这里只把我遇到的问题说一下:

a、DS18B20读取温度程序。

如下

/*********************************************************/
// 读取温度值
/*********************************************************/
int DS18B20_ReadTemp(void)
{
	uchar j;
	int b,temp=0;	

	EA=0;
	DS18B20_ReSet();							// 产生复位脉
	DS18B20_WriteByte(0xcc);			// 忽略ROM指令
	DS18B20_WriteByte(0x44);			// 启动温度转换指令

	DS18B20_ReSet();							// 产生复位脉
	DS18B20_WriteByte(0xcc);			// 忽略ROM指令
	DS18B20_WriteByte(0xbe);			// 读取温度指令

	for(j=0;j<16;j++)							// 读取温度数量
	{						
		DQ=0;
		_nop_();
		_nop_();
		DQ=1;	
		Delay15us();
		b=DQ;
		Delay15us();
		Delay15us();
		Delay15us();
		b=b<<j;
		temp=temp|b;
	}
	
	temp=temp*0.0625;							// 合成温度值	
	
	if(temp<0)
		temp=0;
	 
	EA=1;
	return (temp);								// 返回检测到的温度值
}

 在程序的开始和末尾最好加上EA=0和EA=1。就是禁用总中断和开启总中断。因为DS18B20对于时序很敏感,如果不加这两个命令,读取温度会出现乱码!

b、ATK-ESP8266发送数据时,组成字符串程序。

如下为组成字符串程序

void SendDat(int temp,uchar smoke)
{
			
	dat[0]=(char)(temp%100/10)+48;//发送温度值的十位
	dat[1]=(char)(temp%10)+48;//发送温度值的个位
	dat[2]=(char)temp_flag+48;//发送温度值报警标志位
	dat[3]=(char)fire_flag+48;//发送火焰报警标志位
	dat[4]=(char)smoke_flag+48;//发送烟雾浓度报警标志位
	dat[5]=(char)(smoke%100/10)+48;//发送烟雾浓度值的十位
	dat[6]=(char)(smoke%10)+48;//发送烟雾浓度值的个位
	
}

如下为发送程序

SendDat(temp,smoke);

		if(disFlag==1)
		{
		
			disFlag=0;
			Uart_SendStrData("AT+CIPSEND=0,7\r\n");
			DelayMs(5);	
			Uart_SendStrData(dat);
			DelayMs(5);						
		}

组成字符串程序时,也可以用sprintf函数,比如:sprintf(dat,"%d%d%d%d%d%d",temp,(int)temp_flag,(int)fire_flag,(int)smoke_flag,(int)smoke);

如果这样写,不仅会增加代码总量大小,而且sprintf用不好的话会造成错误。所以建议使用如上的字符串组成程序。

c、初始化ATK-ESP8266时,在函数开头应该延时一段时间,让板子上电时,8266自己可以有个初始化过程,否则8266会出现错误,导致连接不上8266。

/*********************************************************/
// ATK-ESP8266初始化
/*********************************************************/
void Init_ESP01S(){   
	DelayMs(50);  
	Uart_SendStrData("AT+CIPMUX=1\r\n");            // ?????
	DelayMs(5);   
	Uart_SendStrData("AT+CIPSERVER=1,8080\r\n");      // ?????,??8080??
	DelayMs(5);
}

以上就是我的描述,想进一步了解的朋友私信我。谢谢!

标签: ydl连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台