基于STM32设计的森林火灾预警系统(联动控制+SIM800C+华为云IoT)

1. 功能介绍

随着全球气候变化和人类活动的增加,森林火灾成为了一个严重的环境问题。及早发现和迅速响应火灾事件对于减少火灾的损失至关重要。为了实现对森林火灾的快速预警和联动控制,决定利用华为云IoT物联网平台来搭建一个高效的系统模型。

该系统模型的目标是在检测到森林火灾后,能够快速将火灾信息上报到云平台,并与指定的服务器进行数据报告的交互。同时,系统还能自动向抽水泵发送指令,打开开关以进行抽水灭火操作。通过这样的联动控制系统,可以实现快速响应和减少火灾对森林和生态环境的破坏。

该系统模型的核心是华为云IoT物联网平台,它提供了丰富的功能和服务,包括设备接入、数据采集、消息通信、云端数据存储和分析等。我们可以利用该平台的能力来接收来自火灾检测设备的数据,并通过云端的数据分析和处理来实现火灾预警和联动控制。

当火灾检测设备检测到火灾时,会通过无线通信将火灾信息发送到华为云IoT物联网平台。云平台接收到信息后,会立即进行处理并将火灾报告发送给指定的服务器。服务器可以根据报告中的信息采取相应的措施,如调度抽水泵进行灭火操作。

通过这个系统模型,可以实现对森林火灾的快速预警和联动控制,大大提高了火灾应对的效率和准确性。同时,利用华为云IoT物联网平台的强大功能,可以灵活地扩展和定制系统,以适应不同规模和需求的森林火灾防控工作。

硬件平台介绍:

MCU: STM32F103ZET6

物联网云平台: 华为IOT云平台

气体检测传感器: MQ2-烟雾传感器、MQ135-空气质量检测传感器

火焰检测: 采用火焰检测传感器

抽水机: 采用直流电机模拟水泵,打开开关抽水喷水灭火

上网网卡: 采用GSM模块SIM800C,使用的是物联网专用卡,包年只能上网这种。

与云端服务器的通信协议: 终端设备采用MQTT3.1.1协议与华为云服务器进行登录连接。

温湿度检测传感器: DHT11

供电方式: 电池+太阳能供电

为了演示联动控制,火警(烟雾)检测装置和灭火(直流电机)装置分为两个独立的设备,分别连接上云端。

火警检测装置连接上物联网服务器之后,可以在服务器上配置数据处理规则,如果烟雾浓度超标,可以自动向灭火装置发送指令,进行灭火操作。服务器收到火警检测装置上传的烟雾浓度、空气质量等数据后,可以向自己的私有服务器转发数据,方便自己服务器收到数据后做分析存储处理,比如: 向指定邮箱发送邮件、手机APP推送通知栏、向指定用户推送短消息提示等等。

2. 创建产品(火警预警装置)

打开官网链接: www.huaweicloud.com/s/JeeJqeiBl...

(1)选择设备接入IotTDA选项。

(2)选择免费试用。

(3)在产品页面选择创建新的产品。

(4)填入产品信息,创建产品

(5)选择自己刚才创建的产品,创建数据模型,点击自定义模型

(6)选择添加属性

这个添加的属性就是设备端上报的数据类型。 比如: MQ2烟雾传感器检测的烟雾数据值类型。

在这个页面上还有一个添加命令的功能,这是用于云端下发指令给设备端使用的。当前这个设备是火警检测装置,只需要上报数据给服务器,不需要下发指令,这里就只需要添加属性就行了。

根据自己的设备的具体情况填写即可,如果上报的数据有多种类型就创建多个属性。

3. 创建产品(灭火装置)

创建的流程和上面一样,这是多增加了一个命令下发的功能,方便云端远程控制电机开启和关闭,实现灭火功能。

(1)创建产品

(2)产品创建完毕之后,添加服务器ID

(3)添加属性,电机属性是可以读可以写的,范围设置为0和1,只能开关

(4)添加命令,这个命令用于云端远程向设备下发指令,设备收到指令后可以做出相应的逻辑处理

接着选择新增输入参数:

最后点击确定即可。

现在产品已经创建完毕。

4. 创建设备(火警预警装置)

(1)在设备页面,选择注册设备,选择自己的对应的产品,设备标识码一般填自己设备的硬件标号。

(2)设备创建成功之后会弹出弹窗,点击保存并关闭,会自动弹出下载窗口,是个文本文件,存放了密匙信息

