STM32+SIM800C采用MQTT协议登录OneNet上传温湿度、MQ2烟雾浓度、GPS数据

539 阅读7分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

本系统主控芯片采用STM32F103C8T6,采集DHT11温度、湿度数据、MQ-2烟雾传感器数据实时在OLED显示屏上显示、当烟雾浓度超过阀值时,可以通过SIM800C向指定手机号码发送短信。

一、环境介绍

MCU: STM32F103C8T6

GSM模块: SIM800C

开发软件: Keil5

MQTT协议采用OneNet的旧版协议,登录OneNet控制台创建应用时要选择旧版本。

二、硬件与需求

一块STM32F103C8T6最小系统板。

img

img

一块OLED显示屏

img

一个DHT11温湿度传感器

img

一个MQ-2可燃气体传感器

img

一个SIM800C模块

img

软件要求

采集DHT11温度、湿度数据、采集MQ-2烟雾传感器数据实时在OLED显示屏上显示、当烟雾浓度超过阀值时,可以通过SIM800C向指定手机号码发送短信。

并需要使用SIM800C连接GPRS网络,将温度、湿度、烟雾浓度上传到OneNet服务器进行可视化显示。

三、核心代码

3.1 main.c

 //////////////////////////////////////////////////////////////////////////////////   
 //  功能描述   : 智能环境检测系统
 //   时间      : 20190605
 //   版本      : v3.3
 //             版权所有,盗版必究。
 //Copyright(C) DS小龙哥 2016 - 2020
 ///////////////////////////////////////////////////////////////////////////////////
 #include "stm32f10x.h"
 #include "delay.h"
 #include "usart.h"
 #include <stdio.h>
 #include "dht11.h"
 #include "oled.h"
 #include "adc.h"
 #include "timer.h"
 #include "sim800c.h"
 #include "gps.h"
 ​
 /*
 DTH11接线说明:
 VCC---3.3V
 GND---GND
 DAT---PA5
 ​
 MQ-2接线说明:
 VCC---3.3V
 GND---GND
 AO----PB0
 ​
 使用IIC接口的OLED显示屏接线说明:
 GND---GND
 VCC---3.3V
 SDA---PB7
 SCL---PB6
 ​
 使用SPI接口的OLED显示屏接线说明:
 GND---GND
 VCC---3.3V
 D0-----PB5
 D1-----PB6
 RES----PB7
 DC-----PB8
 CS-----PB9  
 ​
 SIM800C接线说明:
 GND----GND
 PA2----SIM800C_RXD
 PA3----SIM800C_TXD
 ​
 ​
 CH340模块接线说明:
 GND----GND
 RX-----PA9
 ​
 GPS接线说明: (波特率需要根据GPS模块实际情况进行修改)
 GND----GND
 VCC---3.3V
 PB11----GPS_TX
 */
 ​
 u8 dht11_temp,dht11_humi;
 u32 time_cnt=0;
 u32 OneNet_Sendtime=0;
 u8 data_select=0; //发送的数据选择
 u8 DisplayState=0;
 char DisplayDataBuffer[20];
 u16 MQ_2; //存放ADC的数据
 void DisplayPage1(void); //第一页
 void DisplayPage2(void); //第二页
 ​
 //烟雾超标提示
 u8 sim800c_buff[]="MQ-2 smoke exceeded";
 char tmp_buffer[100];
 double Longitude=103.718463; //经度
 double latitude=36.107013;  //纬度
 ​
 int main(void)
 {
     u8 state;
     USART_X_Init(USART1,72,115200); //串口初始化
     printf("串口初始化完成!\r\n");
     OLED_Init();         //OLED显示屏初始化
   ADC1_Init();
     if(DHT11_Init())printf("DHT11检测错误!\r\n");
     
     TIM2_Init(72,20000);//辅助串口3接收,超时时间为20ms
   USART_X_Init(USART2,36,9600); //可能的波特率(测试):  57600 、9600、115200
     
     USART_X_Init(USART3,36,9600);//接GPS模块
   TIM3_Init(72,20000);//辅助串口3接收,超时时间为20ms
     
     //显示初始化信息
   OLED_Clear_GRAM();
     OLED_DisplayString(0,0,16,"System Init..");
     OLED_Refresh_GRAM(); //刷新显存
     
     //延时等待
     printf("延时等待\r\n");
     DelayMs(1000);
     DelayMs(1000);
     DelayMs(1000);
     DelayMs(1000);
     printf("开始初始化SIM800C \r\n");
     
     //初始化SIM800C  
     OLED_DisplayString(0,16,16,"SIM800C Init..");
     OLED_Refresh_GRAM(); //刷新显存
     while(1)
     {
             state=SIM800C_InitCheck();
             if(state==0)break;
             DelayMs(1000);
             printf("SIM800C初始化状态:%d\r\n",state);
     }
     
     //设置文本模式
     OLED_DisplayString(0,32,16,"SIM800C Text Set...");
     OLED_Refresh_GRAM(); //刷新显存
   while(1)
     {
             state=SIM800C_SetNoteTextMode();
             if(state==0)break;
             DelayMs(1000);
             printf("设置文本模式状态:%d\r\n",state);
     }
     //同步网络时间
     //SIM800C_NtpUpdate();
     
     //初始化GPRS
     SIM800C_GPRS_Init();
     while(1)
     {
      delay_ms(1);
      time_cnt++;
          OneNet_Sendtime++;
      //记录时间
      if(time_cnt>=100)
      {
          time_cnt=0;
                  DisplayState=!DisplayState;
          printf("切换页面!\r\n");
      }
      
          //向云端发送一次数据(每次选择发送一种数据)
          if(OneNet_Sendtime>=500) //单位ms
          {
                 OneNet_Sendtime=0;
                switch(data_select)
                  {
                      case 0:OneNet_HTTP_DataUpdate("T",dht11_temp);
                          break;
                      case 1:OneNet_HTTP_DataUpdate("H",dht11_humi);
                          break;
                      case 2:OneNet_HTTP_DataUpdate("MQ2",MQ_2);
                          break;
                      case 3:OneNet_HTTP_GPS_DataUpdate("GPS",Longitude,latitude);
                          break;
                      
                  }
                  data_select++;
                  if(data_select>3)data_select=0;
           }
          
      //采集DHT11温湿度与MQ-2的数据
      DHT11_Read_Data(&dht11_temp,&dht11_humi);
      MQ_2=ADC1_GetCHx(8);
          
          //串口打印数据
 //       printf("温度:%d\r\n",dht11_temp);
 //       printf("湿度:%d\r\n",dht11_humi);
 //       printf("MQ-2:%d\r\n",MQ_2);
          
          //判断烟雾是否超标,设置阀值
      if(MQ_2>=2000)
          {
                 //发送短信
                 if(SIM800C_SendNote((u8*)"13800138000",sim800c_buff,strlen((char*)sim800c_buff))==0)
                     printf("短信发送成功\r\n");
                 else
                     printf("短信发送失败\r\n");
          }
          
          
      //采用时间间隔切换页面
      if(DisplayState)
      {
          DisplayPage2();
      }
      else 
      {
          DisplayPage1();
      }
      
         //实时接收WIFI收到的数据
      if(USART2_RX_FLAG)
      {
          USART2_RX_BUFF[USART2_RX_CNT]='\0';
          USART2_RX_CNT=0;
          USART2_RX_FLAG=0;
                printf("USART2_RX_BUFF=%s\r\n",USART2_RX_BUFF);
          memset(USART2_RX_BUFF,0,sizeof(USART2_RX_BUFF));
      }
          
          //实时接收GPS收到的数据
      if(USART3_RX_FLAG)
      {
          USART3_RX_BUFF[USART3_RX_CNT]='\0';
          USART3_RX_CNT=0;
          USART3_RX_FLAG=0;
                  //解析GPS经纬度信息
                  GPS_GPRMC_Decoding(USART3_RX_BUFF,&Longitude,&latitude);
                printf("经度:%f,纬度:%f\r\n",Longitude,latitude);
                printf("USART2_RX_BUFF=%s\r\n",USART3_RX_BUFF);
          memset(USART2_RX_BUFF,0,sizeof(USART3_RX_BUFF));
      }
      }
 }
 ​
 /*
 函数功能:  温湿度DHT11显示页面
 */
 void DisplayPage2(void)
 {
         u8 i;
     OLED_Clear_GRAM();
         /*1. 最上方界面提示*/
         for(i=0;i<5;i++)
         {
             OLED_DisplayData(24+i*16,0,16,16,ChineseFont[i+8]); 
         }
         
         /*2. 温湿度显示*/
         snprintf(DisplayDataBuffer,sizeof(DisplayDataBuffer),"T :%d",dht11_temp);
         OLED_DisplayString(40,24,16,DisplayDataBuffer);
         snprintf(DisplayDataBuffer,sizeof(DisplayDataBuffer),"RH:%d%%",dht11_humi);
         OLED_DisplayString(40,40,16,DisplayDataBuffer);
         OLED_Refresh_GRAM(); //刷新显存
 }
 ​
 ​
 /*
 函数功能:  烟雾传感器显示页面
 */
 void DisplayPage1(void)
 {
         u8 i;
     OLED_Clear_GRAM();
         /*1. 最上方界面提示*/
         for(i=0;i<6;i++)
         {
             OLED_DisplayData(16+i*16,0,16,16,ChineseFont[i+13]);    
         }
         
         /*2. 烟雾浓度显示*/
         snprintf(DisplayDataBuffer,sizeof(DisplayDataBuffer),"%d%%",MQ_2);
         OLED_DisplayString(40,24,16,DisplayDataBuffer);
         OLED_Refresh_GRAM(); //刷新显存
 }

