概述
转眼间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开发板的功能
- 接收来自协调器的串口数据,并将数据信息显示到LCD屏
- 判断温度是否超过阈值,并产生报警
- 产生报警后通过按键发送报警信号或关闭报警信号给协调器
具体实现
接下来为大家介绍一下个模块的部分代码
显示报警模块
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]='