ZigBee课程设计(温湿度采集控制)

转眼间ZigBee课程也上完了,本次完成了一个课程设计,希望大家能够互相探讨,解决问题,若有错误的地方麻烦大家及时提醒,我将不胜感激!当然我是和两位搭档一起合作完成,我只负责了stm32和单片机部分,希望大家多指教~~

设计方案概述

设计方案

在大棚蔬菜中安置温湿度传感器与温湿度警报显示装置,通过ZigBee通信技术,串口通信技术将采集到的该区域温湿度上传至控制系统,下发给显示装置。控制系统STM32F103ZET6协调器组成,接收数据信息,整理,按区域节点显示在控制端的LCD屏,判断并产生报警信号。显示装置实时显示温湿度,根据信号产生报警,关闭报警来提醒人们。

设计图
在这里插入图片描述

资源说明

1个STM32F103ZET6开发板
2个STC89C52单片机
3个ZigBee开发板(1个协调器,2个终端节点)

通信过程中的信息格式

为了快点完成课设,所以通信的格式特别的简洁,也不规范,考虑的因素很少,希望大家可以自己设计

五位字符(数据信息):
第一位:节点编号(1,2)
第二位:温度的十位
第三位:温度的个位
第四位:湿度的十位
第五位:湿度的个位

五位字符(警报信息):
第一位:警报标志(3代表1号节点警报,4代表2号节点警报)
第二位:固定为0
第三位:固定为0
第四位:固定为0
第五位:控制开关警报

模块介绍

显示报警模块

通过STC89C52单片机与采集模块进行串口通信
功能
1.将接收到的信息在数码管上显示
2.通过按键可以切换查看温湿度以及节点号
3.当收到报警信号时,报警(数码管显示全0),当接收到取消报警信号时,恢复正常显示

采集模块

作为终端节点的ZigBee开发板(CC2530)
功能
1.采集温湿度将数据发送给协调器和显示报警模块
2.接收协调器报警信号,将报警信号发送给显示报警模块

中控模块

中控模块由两部分组成:
1.一块作为协调器的ZigBee开发板
2.STM32F103ZET6开发板

它们之间通过串口通信

协调器功能
1.组建ZigBee网络
2.将采集模块上传的温湿度数据通过串口发送给STM32F103ZET6开发板
3.接收STM32F103ZET6开发板发出的报警信号并广播给终端节点
STM32F103ZET6开发板的功能

  1. 接收来自协调器的串口数据,并将数据信息显示到LCD屏
  2. 判断温度是否超过阈值,并产生报警
  3. 产生报警后通过按键发送报警信号或关闭报警信号给协调器

具体实现

接下来为大家介绍一下个模块的部分代码

显示报警模块

1. 接收串口信息:接受到信息产生中断,在中断服务函数中将数据存入buf数组中,由于涉及到控制信号的接收所以设置一个alterflag标志位来控制信号数据不存入buf中,只需将第五个控制位存入变量n中