json 复制代码
{
     "device_id": "61bacdc02b2aa20288c5a094_QQ1126626497",
     "secret": "1126626497"
 }

5. 创建设备(灭火装置)

流程与上面火警预警装置设备一样的。

json 复制代码
{
     "device_id": "61bad0564d9b020287193be2_QQ1126626497",
     "secret": "1126626497"
 }

6. 生成MQTT协议登录ID和密匙

设备创建完成接来下生成MQTT登录账号、密匙,方便设备登录云端平台。

官网工具地址: iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

填入刚才创建设备时,保存下载文件里的信息,对着弹窗填入,最后生成了ID、用户名、密码参数,用于MQTT协议登录使用。

(1)火警预警装置生成登录参数

复制代码
ClientId  61bacdc02b2aa20288c5a094_QQ1126626497_0_0_2021121605
 Username  61bacdc02b2aa20288c5a094_QQ1126626497
 Password  43ed43bcbddc48772694fc2b18ec1112170f4d6cc52fbf1e01401c2ea1748475

(2)灭火装置

复制代码
ClientId 61bad0564d9b020287193be2_QQ1126626497_0_0_2021121605
 Username 61bad0564d9b020287193be2_QQ1126626497
 Password 43ed43bcbddc48772694fc2b18ec1112170f4d6cc52fbf1e01401c2ea1748475

7. 上报属性格式与主题订阅格式

产品设备、MQTT登录参数都到位了,接下来需要了解设备向服务器上报数据时,如何上报,格式是怎么样的。

(1)第一个问题是:华为云IoT物联网服务器的IP和端口号是多少?

在总览选项页面,点击多协议接入选项,就能看到了。

如果选择MQTT协议接入:

makefile 复制代码
域名是: a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
 如果你的设备不能解析域名,也可以直接填IP地址 121.36.42.100
 端口号: 1883

(2)第二个问题是:发布数据的主题和订阅数据的主题怎么填?

在产品页面,选择自己的产品,进去之后就能看到主题的格式介绍页面了。

为了方便后续复制粘贴,这里总结下格式:

火警预警装置:

bash 复制代码
格式: $oc/devices/{device_id}/sys/messages/down
 //订阅主题: 平台下发消息给设备
 $oc/devices/61bacdc02b2aa20288c5a094_QQ1126626497/sys/messages/down
 ​
 ​
 格式: $oc/devices/{device_id}/sys/properties/report
 //设备上报数据
 $oc/devices/61bacdc02b2aa20288c5a094_QQ1126626497/sys/properties/report

灭火装置:

bash 复制代码
格式: $oc/devices/{device_id}/sys/messages/down
 //订阅主题: 平台下发消息给设备
 $oc/devices/61bad0564d9b020287193be2_QQ1126626497/sys/messages/down
 ​
 ​
 格式: $oc/devices/{device_id}/sys/properties/report
 //设备上报数据
 $oc/devices/61bad0564d9b020287193be2_QQ1126626497/sys/properties/report

(3)第三个问题是:上报属性时,数据格式是什么?

官方文档介绍: support.huaweicloud.com/devg-iothub...

总结下格式: 上报的数据就是JSON格式,一次性可以上传多个属性数据,JSON数组里按照顺序增加即可。

重要的字段含义解释:这两个字段后面的数据需要自己根据自己的设备产品去填充的。

matlab 复制代码
service_id 示设备服务的ID。
 ​
 properties 是设备服务的属性列表,具体字段在设备关联的产品模型中定义。

火警预警装置上传的数据:

json 复制代码
{"services": [{"service_id": "MQ2","properties":{"MQ2":100}}]}

灭火装置上传的数据:

json 复制代码
{"services": [{"service_id": "motor","properties":{"motor":1}}]}

8. 使用MQTT客户端模拟设备测试

(1)登录火警预警装置

(2)灭火装置登录

可以看到,设备已经成功登录服务器,完成了数据上报。这也证明服务器端设备创建已经全部OK,正常。

9. 配置设备联动

(1)创建规则

(2)填写规则信息

(3)添加触发条件,选择需要处理数据的设备,设置条件:当烟雾浓度大于等于100就触发

(4)添加执行动作,当烟雾浓度超过100就下发指令给灭火装置

(3)最后点击创建规则,生效规则

(4)测试效果

