写点什么

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

作者:DS小龙哥
  • 2022 年 8 月 04 日
  • 本文字数:7305 字

    阅读完需:约 24 分钟

一、环境介绍

MCU: STM32F103C8T6


GSM 模块: SIM800C


开发软件: Keil5


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


OneNET 是由中国移动打造的 PaaS 物联网开放平台。平台能够帮助开发者轻松实现设备接入与设备连接,快速完成产品开发部署,为智能硬件、智能家居产品提供完善的物联网解决方案。


SIM800C 是一款四频 GSM/GPRS 模块,支持高达 85.6kbps 的 GPRS 数据传输。它具有强大的扩展能力和丰富的接口,包括 UART、USB2.0、GPIO 等,内部集成了完善的 AT 指令,单片机操作非常方便。


这篇文章利用 STM32+SIM800C 连接 OneNet 平台,将温度、湿度、烟雾浓度上传到 OneNet 服务器进行可视化显示。本地也将采集的 DHT11 温度、湿度数据、MQ-2 烟雾传感器数据实时在 OLED 显示屏上、当烟雾浓度超过阀值时,可以通过 SIM800C 向指定手机号码发送短信进行提示。

二、硬件与需求

一块 STM32F103C8T6 最小系统板。




一块 OLED 显示屏



一个 DHT11 温湿度传感器



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



一个 SIM800C 模块



软件要求

采集 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.3VGND---GNDDAT---PA5
MQ-2接线说明:VCC---3.3VGND---GNDAO----PB0
使用IIC接口的OLED显示屏接线说明:GND---GNDVCC---3.3VSDA---PB7SCL---PB6
使用SPI接口的OLED显示屏接线说明:GND---GNDVCC---3.3VD0-----PB5D1-----PB6RES----PB7DC-----PB8CS-----PB9
SIM800C接线说明:GND----GNDPA2----SIM800C_RXDPA3----SIM800C_TXD

CH340模块接线说明:GND----GNDRX-----PA9
GPS接线说明: (波特率需要根据GPS模块实际情况进行修改)GND----GNDVCC---3.3VPB11----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
复制代码


四、创建应用

发布的链接: https://open.iot.10086.cn/iotbox/appsquare/appview?openid=6b5f9941b4d0464671fa1bb6cd3511dc





发布于: 4 小时前阅读数: 3
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
STM32+SIM800C采用MQTT协议登录OneNet上传温湿度、MQ2烟雾浓度、GPS数据_8月月更_DS小龙哥_InfoQ写作社区