void receive(void) interrupt 4{
	if(RI==1)
	{
		 //FENG=1;
		if(i==5)	   //接收到5个后将下标置0,为下次接受做准备
			i=0;
		RI=0;
		receiv=SBUF;   //将缓存变量SBUF中数据存入变量receiv
		if(i==0&&(receiv=='4'||receiv=='3')  //通过数据的第一位判断是否是警报信号
			 alterflag=0;			 //警报信号标志置为0
		else if(alterflag)			  //如果不是警报信号而是温湿度数据则存入buf中
			buf[i]=receiv-0x30;
		else if(i==4&&alterflag==0)	   //是警报信号将信号中第五个控制位存入变量n中
			n=receiv;
		i++;
		flag=1;	   //接收到数据标志
	}
}

2. 数码管显示:根据一些标志来判断显示的信息,数据显示:第一个为节点号,第二个为温湿度的十位,第三个为温湿度的个位。报警显示:全部显示0

void lcdshow()
{
	if(alterflag==0)	  //是报警信号
	{
		if(n=='1')		 //报警信号第五个控制位为1则为报警
		{
			buf[0]=0;		//数码管全部显示0
			buf[1]=0;
			buf[2]=0;
			buf[3]=0;
			buf[4]=0;
		}
		else if(n=='0')	  //报警信号第五个控制位为0则为取消报警
		{
			alterflag=1;
		}	
	}
	if(sign)	//根据按键信息来显示温度还是湿度  sign:1为温度 0为湿度
	{
		P1=0xf1;
		P0=led_mod[buf[2]];
		delayms(5);
		P1=0xf2;
		P0=led_mod[buf[1]];
		delayms(5);
		P1=0xf4;
		P0=led_mod[buf[0]];
		delayms(5);
	}
	else
	{
		P1=0xf1;
		P0=led_mod[buf[4]];
		delayms(5);
		P1=0xf2;
		P0=led_mod[buf[3]];
		delayms(5);
		P1=0xf4;
		P0=led_mod[buf[0]];
		delayms(5);	
	}	

3. 按键切换显示内容:判断是否按下,按下改变按键标志

if(KEY==0)	//按键是否按下
{
	delayms(10);  //消抖
	if(KEY==0)
	{
		while(KEY==0);	//当按键松开
		sign=!sign;		//改变按键的标志
	}
}

采集模块

1. 采集温湿度将数据发送给协调器和显示报警模块
终端节点加入网络后触发SEND_DATA_EVENT事件调用下面函数。

void GenericApp_SendTheMessage( void )
{
    DHT11();   //温度采集 
    Data[0] = 2+0x30;//用于表示自己的节点号
    Data[1] = wendu_shi+0x30;
    Data[2] = wendu_ge+0x30;
    Data[3] = shidu_shi+0x30;
    Data[4] = shidu_ge+0x30;
    AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
                       GENERICAPP_CLUSTERID,
                       6,
                       (uint8 *)&Data,
                       &GenericApp_TransID,
                       AF_DISCV_ROUTE, 
                       AF_DEFAULT_RADIUS );//发送到协调器
    HalUARTWrite(0, Data,5);//发送到显示报警模块  
}

其中DHT11()为温度采集函数,其代码如下

void DHT11(void)   //温湿传感启动
{
  P0DIR |= 0x10;
  wenshi=0;
  Delay_ms(19);  //>18MS 主机拉低18ms
  wenshi=1; 
   
  //主机延时40us
  Delay_10us();
  Delay_10us();
  Delay_10us();
  Delay_10us();  
  
  wenshi=1; 
  P0DIR &= ~0x10;//重新配置IO口方向 0001 0000
  if(!wenshi) 
  {
    ucharFLAG=2;
    //判断从机是否80us的低电平,响应信号是否结束
    while((!wenshi)&&ucharFLAG++);
    ucharFLAG=2;
    while((wenshi)&&ucharFLAG++); 
    COM();//读湿度的高八位
    ucharRH_data_H_temp=ucharcomdata;
    COM();//读湿度的低八位
    ucharRH_data_L_temp=ucharcomdata;
    COM();//读温度的高八位
    ucharT_data_H_temp=ucharcomdata;
    COM();//读温度的低八位
    ucharT_data_L_temp=ucharcomdata;    
    COM();
    ucharcheckdata_temp=ucharcomdata;//校验和
    
    //数据校验
    wenshi=1; 
    uchartemp=(ucharT_data_H_temp+ucharT_data_L_temp+ucharRH_data_H_temp+ucharRH_data_L_temp);    
    if(uchartemp==ucharcheckdata_temp)//校验结果正确则收集数据
    {
      ucharRH_data_H=ucharRH_data_H_temp;//收集湿度
      ucharRH_data_L=ucharRH_data_L_temp;
      
      ucharT_data_H=ucharT_data_H_temp;//收集温度
      ucharT_data_L=ucharT_data_L_temp;
      
      ucharcheckdata=ucharcheckdata_temp;
    } 
    wendu_shi=ucharT_data_H/10; 
    wendu_ge=ucharT_data_H%10;
    shidu_shi=ucharRH_data_H/10; 
    shidu_ge=ucharRH_data_H%10;        
  } 
  else //没用成功读取,返回0
  {
    wendu_shi=0; 
    wendu_ge=0;    
    shidu_shi=0; 
    shidu_ge=0;  
  } 
}
void COM(void) // 温湿写入
{     
  uchar i;         
  for(i=0;i<8;i++)    
  {
    ucharFLAG=2;
    //如果高电平 或者uchatFLAG到达0 退出循环
    while((!wenshi)&&ucharFLAG++);
    Delay_10us();
    Delay_10us();
    Delay_10us();
    uchartemp=0;
    if(wenshi)// 如果P0_4是高电平,
      uchartemp=1;//超过30us依然为高电平,即数据为1;否则数据为0
    ucharFLAG=2;
    //如果是高电平并且ucharFLAG++ 一直为真 直到255 当做延时 
    //ucharFLAG变成0 停止执行 但是wenshi没有变成0 说明没有响应
    while((wenshi)&&ucharFLAG++);   //超时则跳出for循环
    if(ucharFLAG==1)
      break;    
    ucharcomdata<<=1;
    ucharcomdata|=uchartemp;  //判断数据是0还是1
  }    
}

2. 接收协调器报警信号,将报警信号发送给显示报警模块
收到协调器广播消息根据数据的第一位判断是否为发送给自己的,其中3表示1号节点,4表示2号节点。(其中烧另外一个节点时判断改为判断"3")

void GenericApp_MessageMSGCB(afIncomingMSGPacket_t *pkt )
{
  uint8 buf[5];
  switch(pkt->clusterId)
  {
  case (GENERICAPP_CLUSTERID):
    osal_memcpy(buf,pkt -> cmd.Data,5);
     if(osal_memcmp(buf,"4",1))//只判断第一位
     {
        HalUARTWrite(0, buf,5);//发送到显示报警模块
     }
  }
}

中控模块

协调器
1. 组建ZigBee网络
网络组建成功点亮黄灯,收到终端节点传来的数据后点亮蓝灯。
2. 将采集模块上传的温湿度数据通过串口发送给STM32F103ZET6

void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
  uint8 buf[10];
  switch ( pkt->clusterId )
  {
    case GENERICAPP_CLUSTERID: 
      uint8 endbuf[2]={0x0d,0x0a};
      HalLedSet(HAL_LED_1,HAL_LED_MODE_ON);
      osal_memcpy(&buf,pkt->cmd.Data,5);存储终端节点的数据
      HalUARTWrite(0, buf,5);//发送给STM32F103ZET6
      HalUARTWrite(0, endbuf,2);//以换行符结尾
      break;   
  } 
}