使用两个MQTT客户端分别模拟火警预警装置和灭火装置,当烟雾浓度超过100时,查看灭火装置是否收到云端下发的指令。

10. 数据转发

如果数据需要转发到其他地方,可以自己创建规则配置。

11. 硬件设备测试

设备端采用GSM模块SIM800C完成上网功能,主控MCU采用STM32F103ZET6。

任意只要能上网的设备都可以使用当前代码连接服务器,因为当前模拟的是户外设备,只能采用GSM模块上网。

如果是智能家居,屋里小区的设备,有WIFI的可以采用ESP8266这些无线网卡。

项目工程源码: download.csdn.net/download/xi...

1. SIM800C.c

这是SIM800C的配置代码

cpp 复制代码
#include "sim800c.h"
 ​
 /*
 函数功能:向SIM800C模块发送指令
 函数参数:
                 char *cmd  发送的命令
               char *check_data 检测返回的数据
 返回值: 0表示成功 1表示失败
 */
 u8 SIM800C_SendCmd(char *cmd,char *check_data)
 {
    u16 i,j;
    for(i=0;i< 5;i++) //测试的总次数
    {
       USART2_RX_FLAG=0;
       USART2_RX_CNT=0;
             memset(USART2_RX_BUFF,0,sizeof(USART2_RX_BUFF));
             USART_X_SendString(USART2,cmd); //发送指令
       for(j=0;j< 500;j++) //等待的时间(ms单位)
       {
           if(USART2_RX_FLAG)
           {
               USART2_RX_BUFF[USART2_RX_CNT]='\\0';
               if(strstr((char*)USART2_RX_BUFF,check_data))
               {
                   return 0;
               }
               else break;
           }
           delay_ms(20); //一次的时间
       }
    }
    return 1;
 }
 ​
 ​
 /*
 函数  功能:GSM模块初始化检测
 函数返回值:1表示模块检测失败,0表示成功
 */
 u8 SIM800C_InitCheck(void)
 {
       if(SIM800C_SendCmd("AT\\r\\n","OK"))return 1;
       else printf("SIM800模块正常!\\r\\n");
       
         if(SIM800C_SendCmd("ATE0\\r\\n","OK"))return 2;
       else printf("设置模块不回显成功!\\r\\n");
     
         if(SIM800C_SendCmd("AT+CGMI\\r\\n","OK"))return 3;
         else printf("查询制造商名称成功!%s\\r\\n",USART2_RX_BUFF);
     
         if(SIM800C_SendCmd("AT+CGMM\\r\\n","OK"))return 4;
         else printf("查询模块型号成功!%s\\r\\n",USART2_RX_BUFF);
         
       DelayMs(1000);
         DelayMs(1000);
         if(SIM800C_SendCmd("AT+CNUM\\r\\n","+CNUM:"))return 5;
         else printf("获取本机号码成功!%s\\r\\n",USART2_RX_BUFF);
       /* 返回格式如下:
         +CNUM: "","+8613086989413",145,7,4
         OK
         */
         return 0;
 }
 ​
 /*
 函数  功能:GSM模块短信模式设置
 函数返回值:0表示模块设置成功
 */
 u8 SIM800C_SetNoteTextMode(void)
 {
         if(SIM800C_SendCmd("AT+CSCS="GSM"\\r\\n","OK"))return 1;// "GSM"字符集
         else printf("短信GSM字符集设置成功!\\r\\n");
     
       if(SIM800C_SendCmd("AT+CMGF=1\\r\\n","OK"))return 2; //文本模式
         else printf("短信文本模式设置成功!\\r\\n");
         return 0;
 }
 ​
 /*
 函数功能:发送短信
 函数参数:
                     num:电话号码
                     text:短信内容
 函数返回值:0表示发送成功
 */
 u8 SIM800C_SendNote(u8 *num,u8 *text,u16 len)
 {
         char data[50];
         char send_buf[2];
         sprintf(data,"AT+CMGS="%s"\\r\\n",num);
         if(SIM800C_SendCmd(data," >"))return 1; //设置发送的手机号
         USART_X_SendData(USART2,text,len);     //发送短信内容
     
         send_buf[0] = 0x1a;
         send_buf[1] = '\\0';
       if(SIM800C_SendCmd(send_buf,"+CMGS"))return 2; //发送结束符号
         return 0;
 }
 ​
 ​
 /*
 函数功能:NTP网络同步时间
 */
 void SIM800C_NtpUpdate(void)
 {  
      SIM800C_SendCmd("AT+SAPBR=3,1,"Contype","GPRS"\\r\\n","OK");//配置承载场景1
      SIM800C_SendCmd("AT+SAPBR=3,1,"APN","CMNET"\\r\\n","OK");
      SIM800C_SendCmd("AT+SAPBR=1,1\\r\\n","OK");                     //激活一个GPRS上下文
    DelayMs(5);
    SIM800C_SendCmd("AT+CNTPCID=1\\r\\n","OK");                     //设置CNTP使用的CID
      SIM800C_SendCmd("AT+CNTP="202.120.2.101",32\\r\\n","OK");     //设置NTP服务器和本地时区(32时区 时间最准确)
    SIM800C_SendCmd("AT+CNTP\\r\\n","+CNTP: 1");                    //同步网络时间
      printf("同步网络时间:%s\\r\\n",USART2_RX_BUFF);
 }
 ​
 ​
 /*
 函数功能:GPRS数据通信初始化
 返 回 值: 0表示成功
 */
 u8 SIM800C_GPRS_Init(void)
 {
      SIM800C_SendCmd("AT+CIPCLOSE=1\\r\\n","CLOSE OK");   //关闭连接
      SIM800C_SendCmd("AT+CIPSHUT\\r\\n","SHUT OK");       //关闭移动场景 
      if(SIM800C_SendCmd("AT+CGCLASS="B"\\r\\n","OK"))return 1;              //设置GPRS移动台类别为B,支持包交换和数据交换 
      if(SIM800C_SendCmd("AT+CGDCONT=1,"IP","CMNET"\\r\\n","OK"))return 2;//设置PDP上下文,互联网接协议,接入点等信息
      if(SIM800C_SendCmd("AT+CGATT=1\\r\\n","OK"))return 3;                    //附着GPRS业务
      if(SIM800C_SendCmd("AT+CIPCSGP=1,"CMNET"\\r\\n","OK"))return 4;        //设置为GPRS连接模式
      if(SIM800C_SendCmd("AT+CIPHEAD=1\\r\\n","OK"))return 5;                  //设置接收数据显示IP头(方便判断数据来源)
      return 0;
 }
 ​
 /*
 函数功能: 连接TCP服务器
 函数参数: 
                 ipaddr:ip地址
                 port:端口 
 返 回 值: 0表示成功,其他值表示失败
 */
 u8 SIM800C_Connect_TCP_Server(char *ipaddr,char *port)
 {
      char cmd_buff[100];
      SIM800C_SendCmd("AT+CIPCLOSE=1\\r\\n","CLOSE OK");   //关闭连接
      SIM800C_SendCmd("AT+CIPSHUT\\r\\n","SHUT OK");       //关闭移动场景 
      sprintf(cmd_buff,"AT+CIPSTART="TCP","%s","%s"\\r\\n",ipaddr,port);
      if(SIM800C_SendCmd(cmd_buff,"OK"))return 1;        //发起连接
      return 0;
 }
 ​
 ​
 /*
 函数功能: TCP客户端模式下发送数据
 返 回 值: 0表示成功,其他值表示失败
 */
 u8 SIIM800C_TCP_SendData(u8 *data,u32 len)
 {
      char send_buf[2];
     //准备发送数据
      if(SIM800C_SendCmd("AT+CIPSEND\\r\\n"," >")==0)
      {
           //发送数据
             USART_X_SendData(USART2,data,len);
           //发送结束符号
           DelayMs(50);
           send_buf[0] = 0x1a;
           send_buf[1] = '\\0';
           if(SIM800C_SendCmd(send_buf,"SEND OK"))return 2;
           else  return 0;
      }
      return 1;
 }