3.2 sim800c.c

 #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;
 }
 ​
 /*
 函数功能: 采用HTTP协议方式向OneNet服务器上报数据
 函数参数:
                 char *data_point:数据点的名称
                 u32 data :上传的数据
 */
 char OneNet_HTTP_CMD[1024];
 char OneNet_HTTP_BUFF[300];
 #define ONENET_DEVICE_ID "529199894"
 #define ONENET_API_KEY "GfYgLKD4UxsjgJqkXhEoYLhL6fE="
 ​
 void OneNet_HTTP_DataUpdate(char *data_point,u32 data)
 {
         //拼接数据
       snprintf(OneNet_HTTP_BUFF,sizeof(OneNet_HTTP_BUFF),
             "{"datastreams":[{"id":"%s","datapoints":[{"value":%d}]}]}",data_point,data);
 ​
         //拼接数据
         snprintf(OneNet_HTTP_CMD,sizeof(OneNet_HTTP_CMD),
             "POST /devices/%s/datapoints HTTP/1.1\r\n" \
             "api-key:%s\r\n" \
             "Host:api.heclouds.com\r\n" \
             "Connection:close\r\n" \
             "Content-Length:%d\r\n" \
             "\r\n" \
             "%s",
         ONENET_DEVICE_ID,ONENET_API_KEY,strlen(OneNet_HTTP_BUFF),OneNet_HTTP_BUFF
         );
         printf("OneNet_HTTP_CMD=%s\r\n",OneNet_HTTP_CMD);
         
         printf("连接服务器的状态:%d\r\n",SIM800C_Connect_TCP_Server("183.230.40.33","80"));
         DelayMs(500);
         printf("数据发送的状态:%d\r\n",SIIM800C_TCP_SendData((u8*)OneNet_HTTP_CMD,strlen(OneNet_HTTP_CMD)));
 }
 ​
 /*
 函数功能: 采用HTTP协议方式向OneNet服务器上报GPS经纬度信息
 函数参数:
                 char *data_point:数据点的名称
                 double Longitude,double latitude:上传的经纬度数据
 */
 void OneNet_HTTP_GPS_DataUpdate(char *data_point,double Longitude,double latitude)
 {
         //拼接数据
       snprintf(OneNet_HTTP_BUFF,sizeof(OneNet_HTTP_BUFF),
             "{"datastreams":[{"id":"%s","datapoints":[{"value":{"lon":%lf,"lat":%lf}}]}]}",
            data_point,Longitude,latitude);
 ​
         //拼接数据
         snprintf(OneNet_HTTP_CMD,sizeof(OneNet_HTTP_CMD),
             "POST /devices/%s/datapoints HTTP/1.1\r\n" \
             "api-key:%s\r\n" \
             "Host:api.heclouds.com\r\n" \
             "Connection:close\r\n" \
             "Content-Length:%d\r\n" \
             "\r\n" \
             "%s",
         ONENET_DEVICE_ID,ONENET_API_KEY,strlen(OneNet_HTTP_BUFF),OneNet_HTTP_BUFF
         );
         printf("GPS_OneNet_HTTP_CMD=%s\r\n",OneNet_HTTP_CMD);
         
         printf("连接服务器的状态:%d\r\n",SIM800C_Connect_TCP_Server("183.230.40.33","80"));
         DelayMs(500);
         printf("数据发送的状态:%d\r\n",SIIM800C_TCP_SendData((u8*)OneNet_HTTP_CMD,strlen(OneNet_HTTP_CMD)));
 }

3.3 sim800c.h

 #ifndef _GSM_H
 #define _GSM_H
 #include "stm32f10x.h"
 #include "usart.h"
 #include "delay.h"
 ​
 u8 SIM800C_SendCmd(char *cmd,char *check_data);
 u8 SIM800C_InitCheck(void);
 u8 SIM800C_SetNoteTextMode(void);
 u8 SIM800C_SendNote(u8 *num,u8 *text,u16 len);
 void SIM800C_NtpUpdate(void);
 u8 SIM800C_GPRS_Init(void);
 u8 SIM800C_Connect_TCP_Server(char *ipaddr,char *port);
 u8 SIIM800C_TCP_SendData(u8 *data,u32 len);
 ​
 void OneNet_HTTP_GPS_DataUpdate(char *data_point,double Longitude,double latitude);
 void OneNet_HTTP_DataUpdate(char *data_point,u32 data);
 #endif

四、创建应用

发布的链接: OneNET-中国移动物联网开放平台

img

img

img