3. 接收STM32F103ZET6发出的报警信号并广播给终端节点
用回调函数来处理报警信号,并以广播模式发出

GenericApp_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;//广播模式
  GenericApp_DstAddr.endPoint =GENERICAPP_ENDPOINT;
  GenericApp_DstAddr.addr.shortAddr = 0xFFFF;//所有节点

以下为回调函数

static void rxCB(uint8 port, uint8 event)
{
  uint8 buf[5];
  HalUARTRead(0,buf,5);//读取STM32F103ZET6发来的报警信号
  AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
                       GENERICAPP_CLUSTERID,
                       5,
                       (uint8*)&buf,
                       &GenericApp_TransID,
                       AF_DISCV_ROUTE, 
                       AF_DEFAULT_RADIUS );//广播给网络下的所有节点
}

STM32F103ZET6
1.接收串口信息:在串口中断服务函数中将收到的数据保存在串口缓存中,根据接收到信息标志USART_RX_STA的最高位来判断是否收到数据,然后调用DataHandle函数将缓存中的数据存入对应的变量中

u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN //(200)个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA=0;       //接收状态标记	

DataHandle函数:

void DataHandle()
{
	char num = USART_RX_BUF[0];    //根据数据的第一位判断是哪个节点
	if(num =='1')   //1节点
	{
		number1[0]=USART_RX_BUF[0];   //存下节点标号
		number1[1]='\0';
		temp1[0]=USART_RX_BUF[1];			//存下温度的十位
		temp1[1]=USART_RX_BUF[2];			//存下温度的个位
		temp1[2]='\0';
		hum1[0]=USART_RX_BUF[3];      //存下湿度的十位
		hum1[1]=USART_RX_BUF[4];      //存下湿度的个位
		hum1[2]='\0';
	}
	else if(num=='2')  //2节点
	{
		number2[0]=USART_RX_BUF[0];
		number2[1]='\0';
		temp2[0]=USART_RX_BUF[1];
		temp2[1]=USART_RX_BUF[2];
		temp2[2]='\0';
		hum2[0]=USART_RX_BUF[3];
		hum2[1]=USART_RX_BUF[4];
		hum2[2]='\0';
	}
}