2. adc.c

这是烟雾传感器的ADC通道配置代码。

cpp 复制代码
//////////////////////////////////////////////////////////////////////////////////   
 //  功能描述   : 智能环境检测系统
 //   时间      : 20190605
 //   版本      : v3.3
 //             版权所有,盗版必究。
 //Copyright(C) DS小龙哥 2016 - 2020
 ///////////////////////////////////////////////////////////////////////////////////
 #include "adc.h"
 ​
 /*
 函数功能: ADC1的初始化
 规则通道方式
 */
 void ADC1_Init(void)
 {
       /*1. 配置ADC采集输入的IO口*/
     RCC- >APB2ENR |= 1 < < 3;//PB
     GPIOB- >CRL &= 0xFFFFFFF0;
     GPIOB- >CRL |= 0x00000000;//配置PB0为模拟输入模式
     
     /*2.配置ADC1时钟*/
     RCC- >APB2ENR|=1< < 9;         //开启ADC1时钟
     RCC- >APB2RSTR|=1< < 9;        //开启复位时钟
     RCC- >APB2RSTR&=~(1< < 9); //关闭复位时钟
         
     /*3. 配置ADC的预分频器*/
     RCC- >CFGR&=~(0x3< < 14); //清空预分频
     RCC- >CFGR|=0x2< < 14;    //12MHZ
     
     /*4. 配置ADC CR1基本寄存器*/
     ADC1- >CR1&=~(0xF< < 16); //0000:独立模式
     ADC1- >CR2|=1< < 23;      //1:启用温度传感器和VREFINT。
     //ADC1- >CR2|=1< < 22;    //1:开始转换规则通道。
     ADC1- >CR2|=1< < 20;      //1:使用外部事件启动转换
     ADC1- >CR2|=0x7< < 17;    //111: SWSTART
     ADC1- >CR2&=~(1< < 11);   //0:右对齐;
     ADC1- >CR2&=~(1< < 1);    //0:单次转换模式;
     
     /*5. 配置ADC规则序列寄存器*/
     ADC1- >SQR1&=~(0xF< < 20); //0000: 1个转换
     ADC1- >SMPR2|=0x7< < 3;    //配置通道1 111: 239.5周期
     ADC1- >SMPR1|=0x7< < 18;   //配置通道16 111: 239.5周期
         
     ADC1- >CR2|=1< < 0;        //1:开启ADC并启动转换。
     ADC1- >CR2|=1< < 3;        //1:初始化校准寄存器。
     ADC1- >CR2|=1< < 2;        //1:开始校准
     while(ADC1- >CR2&1< < 2){} //等待校准结束
 }
 ​
 ​
 /*
 函数功能: 获取指定通道的ADC值
 函数参数: u8 ch  通道号
 */
 u16 ADC1_GetCHx(u8 ch)
 {
         ADC1- >SQR3&=0xFFFFFFE0;   //00000
       ADC1- >SQR3|=ch< < 0;        //规则序列中的第1个转换
         ADC1- >CR2|=1< < 22;         //1:开始转换规则通道。
         while(!(ADC1- >SR&1< < 1)){} //等待转换完成
         return ADC1- >DR;          //返回接收到的数据值
 }

