火災檢測系統課設報告
目錄
一、 需求分析···································1
二、 系統設計···································2
三、 詳細設計···································2
四、 調試分析···································8
五、 總結分析···································9
六、 團隊運行情況和個人工作描述·················9
七、 附錄·············································10
一、需求分析
1、設計內容:
設計一個能對火災進行檢測的系統
2、設計要求:
能夠檢測到明火,能夠報警,能夠噴灑滅火。上位機能夠顯示所有節點、以及它們之間的關系,能夠綁定噴灑裝置,能夠控制噴灑。
3、設計實現功能分析:
1)一個終端節點上連有溫濕度傳感器、火焰傳感器、煙霧傳感器
2)一個協調器上連接繼電器(繼電器連接水泵來控制水泵工作)、蜂鳴器
3)通過上位機能夠看到所有節點的狀態、實現火災報警和能在沒有火災的時候通過上位機控制繼電器的工作
4)當有火焰產生時或是溫濕度超出界限或是煙霧超過一定界限,蜂鳴器就會報警上位機也會報警,同時繼電器開始工作讓水泵實現澆水
4、實驗平台以及工具:
實驗平台:IAR的Embedded Workbench系列是一種增強型一體化嵌入式集成開發環境,其中完全集成了開發嵌入式系統所需要的文件編輯、項目管理、編譯、鏈接和調試工具。
實驗工具:CC2530模塊,火焰傳感器,DTH11溫濕度傳感器,煙霧傳感器,蜂鳴器,繼電器,水泵。
5、課設協議棧:
Z-Stack Home 1.2.2a
二、系統設計
- 系統組成圖
- 傳感器模塊以及與節點的接口
1)DHT11溫濕度傳感器:
DS18B20是常用的數字溫度傳感器,其輸出的是數字信號,具有體積小,硬件開銷低,抗干擾能力強,精度高的特點。
原理圖:
對其口的定義:#define DATA_PIN P0_4
2)火焰傳感器
火焰傳感器:由各種燃燒生成物、中間物、高溫氣體、碳氫物質以及無機物質為主體的高溫固體微粒構成的。火焰的熱輻射具有離散光譜的氣體輻射和連續光譜的固體輻射。不同燃燒物的火焰輻射強度、波長分布有所差異,但總體來說,其對應火焰溫度的近紅外波長域及紫外光域具有很大的輻射強度,根據這種特性可制成火焰傳感器。
原理圖:
對其口的定義:#define DATA_PIN1 P0_5
3)MQ-2煙霧傳感器
MQ-2常用於家庭和工廠的氣體泄漏監測裝置,適宜於液化氣、苯、烷、酒精、氫氣、煙霧等的探測。故因此,MQ-2可以准確來說是一個多種氣體探測器。
MQ-2的探測范圍極其的廣泛。它的優點:靈敏度高、響應快、穩定性好、壽命長、驅動電路簡單。
原理圖:
對其口的定義:#define DATA_PIN3 P0_6
4)蜂鳴器
原理圖:
對其口的定義:P0DIR |= 0x80;
5)繼電器
繼電器vcc GND 接5v gnd
繼電器輸入端IN1 接STC89C52單片機任意io口,盡量避免P30 和 P31
上電后 繼電器會不斷吸和與釋放
原理圖:
對其口定義:#define DATA_PIN2 P1_7
- 實現流程圖:
三、詳細設計
對於不同的模塊,我們編寫了不同的函數來調用實現它們的功能。我將他們分為兩大模塊:一是開發板上對器件控制模塊,二是上位機的實現與控制模塊,具體如下:
1)火焰判斷模塊
因為這個輸出是最簡單的只要判斷他輸出的是0是1,所以就沒寫函數,只有一個簡單的獲取判斷代碼:
fire = DATA_PIN1;
2)溫濕度傳感器模塊
針對這個傳感器,主要有兩個函數,一個是溫濕度的寫入,一個是對溫濕度的讀取使用。
void COM(void) // 溫濕度的寫入
{
uchar i;
for(i=0;i<8;i++)
{
ucharFLAG=2; //判斷
while((!DATA_PIN)&&ucharFLAG++);
Delay_10us();//延時
Delay_10us();
Delay_10us();
uchartemp=0;
if(DATA_PIN)uchartemp=1;
ucharFLAG=2;
while((DATA_PIN)&&ucharFLAG++);
if(ucharFLAG==1)break;
ucharcomdata<<=1;
ucharcomdata|=uchartemp;
}
}
void DHT11(void) //溫濕度的使用以及其他傳感器獲得數據后的輸出
{
DATA_PIN=0;
Delay_ms(19); //>18MS
DATA_PIN=1;
DATA_PIN_INPUT; //輸入
Delay_10us();
Delay_10us();
Delay_10us();
Delay_10us();
if(!DATA_PIN)
{
P1DIR &= ~0x20; //P1.5定義為輸入口
ucharFLAG=2;
while((!DATA_PIN)&&ucharFLAG++);
ucharFLAG=2;
while((DATA_PIN)&&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;
DATA_PIN=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=ucharT_data_H;//溫度最終讀數
shidu=ucharRH_data_H;//濕度最終讀數
fire = DATA_PIN1;//火焰情況
yanwu = ReadqitiData();//煙霧情況
}
Else//沒獲取到
{
shidu=0;
wendu=0;
fire = DATA_PIN1;//
yanwu = ReadqitiData();
}
DATA_PIN_OUTPUT; //輸出
}
3)煙霧傳感器模塊
煙霧傳感器的話也只有一個獲取讀數的函數
uint8 ReadqitiData( void )
{
uint16 reading = 0;
P0SEL &= ~0x40; //設置為普通 IO 口
P0DIR &= ~0x40; // 設置為輸入方式
asm("NOP");asm("NOP");
ADCIF = 0;
ADCCON3 = (0x80 | HAL_ADC_DEC_064 | HAL_ADC_CHANNEL_6);
while ( !ADCIF );
asm("NOP");asm("NOP");
reading = ADCL;
reading |= (int16) (ADCH << 8);
reading >>= 8;
return reading;
}
4)蜂鳴器模塊
蜂鳴器的話重要的是初始化,使用時只要置0置1就行
#ifdef ZDO_COORDINATOR
//協調器初始化
//逢蜂鳴器初始化
//P0SEL &= ~0x80; //設置P07為普通IO口
P0DIR |= 0x80; //P07定義為輸出口
//默認蜂鳴器不響
P0_7=1;
P1SEL &= ~0x80; //設置為普通IO口
P1DIR |= 0x80; //定義為輸出口
5)組網的選擇模塊
#endif
SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;//廣播
SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;
// Setup for the flash command's destination address - Group 1
SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;//組播
SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;
SampleApp_P2P_DstAddr.addrMode = (afAddrMode_t)Addr16Bit; //點播
SampleApp_P2P_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_P2P_DstAddr.addr.shortAddr = 0x0000; //發給協調器
SampleApp_Bind_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent;
6)協調器的任務處理模塊(部分代碼)
if ( events & SYS_EVENT_MSG )
{
afIncomingMSGPacket_t *MSGpkt;
while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID )) )
{
switch ( MSGpkt->hdr.event )
{
// Received when a key is pressed
case KEY_CHANGE:
SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break;
case AF_INCOMING_MSG_CMD:
SampleApp_ProcessMSGCmd( MSGpkt );
break;
case ZDO_STATE_CHANGE:
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if ( (SampleApp_NwkState == DEV_ZB_COORD)||
(SampleApp_NwkState == DEV_ROUTER)
|| (SampleApp_NwkState == DEV_END_DEVICE) )
{
//連網成功后,啟動一個定時器
SampleApp_DeviceConnect();
osal_start_timerEx( SampleApp_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
}
else
{
// Device is no longer in the network
}
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt );
}
return ( events ^ SYS_EVENT_MSG );
}
7)通過串口與上位機之間的輸入輸出模塊
輸出:#ifdef ZDO_COORDINATOR
//協調器串口輸出數據
{
uint8 buff[200]={0};
//格式化溫度數據,用於串口輸出
sprintf(buff, "%d %d %d %d %d %d %d %d %d %d %d %d %d\r\n", temp1Int, hum1Int, tm1, yanwu1Int,temp2Int, hum2Int, tm2, yanwu2Int, temp3Int, hum3Int,tm3, yanwu3Int,DATA_PIN2);
//串口輸出提示信息
HalUARTWrite(0, buff, osal_strlen(buff));
}
輸入:uint8 buff1[10]={0};
HalUARTRead(0,buff1,10);
if(buff1[0]=='s'&&buff1[1]=='t'&&buff1[2]=='o'&&buff1[3]=='p')
{
DATA_PIN2=0;
FLAG=ALLOW_USE;
}
if(buff1[0]=='s'&&buff1[1]=='t'&&buff1[2]=='a'&&buff1[3]=='r'&&buff1[4]=='t')
{
DATA_PIN2=1;
FLAG=DISALLOW_USE;
}
8)通過按鍵控制繼電器工作模塊
if ( keys & HAL_KEY_SW_6 )//key1,強制澆水
{
if(ledState==0)
{
DATA_PIN2=1;
FLAG=DISALLOW_USE;
HalLedSet (HAL_LED_2, HAL_LED_MODE_ON);
P0_7=1;
ledState=1;
}
else
{
DATA_PIN2=0;
FLAG=DISALLOW_USE;
HalLedSet (HAL_LED_2, HAL_LED_MODE_OFF);
P0_7=1;
ledState=0;
}
}
if ( keys & HAL_KEY_SW_1 )//key2,解除禁制
{
FLAG=ALLOW_USE;
}
9)接收終端數據並進行處理模塊
#ifdef ZDO_COORDINATOR
// 接收終端上傳的溫度數據
uint8 id=pkt->cmd.Data[0];//終端id
uint8 t=pkt->cmd.Data[1]; //終端溫度
uint8 h=pkt->cmd.Data[2]; //終端濕度
uint8 f=pkt->cmd.Data[3]; //終端火
uint8 y=pkt->cmd.Data[4]; //終端煙霧
if(id==1)
{
//保存終端1的溫度和濕度
temp1Int=t;
hum1Int=h;
yanwu1Int=y;
fire1Int=f;
}
else if(id==2)
{
//保存終端2的溫度和濕度
temp2Int=t;
hum2Int=h;
yanwu2Int=y;
fire2Int=f;
}
else if(id==3)
{
//保存終端3的溫度和濕度
temp3Int=t;
hum3Int=h;
yanwu3Int=y;
fire3Int=f;
}
//蜂鳴器報警
if(temp1Int>25||hum1Int<30||fire1Int==0||yanwu1Int>40)
tm1=1;
else
tm1=0;
if(temp2Int>25||hum2Int<30||fire2Int==0||yanwu2Int>40)
tm2=1;
else
tm2=0;
if(temp3Int>25||hum3Int<30||fire3Int==0||yanwu3Int>40)
tm3=1;
else
tm3=0;
if(f==0&&FLAG==ALLOW_USE)//有火報警
{
P0_7=0;
DATA_PIN2=1;
}
else if(t>25&&FLAG==ALLOW_USE)//溫度高於35度報警
{
P0_7=0;
DATA_PIN2=1;
}
else if(h>0&&h<30&&FLAG==ALLOW_USE)//濕度低於30報警
{
P0_7=0;
DATA_PIN2=1;
}
else if(y>40&&FLAG==ALLOW_USE)
{
P0_7=0;
DATA_PIN2=1;
}
else if(FLAG==ALLOW_USE)
{
P0_7=1;//不報警
DATA_PIN2=0;
}
10)上位機的主要代碼
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string data=serialPort1.ReadLine();//通過串口讀取下位機發送來的數據
textBox13.Text = data;
string[] arr = Regex.Split(data, @"\s+");
if(arr[1]!=null){//對溫濕度,氣體濃度的顯示框顯示示數
textBox1.Text = " " + arr[0];
textBox2.Text = " " + arr[1];
textBox3.Text = " " + arr[3];
textBox4.Text = " " + arr[7];
textBox5.Text = " " + arr[4];
textBox6.Text = " " + arr[5];
textBox7.Text = " " + arr[11];
textBox8.Text = " " + arr[8];
textBox9.Text = " " + arr[9];
button1.BackColor = System.Drawing.Color.Lime;
button4.BackColor = System.Drawing.Color.Lime;
button6.BackColor = System.Drawing.Color.Lime;
button8.BackColor = System.Drawing.Color.Lime;
if (Convert.ToInt32(arr[2]) == 1)//判斷是否報警,來更改報警按鈕顏色
{
button1.BackColor = System.Drawing.Color.Red;
SystemSounds.Beep.Play();//實現報警
}
else
button1.BackColor = System.Drawing.Color.Lime;
if (Convert.ToInt32(arr[6]) == 1)
{
button4.BackColor = System.Drawing.Color.Red;
//SystemSounds.Beep.Play();
}
else
button4.BackColor = System.Drawing.Color.Lime;
if (Convert.ToInt32(arr[10]) == 1)
{
button6.BackColor = System.Drawing.Color.Red;
//SystemSounds.Beep.Play();
}
else
button8.BackColor = System.Drawing.Color.Lime;
if (Convert.ToInt32(arr[12]) == 0)
{
flag1 = false;
button2.Image = Properties.Resources.switch1;
}
else
{
flag1 = true;
button2.Image = Properties.Resources.switch2;
}
chart_TShow(1, Convert.ToInt32(arr[0]));//繪制溫度曲線
chart_TShow(2, Convert.ToInt32(arr[4]));
chart_TShow(3, Convert.ToInt32(arr[8]));
chart_HShow(1, Convert.ToInt32(arr[1]));//繪制濕度曲線
chart_HShow(2, Convert.ToInt32(arr[5]));
chart_HShow(3, Convert.ToInt32(arr[9]));
chart_SShow(1, Convert.ToInt32(arr[3]));//繪制煙霧曲線
chart_SShow(2, Convert.ToInt32(arr[7]));
chart_SShow(3, Convert.ToInt32(arr[11]));
}
}
四、調試分析
將代碼分別燒錄進終端與協調器里,將傳感器與蜂鳴器等組裝好,便可以進入測試:
測試截圖:
上位機顯示截圖:
等待協調器與終端進行組網,組網成功后它們led燈會亮,這時候我們就能開始在上位機上了解各個節點的情況。在靠經火焰傳感器的附近打火,這時候便可以聽到蜂鳴器在報警,同時繼電器也開 始工作讓水泵也運行起來,接着我們可以聽到上位機也在報警,對應節點報警的那一欄Alarm變為紅色,同時有報警提示音。接着我們嘗試提高溫度或降低濕度或增大煙霧濃度來達到報警界限,同樣能聽到報警,繼電器也正常進行工作。當一切正常的時候,在上位機上按下繼電器的開關,也能使繼電器進入工作狀態,再按一下就能實現關閉。同理,按下協調器上的k1也能使繼電器工作,再按一下就能實現關閉。
遇到的問題:
我們的火災檢測系統制作的磕磕碰碰,主要幾點讓我印象深刻的就是下面幾個問題:最開始協調器上的繼電器與蜂鳴器設置出現了bug,因為最開始設定檢測到有火,蜂鳴器和繼電器就一起工作,於是便定義了一個變量,但真正測試的時候發現蜂鳴器一直在叫而繼電器工作時斷時續,我們以為是代碼出了問題,最后經過排查發現它們用到的口重復了。還有就是上位機中碰到的困難就是用到新的工具Visual Studio2022來制作上位機,並且用到的是C#語言,入手起來比較困難。最后便是發現上位機控制繼電器,繼電器並不能正常的聽取控制,后來發現是協調器里的一部分代碼占用了串口導致出了問題,最后經過修正也正常了。多余的沒提到的小問題也基本上都是代碼編寫方面的問題,經過討論與請教同學最后都得到了很好的解決。
五、總結分析
本次課設我們小組對於火災檢測系統的功能都實現了,要求分析里面的功能該有的也基本上都有了。我們完成了通過溫濕度傳感器、煙霧傳感器和火焰傳感器的判斷,能對快起火情況以及起火情況做出報警並且啟動繼電器讓水泵進行工作,同時我們也能在上位機上看到具體是哪個節點出現了問題,那個節點那里的溫濕度、氣體濃度以及有無火焰的狀態也都能看到,還能通過手動按下上位機的按鈕或是協調器的k1控制水泵的工作。
當然我們完成的這些也只能算是完成了最基本的一些功能,其實還可以加入更多的功能來完善它讓火災檢測系統變得更加完整更加優秀,比如說在用幾個傳感器測量其他條件因素來判斷是否起火的情況,加入語音模塊能夠實現語音控制水泵工作,加上藍牙模塊我們還可以在手機上看到節點情況,收到報警信息等等。
六、團隊運行情況以及個人工作描述
我們小組成員有我、余志輝和張童欣,起初,我們的打算是一個做協調器(帶有蜂鳴器),一個做終端節點(帶有溫濕度傳感器、氣體傳感器和火焰傳感器),最后一個也做終端(帶有繼電器),結果通過簡單的串口調試助手顯示。但是我們呢發現最后一個終端節點太過簡單,沒有必要在耗費一個人去做,於是就決定把繼電器也放在協調器上,不做終端節點的人則去做上位機,設計一個可以控制協調器的上位機。最終的分工就是張童欣和余志輝同學負責協調器與終端節點,而我負責制作一個上位機以及負責通過串口的一些輸入與輸出的編寫。他們倆前期是先了解傳感器的工作原理與引腳,以及查看z_stack代碼里面的一些函數如何使用,然后他們在考慮如何去設計組網,選用哪種方式去組網,前期進展的比較慢,都在慢慢的學習掌握。我前期則是先選擇制作上位機的軟件,有VB,VS等等很多工具的選擇,最后我選擇用VS,它的制作窗口是用C#來進行,接着我便從網上找來一些相關的串口窗口制作的文章以及視頻來觀看學習。當他們的代碼完成的差不多了的時候,我的上位機也差不多完成了,然后我就在他們的代碼基礎上加上簡單的串口輸入以及輸出,再進行后期調試。期間我們碰到問題也會進行討論與琢磨。對於我自己工作的完成情況我是比較滿意的,上位機需要有的基本功能我都實現了,對於我的兩位同學的任務完成情況我認為也是很優秀的,他們對代碼進行不厭其煩的修改,把一些較為混亂的代碼進行簡潔化與整理化,以及到最后了他們還在考慮能不能在添加一些什么功能上去,能和他們一起完成這次課設是我的榮幸。就基礎功能而言我認為我們團隊完成的還是比較優秀的,當然我們還需再接再厲,一起進步,一起加油!