2.LCD显示:在循环里面调用显示函数LCD_show,根据报警标志来显示相应的报警信息

void LCD_show()
{
	LCD_ShowString(30,40,200,16,16,"number:");
	LCD_ShowString(120,40,200,16,16,number1);
	LCD_ShowString(30,60,200,16,16,"temp:");
	LCD_ShowString(120,60,200,16,  16,temp1);
	LCD_ShowString(30,80,200,16,16,"humidity:");
	LCD_ShowString(120,80,200,16,16,hum1);
	LCD_ShowString(30,100,200,16,16,"number:");
	LCD_ShowString(120,100,200,16,16,number2);
	LCD_ShowString(30,120,200,16,16,"temp:");
	LCD_ShowString(120,120,200,16,16,temp2);
	LCD_ShowString(30,140,200,16,16,"humidity:");
	LCD_ShowString(120,140,200,16,16,hum2);
	LCD_ShowString(30,280,200,16,16,"lowtemp:15  hightemp:19"); 
	if(ALERT1==true && ALERT2==false)    //节点1产生报警
	{
		LCD_ShowString(30,175,200,16,24,"ALERT1");
		LCD_ShowString(30,210,200,16,24,"PRESS KEY0");
	}
	else if(ALERT1==false && ALERT2==true)   //节点2产生报警
	{
		LCD_ShowString(30,175,200,16,24,"ALERT2");
		LCD_ShowString(30,210,200,16,24,"PRESS KEY0");
	}
	else if(ALERT1 && ALERT2)   //节点1,2都产生报警
	{
		LCD_ShowString(30,175,200,16,24,"ALERT");
		LCD_ShowString(30,210,200,16,24,"PRESS KEY0");
	}
}

3.判断温度是否超过阈值,并产生报警:根据收到数据转化位十进制数与阈值比较,若超过阈值则将报警标志置1,具体函数在接收到信息后进来判断,函数为ALERT01

void ALERT01()
{
	int temprture1 = (temp1[0]-0x30)*10+(temp1[1]-0x30);    //温度转化为十进制数
	int temprture2 = (temp2[0]-0x30)*10+(temp2[1]-0x30); 
	if((temprture1<=lowtemp && temprture1>0) || temprture1>=hightemp)   //判断节点1温度是否超过阈值
	{
		ALERT1 = true;  //改变节点1报警标志
	}  
	if((temprture2<=lowtemp && temprture2>0) || temprture2>=hightemp)   //判断节点2温度是否超过阈值
	{
		ALERT2 = true;  //改变节点2报警标志
	}
}