3. DHT11.c

这是温湿度检测代码。

cpp 复制代码
//////////////////////////////////////////////////////////////////////////////////   
 //  功能描述   : 智能环境检测系统
 //   时间      : 20190605
 //   版本      : v3.3
 //             版权所有,盗版必究。
 //Copyright(C) DS小龙哥 2016 - 2020
 ///////////////////////////////////////////////////////////////////////////////////
 #include "dht11.h"
 #include "delay.h"
 ​
 /*
 复位DHT1
 */
 void DHT11_Rst(void)       
 {                 
       DHT11_IO_OUT();   //SET OUTPUT
     DHT11_DQ_OUT=0;     //拉低DQ
     delay_ms(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();
     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();
 }
相关推荐
zopple6 小时前
常见的 Spring 项目目录结构
java·后端·spring
cjy0001118 小时前
springboot的 nacos 配置获取不到导致启动失败及日志不输出问题
java·spring boot·后端
小江的记录本9 小时前
【事务】Spring Framework核心——事务管理:ACID特性、隔离级别、传播行为、@Transactional底层原理、失效场景
java·数据库·分布式·后端·sql·spring·面试
sheji34169 小时前
【开题答辩全过程】以 基于springboot的校园失物招领系统为例,包含答辩的问题和答案
java·spring boot·后端
程序员cxuan9 小时前
人麻了,谁把我 ssh 干没了
人工智能·后端·程序员
wuyikeer10 小时前
Spring Framework 中文官方文档
java·后端·spring
Victor35610 小时前
MongoDB(61)如何避免大文档带来的性能问题?
后端
Victor35610 小时前
MongoDB(62)如何避免锁定问题?
后端
wuyikeer11 小时前
Spring BOOT 启动参数
java·spring boot·后端
子木HAPPY阳VIP12 小时前
Ubuntu 22.04 VMware 设置固定IP配置
人工智能·后端·目标检测·机器学习·目标跟踪