?
1. 前言
隨著人們生活質量的提高,對于生活環境的問題,人們的關注度進一步提高,同時政府部門采取了許多措施來改善環境狀況。但是總體上來說我國的環境監測技術水平比較落后,傳統上的監測手段比較單一,監測數據也不夠準確,耗盡了大量的人力和財力,卻成效不高。
針對上述缺點,當前文章綜合了嵌入式處理技術、傳感器技術、無線網絡通信等技術,設計了一個基于STM32的無線環境監測系統,系統主要實現了對濕度、溫度、有毒氣體、煙霧濃度、空氣質量等參數進行實時監測的功能。為了實現無線數據傳輸功能,采用了無線wifi技術。系統的測試分析表明系統整體數據采集性能良好,數據傳輸穩定性可靠,到達了預期目標。
系統與傳統的監測技術相比,具有監測數據準確,監測范圍廣,智能化高等特點。且系統具有一定的創新性,在實際的工程運用和理論研究上體現出了一定的研究價值最后通過實物的調試,各項參數及功能符合設計要求,能達到預期的目的。
設計以STM32微控制器為平臺,采用DHT11溫濕度傳感器、煙霧傳感器MQ-2、易燃氣體傳感器MQ-4、空氣質量檢測傳感器MQ-135對室內溫濕度和危險氣體進行采集。通過wifi無線網絡將數據傳送給微控制器,STM32微控制器處理數據后,由自帶oled液晶屏顯示。當室內溫度達到預警值或有危險氣體時,系統將會自動警報并將警報信息通過wifi網絡傳輸給客戶手機。且每隔一段時間會通過wifi自動發送監測信息到手機,從而實現對室內環境的監測及報警功能。
源碼獲取: https://download.csdn.net/download/xiaolong1126626497/63979263
基于STM32設計的環境監測項目
2. 實現功能與整體框架圖
開發板采用STM32最小系統板,主控CPU采用STM32F103C8T6,其他傳感器采用模塊的形式連接到開發板。
主要實現以下功能實現: 1、通過DHT11溫濕度傳感器、煙霧傳感器MQ-2、易燃氣體傳感器MQ-4、空氣質量檢測傳感器MQ-135對室內溫濕度和危險氣體進行采集。 2、通過傳感器用ADC模擬數字的轉換,采集到的數據顯示在oled屏幕上。 3、當檢測到的數據超過設定的安全值時,屏幕上會顯示警報。 4、檢測到的數據能定時通過ESP8266 wifi無線傳輸發送到所連接的用戶的手機上,實現監測功能。
系統框架圖如下:
3. 硬件特點介紹
(1) 溫濕度傳感器 溫濕度傳感器采用DHT11,這是一款直接輸出數字信號的溫濕度傳感器;其精度濕度±5%RH, 溫度±2℃,量程濕度5~95%RH, 溫度-20~+60℃。通過單總線時序輸出,占用的IO口也比較少,工作電壓3V~5V,單片機連接控制很方便。
(2) MQ系列的氣體檢測傳感器 煙霧傳感器MQ-2、易燃氣體傳感器MQ-4、空氣質量檢測傳感器MQ-135,這些傳感器都是輸出模擬信號。 配置好STM32的ADC采集接口,采集數據進行處理即可。
(3) ESP8266 WIFI 聯網的模塊采用ESP8266 WIFI,ESP8266在物聯網里使用非常多,有很多成熟的案例.WIFI本身也支持二次開發,默認集成的SDK支持AT指令控制,單片機可以通過串口方式控制ESP8266完成網絡通信,非常方便.
(4) OLED顯示屏 OLED顯示屏采用中景園電子的0.96寸OLED,分辨率是128x64,使用的SPI引腳接口屏幕,刷屏速度很快,控制簡單
(5) 上位機設計
手機APP和PC端沒有單獨設計精美的界面,只是簡單的展示了數據顯示。
4. 核心源碼
?編輯
4.1 DHT11溫濕度代碼
#include "dht11.h"
#include "delay.h"
?
//復位DHT11
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //SET OUTPUT
DHT11_DQ_OUT=0; //拉低DQ
DelayMs(20); //拉低至少18ms
DHT11_DQ_OUT=1; //DQ=1
delay_us(30); //主機拉高20~40us
}
//等待DHT11的回應
//返回1:未檢測到DHT11的存在
//返回0:存在
u8 DHT11_Check(void)
{
u8 retry=0;
DHT11_IO_IN();//SET INPUT
while (DHT11_DQ_IN&&retry<100)//DHT11會拉低40~80us
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
else retry=0;
while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后會再次拉高40~80us
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
return 0;
}
//從DHT11讀取一個位
//返回值:1/0
u8 DHT11_Read_Bit(void)
{
u8 retry=0;
while(DHT11_DQ_IN&&retry<100)//等待變為低電平
{
retry++;
delay_us(1);
}
retry=0;
while(!DHT11_DQ_IN&&retry<100)//等待變高電平
{
retry++;
delay_us(1);
}
delay_us(40);//等待40us
if(DHT11_DQ_IN)return 1;
else return 0; ?
}
?
//從DHT11讀取一個字節
//返回值:讀到的數據
u8 DHT11_Read_Byte(void) ? ?
{ ? ? ? ?
? ?u8 i,dat;
? ?dat=0;
for (i=0;i<8;i++)
{
? dat<<=1;
? ?dat|=DHT11_Read_Bit();
? } ? ?
? ?return dat;
}
?
?
//從DHT11讀取一次數據
//temp:溫度值(范圍:0~50°)
//humi:濕度值(范圍:20%~90%)
//返回值:0,正常;1,讀取失敗
u8 DHT11_Read_Data(u8 *temp,u8 *humi) ? ?
{ ? ? ? ?
u8 buf[5];
u8 i;
DHT11_Rst();
//printf("------------------------\r\n");
if(DHT11_Check()==0)
{
for(i=0;i<5;i++)//讀取40位數據
{
buf[i]=DHT11_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
*humi=buf[0];
*temp=buf[2];
}
}else return 1;
return 0; ? ?
}
?
?
//初始化DHT11的IO口 DQ 同時檢測DHT11的存在
//返回1:不存在
//返回0:存在 ?
u8 DHT11_Init(void)
{
RCC->APB2ENR|=1<<2; ? ?//使能PORTG口時鐘
GPIOA->CRL&=0XFF0FFFFF;//PORTG.11 推挽輸出
GPIOA->CRL|=0X00300000;
GPIOA->ODR|=1<<5; ? ? ?//輸出1 ? ?
DHT11_Rst();
return DHT11_Check();
}
4.2 ESP8266代碼
#include "esp8266.h"
extern u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; //接收緩沖,最大USART3_MAX_RECV_LEN字節
extern u8 USART3_TX_BUF[USART3_MAX_SEND_LEN]; //發送緩沖,最大USART3_MAX_SEND_LEN字節
extern vu16 USART3_RX_STA; //接收數據狀態
?
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//用戶配置區
?
//連接端口號:8086,可自行修改為其他端口.
const u8 portnum[]="8089";
?
//WIFI STA模式,設置要去連接的路由器無線參數,請根據你自己的路由器設置,自行修改.
const u8 wifista_ssid[]="wbyq1"; //路由器SSID號
const u8 wifista_encryption[]="wpa2_aes"; //wpa/wpa2 aes加密方式
const u8 wifista_password[]="123456789"; //連接密碼
?
//WIFI AP模式,模塊對外的無線參數,可自行修改.
const u8 wifiap_ssid[]="Cortex_M3"; //對外SSID號
const u8 wifiap_encryption[]="wpawpa2_aes"; //wpa/wpa2 aes加密方式
const u8 wifiap_password[]="12345678"; //連接密碼
?
?
/*
函數功能:向ESP82668266發送命令
函數參數:
cmd:發送的命令字符串
ack:期待的應答結果,如果為空,則表示不需要等待應答
waittime:等待時間(單位:10ms)
返 回 值:
0,發送成功(得到了期待的應答結果)
1,發送失敗
*/
u8 ESP8266_SendCmd(u8 *cmd,u8 *ack,u16 waittime)
{
u8 res=0;
USART3_RX_STA=0;
UsartStringSend(USART3,cmd);//發送命令
if(ack&&waittime) //需要等待應答
{
while(--waittime) //等待倒計時
{
DelayMs(10);
if(USART3_RX_STA&0X8000)//接收到期待的應答結果
{
if(ESP8266_CheckCmd(ack))
{
res=0;
//printf("cmd->ack:%s,%s\r\n",cmd,(u8*)ack);
break;//得到有效數據
}
USART3_RX_STA=0;
}
}
if(waittime==0)res=1;
}
return res;
}
?
?
/*
函數功能:ESP8266發送命令后,檢測接收到的應答
函數參數:str:期待的應答結果
返 回 值:0,沒有得到期待的應答結果
其他,期待應答結果的位置(str的位置)
*/
u8* ESP8266_CheckCmd(u8 *str)
{
char *strx=0;
if(USART3_RX_STA&0X8000) //接收到一次數據了
{
USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加結束符
strx=strstr((const char*)USART3_RX_BUF,(const char*)str); //查找是否應答成功
printf("RX=%s",USART3_RX_BUF);
}
return (u8*)strx;
}
?
/*
函數功能:向ESP8266發送指定數據
函數參數:
data:發送的數據(不需要添加回車)
ack:期待的應答結果,如果為空,則表示不需要等待應答
waittime:等待時間(單位:10ms)
返 回 值:0,發送成功(得到了期待的應答結果)luojian
*/
u8 ESP8266_SendData(u8 *data,u8 *ack,u16 waittime)
{
u8 res=0;
USART3_RX_STA=0;
UsartStringSend(USART3,data);//發送數據
if(ack&&waittime) //需要等待應答
{
while(--waittime) //等待倒計時
{
DelayMs(10);
if(USART3_RX_STA&0X8000)//接收到期待的應答結果
{
if(ESP8266_CheckCmd(ack))break;//得到有效數據
USART3_RX_STA=0;
}
}
if(waittime==0)res=1;
}
return res;
}
?
/*
函數功能:ESP8266退出透傳模式
返 回 值:0,退出成功;
1,退出失敗
*/
u8 ESP8266_QuitTrans(void)
{
while((USART3->SR&0X40)==0); //等待發送空
USART3->DR='+';
DelayMs(15); //大于串口組幀時間(10ms)
while((USART3->SR&0X40)==0); //等待發送空
USART3->DR='+';
DelayMs(15); //大于串口組幀時間(10ms)
while((USART3->SR&0X40)==0); //等待發送空
USART3->DR='+';
DelayMs(500); //等待500ms
return ESP8266_SendCmd("AT","OK",20);//退出透傳判斷.
}
?
?
/*
函數功能:獲取ESP82668266模塊的AP+STA連接狀態
返 回 值:0,未連接;1,連接成功
*/
u8 ESP8266_ApStaCheck(void)
{
if(ESP8266_QuitTrans())return 0; //退出透傳
ESP8266_SendCmd("AT+CIPSTATUS",":",50); //發送AT+CIPSTATUS指令,查詢連接狀態
if(ESP8266_CheckCmd("+CIPSTATUS:0")&&
ESP8266_CheckCmd("+CIPSTATUS:1")&&
ESP8266_CheckCmd("+CIPSTATUS:2")&&
ESP8266_CheckCmd("+CIPSTATUS:4"))
return 0;
else return 1;
}
?
?
/*
函數功能:獲取ESP8266模塊的連接狀態
返 回 值:0,未連接;1,連接成功.
*/
u8 ESP8266_ConstaCheck(void)
{
u8 *p;
u8 res;
if(ESP8266_QuitTrans())return 0; //退出透傳
ESP8266_SendCmd("AT+CIPSTATUS",":",50); //發送AT+CIPSTATUS指令,查詢連接狀態
p=ESP8266_CheckCmd("+CIPSTATUS:");
res=*p; //得到連接狀態
return res;
}
?
/*
函數功能:獲取ip地址
函數參數:ipbuf:ip地址輸出緩存區
*/
void ESP8266_GetWanip(u8* ipbuf)
{
u8 *p,*p1;
if(ESP8266_SendCmd("AT+CIFSR\r\n","OK",50))//獲取WAN IP地址失敗
{
ipbuf[0]=0;
return;
}
p=ESP8266_CheckCmd(""");
p1=(u8*)strstr((const char*)(p+1),""");
*p1=0;
sprintf((char*)ipbuf,"%s",p+1);
}
?
/*
函數功能:將收到的AT指令應答數據返回給電腦串口
參 數:mode:0,不清零USART3_RX_STA;
1,清零USART3_RX_STA;
*/
void ESP8266_AtResponse(u8 mode)
{
if(USART3_RX_STA&0X8000) //接收到一次數據了
{
USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加結束符
printf("%s",USART3_RX_BUF); //發送到串口
if(mode)USART3_RX_STA=0;
}
}
?
?
/*
函數功能:ESP8266 AP模式+TCP服務器模式測試
*/
void ESP8266_APorServer(void)
{
u8 p[100];
u8 ipbuf[20];
while(ESP8266_SendCmd("AT\r\n","OK",20))//檢查WIFI模塊是否在線
{
ESP8266_QuitTrans();//退出透傳
ESP8266_SendCmd("AT+CIPMODE=0\r\n","OK",200); //關閉透傳模式
printf("未檢測到模塊,正在嘗試連接模塊...\r\n");
DelayMs(800);
}
printf("ESP8266模塊檢測OK!\r\n");
while(ESP8266_SendCmd("ATE0\r\n","OK",20)); //關閉回顯
printf("請用設備連接WIFI熱點:%s,%s,%ss\r\n",(u8*)wifiap_ssid,(u8*)wifiap_encryption,(u8*)wifiap_password);
/*1. 設置WIFI AP模式 */
ESP8266_SendCmd("AT+CWMODE=2\r\n","OK",50);
/*2. 重啟模塊 */
ESP8266_SendCmd("AT+RST\r\n","OK",20);
/*3. 延時3S等待重啟成功*/
DelayMs(1000);
DelayMs(1000);
DelayMs(1000);
/*5. 配置模塊AP模式無線參數*/
sprintf((char*)p,"AT+CWSAP="%s","%s",1,4\r\n",wifiap_ssid,wifiap_password);
ESP8266_SendCmd(p,"OK",1000);
/*4. 設置多連接模式:0單連接,1多連接(服務器模式必須開啟)*/
ESP8266_SendCmd("AT+CIPMUX=1\r\n","OK",20);
/*5. 開啟Server模式(0,關閉;1,打開),端口號為portnum */
sprintf((char*)p,"AT+CIPSERVER=1,%s\r\n",(u8*)portnum);
ESP8266_SendCmd(p,"OK",50);
/*6. 獲取當前模塊的IP*/
ESP8266_GetWanip(ipbuf);//
printf("IP地址:%s 端口:%s",ipbuf,(u8*)portnum);
USART3_RX_STA=0; //清空串口的接收標志位
// while(1)
// {
// key=GetKeyVal(1);//退出測試
// if(key==1)
// {
// printf("退出測試!\r\n");
// ESP8266_QuitTrans(); //退出透傳
// ESP8266_SendCmd("AT+CIPMODE=0","OK",20); //關閉透傳模式
// break;
// }
// else if(key==2) //發送數據
// {
// ESP8266_SendCmd("AT+CIPSEND=0,12\r\n","OK",200); //設置發送數據長度為12個
// ESP8266_SendData("ESP8266測試!","OK",100); //發送指定長度的數據
// DelayMs(200);
// }
// t++;
// DelayMs(10);
// if(USART3_RX_STA&0X8000) //接收到一次數據了
// {
// rlen=USART3_RX_STA&0X7FFF; //得到本次接收到的數據長度
// USART3_RX_BUF[rlen]=0; //添加結束符
// printf("接收的數據: rlen=%d,%s",rlen,USART3_RX_BUF); //發送到串口
// USART3_RX_STA=0;
// if(constate!=3)t=1000; //狀態為還未連接,立即更新連接狀態
// else t=0; //狀態為已經連接了,10秒后再檢查
// }
// if(t==1000)//連續10秒鐘沒有收到任何數據,檢查連接是不是還存在.
// {
//// constate=ESP8266_ConstaCheck();//得到連接狀態
//// if(!constate)printf("連接失敗!\r\n");
// t=0;
// }
// if((t%20)==0)LED2=!LED2;
// ESP8266_AtResponse(1);
// }
}
?審核編輯:湯梓紅
-
STM32
+關注
關注
2266文章
10871瀏覽量
354817 -
監測系統
+關注
關注
8文章
2676瀏覽量
81255 -
檢測設備
+關注
關注
0文章
608瀏覽量
16730
發布評論請先 登錄
相關推薦
評論