4.按键下发报警信息:当产生报警后可以按KEY1下发报警信息给协调器,按KEY0可取消报警,下发取消报警信息
KEY1的中断服务函数

void EXTI3_IRQHandler(void)
{
	delay_ms(10);//消抖
	if(ALERT1 || ALERT2)  //有报警
	{
		if(ALERT1)
		{
			uart_send_buff(USART1,"30001",5);  //第一位3与第五位1表示1号节点的报警信息
		}
		if(ALERT2)
		{
			uart_send_buff(USART1,"40001",5);  //第一位4与第五位1表示2号节点的报警信息
		}
		LCD_Clear(WHITE);
		EXTI_ClearITPendingBit(EXTI_Line3);  //清除LINE3上的中断标志位
	}
}

KEY0的中断服务函数

void EXTI4_IRQHandler(void)
{
	delay_ms(10);//消抖
	if(ALERT1 || ALERT2)  //有报警
	{
		if(ALERT1)
		{
			ALERT1=false;   //1节点警报标志置位false
			uart_send_buff(USART1,"30000",5);  //第一位3与第五位0表示1号节点的取消报警信息
		}
		if(ALERT2)
		{
			ALERT2=false;  ////2节点警报标志置位false
			uart_send_buff(USART1,"40000",5);  //第一位4与第五位0表示2号节点的取消报警信息
		}
		LCD_Clear(WHITE);
		EXTI_ClearITPendingBit(EXTI_Line4);  //清除LINE4上的中断标志位
	}
}

5.下发报警信号函数uart_send_buff:

void uart_send_buff(USART_TypeDef* USARTx, u8 *buf,u8 len)  
{  
  u8 j=0 ;
	LED0=!LED0;  //红灯状态反转
	for(j=0;j<len;j++)							//循环发送给定长度
	{
	  while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET); //循环,直到发送完毕   
		USART_SendData(USARTx,buf[j]);   //发送数据
	}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020010515275091.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyMzk4MzQy,size_16,color_FFFFFF,t_70)

结果展示

采集模块采集到温湿度通过串口发给显示报警模块
由图可知当前1号节点温度数值为:26,2号节点温度值为:24
在这里插入图片描述
当按下按键时,切换查看湿度
由图可知当前1号节点湿度数值为:17,2号节点湿度值为:16
在这里插入图片描述
采集模块将采集到的温湿度发给协调器,协调器通过串口输出可以看到1,2节点的温湿度
在这里插入图片描述
协调器通过串口将温湿度发给STM32控制板显示在LCD上并且由于温度过高发出警报
在这里插入图片描述
Number:1
Temp:26
Humidity:17
Number:2
Temp:24
Humidity:16

Lowtemp:15 hightemp:19

当按下按键1时通过串口发出警报信号给协调器
警报信号30001表示给1号节点的警报信号
在这里插入图片描述
警报信号40001表示给2号节点的警报信号

在这里插入图片描述
协调器在将警报信号广播给采集模块,采集模块收到信号后通过串口将信号发个显示报警模块,产生报警(数码管显示全0)
在这里插入图片描述
当按下按键0时通过串口发出取消警报信号给协调器
警报信号30000表示给1号节点的取消警报信号
在这里插入图片描述
警报信号40000表示给2号节点的警报信号
在这里插入图片描述
协调器在将警报信号广播给采集模块,采集模块收到信号后通过串口将信号发个显示报警模块,取消报警信号,当下次温湿度数据来到时恢复显示。
由图可知当前1号节点温度数值为:25,2号节点温度值为:24
在这里插入图片描述

总结

这门课程也学完了,虽然没什么机会去实践,去将所学的知识好好利用起来,希望自己以后能够多加深入,研究!

发布了11 篇原创文章 · 获赞 42 · 访问量 7357

猜你喜欢

转载自blog.csdn.net/qq_42398342/article/details/103794319
今日推荐