轉眼間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]='\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
總結
這門課程也學完了,雖然沒什麼機會去實踐,去將所學的知識好好利用起來,希望自己以後能夠多加深入,研究!