链接
https://detail.tmall.com/item.htm?_u=d1qf7bf5f35c&id=592705445141&spm=a1z09.2.0.0.d67e2e8d7TgPZ7
$GPRMC,055430.00,A,2256.25353,N,11343.15605,E,2.440,177.00,080119,,,A*69 055430.00, <1> UTC 时间,hhmmss(时分秒)格式 A, <2> 定位状态,A=有效定位,V=无效定位) 2256.25353, <3>纬度ddmm.mmmm(度分)格式(前面的0也将被传输 22°+56.25353 N, <4> 纬度半球N(北半球)或S(南半球) 11343.15605, <5>经度dddmm.mmmm(度分)格式(前面的0也将被传输)<6> 经度半球E(东经)或W(西经) E, <6> 经度半球E(东经)或W(西经) 2.440, <7>地面速率(000.0~999.9节,前面的0也将被传输)*1.852 = KM 177.00, <8>地面航向(000.0~359.9度,以真北为参考基准,前面的0也将被传输) 080119, <9> UTC 日期,ddmmyy(日月年)格式 , <10>磁偏角(000.0~180.0度,前面的0也将被传输) , <11> 磁偏角方向,E(东)或W(西) A*69 <12>模式指示(仅NMEA01833.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效) dd+(mm.mmmm/60)
GPS的数据格式是DDMM.MMMMMM
获取到的GPS帧数据比如是:$GNRMC,112317.000,A,3438.1633,N,11224.4992,E,0.19,186.95,240916,,,A*7D
说明
经度112°24.4992′
纬度34°38.1633′
OneNet支持的GPS数据经测试是DD.DDDDD,因此需要转换
经度为 112+24.4992/60 = 112.40832
纬度为 34+38.1633/60 = 34.636055
上传到GPS的数据流为
{"datastreams":[{"id":"location","datapoints":[{"value":{"lon":112.40832,"lat":34.636055}}]}]}
OneNet的GPS坐标是经过百度地图纠偏过的,所以这部分转换交给平台,直接上传上面的数据即可
用Arduino测试下转换计算过程:
//char lon_str[] = "10845.55422"; //char lat_str[] = "3402.15704"; //String lon_str = "10845.55422"; //String lat_str = "3402.15704"; // double 转化 string char* dtostr(char *str, double d) { sprintf(str, "%f", d); return str; } // GPS数据 mmmm格式 抓换位 double longitudeToOnenetFormat(String lons) { double lon_temp = 0; long lon_Onenet = 0; int dd_int = 0; long mm_int = 0; double lon_Onenet_double = 0; //lon_temp = atof(lon_str); char[] char lon_str[] = "10845.55422"; lon_temp = (lons).toFloat(); lon_Onenet =lon_temp*100000; //转换为整数 dd_int = lon_Onenet/10000000; //取出dd mm_int = lon_Onenet%10000000; //取出MM部分 lon_Onenet_double = dd_int + (double)mm_int/60/100000;//换算为Onenet格式 return lon_Onenet_double; } double latitudeToOnenetFormat(String lat_s) { double lat_temp = 0; long lat_Onenet = 0; int dd_int = 0; long mm_int = 0; double lat_Onenet_double = 0; //lat_temp = atof(lat_str); ///char lat_str[] = "3402.15704"; lat_temp = (lat_s).toFloat(); lat_Onenet =lat_temp*100000; //转换为整数 dd_int = lat_Onenet/10000000; //取出dd mm_int = lat_Onenet%10000000; //取出MM部分 lat_Onenet_double = dd_int + (double)mm_int/60/100000;//换算为Onenet格式 return lat_Onenet_double; } void setup() { // put your setup code here, to run once: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } String lon_str = "10845.55422"; String lat_str = "3402.15704"; double lond=longitudeToOnenetFormat(lon_str); double latd=latitudeToOnenetFormat(lat_str); // char lonc[25] ; // char latc[25] ; // // dtostr(lonc,lons); // dtostr(latc,lats); String lons= String(lond,6); String lats= String(latd,6); Serial.print(lats);Serial.print(" "); Serial.println(lons); } void loop(){ }
在地图中选择对应设备中名为“location”的数据流即可。
测试样例1 纯净版本
arduino stm32采集 esp8266上报
esp8266接口
SoftwareSerial Serial_Gps_arduino(4, 5); // SoftwareSerial(rx , tx) SoftwareSerial Serial_esp_arduino(6, 7); // SoftwareSerial(rx , tx)
stm32接口
Serial1 电脑串口 STM32 PA9 TX-> USB-ttl Rx STM32 PA10 RX-> USB-ttl Tx Serial2 GPS STM32 PA2 TX -> GPS Rx STM32 PA3 RX -> GPS Tx Serial3 esp8266 STM32 PB10 TX -> ESP Rx STM32 PB11 RX -> ESP Tx
代码
发送端
#include <SoftwareSerial.h> SoftwareSerial Serial_Gps_arduino(4, 5); // SoftwareSerial(rx , tx) SoftwareSerial Serial_esp_arduino(6, 7); // SoftwareSerial(rx , tx) #define Serial_Gps Serial_Gps_arduino #define Serial_esp Serial_esp_arduino //#define Serial_Gps Serial2 //#define Serial_esp Serial3 #include "API_Gps.h" #define GNRMC_TERM "$GNRMC," //定义要解析的指令,因为这条指令包含定位和时间信息 char nmeaSentence[68]; String latitude_msg; //纬度 String longitude_msg; //经度 String lndSpeed; //速度 String gpsTime; //UTC时间,本初子午线经度0度的时间,和北京时间差8小时 String beiJingTime; //北京时间 String latitude_old; //纬度 String longitude_old; //经度 String lndSpeed_old; //速度 String gpsTime_old; //UTC时间,本初子午线经度0度的时间,和北京时间差8小时 String beiJingTime_old; //北京时间 void Get_Gps(){ // For one second we parse GPS data and report some key values for (unsigned long start = millis(); millis() - start < 3000;) //一秒钟内不停扫描GPS信息 { while (Serial_Gps.available()) //串口获取到数据开始解析 { char c = Serial_Gps.read(); //读取一个字节获取的数据 switch(c) //判断该字节的值 { case '$': //若是$,则说明是一帧数据的开始 Serial_Gps.readBytesUntil('*', nmeaSentence, 67); //读取接下来的数据,存放在nmeaSentence字符数组中,最大存放67个字节 //Serial_Gps.println(nmeaSentence); latitude_msg = parseGNRMcLat(nmeaSentence); //获取纬度值 longitude_msg = parseGNRMcLon(nmeaSentence);//获取经度值 lndSpeed = parseGNRMcSpeed(nmeaSentence);//获取速度值 gpsTime = parseGNRMcTime(nmeaSentence);//获取GPS时间 if(latitude_msg > "") //当不是空时候打印输出 { //Serial.println("------------------------------------"); //Serial.println("latitude_msg: " + latitude_msg); latitude_old=latitude_msg; } if(longitude_msg > "") //当不是空时候打印输出 { //Serial.println("longitude_msg: " + longitude_msg); longitude_old=longitude_msg; } if(lndSpeed > "") //当不是空时候打印输出 { //Serial.println("Speed (knots): " + lndSpeed); lndSpeed_old=lndSpeed; } if(gpsTime > "") //当不是空时候打印输出 { //Serial.println("gpsTime: " + gpsTime); beiJingTime = getBeiJingTime(gpsTime); //获取北京时间 //Serial.println("beiJingTime: " + beiJingTime); beiJingTime_old=beiJingTime; } }//switch(c) }// while }//for } void setup() //初始化内容 { Serial.begin(9600); //pinMode(pin_light, INPUT); Serial_esp.begin(9600); //定义波特率9600, Serial_Gps.begin(9600); //定义波特率9600, Serial.println("开始运行"); latitude_msg="0"; //纬度 longitude_msg="0"; //经度 lndSpeed="0"; //速度 gpsTime="0"; //UTC时间,本初子午线经度0度的时间,和北京时间差8小时 beiJingTime="0"; //北京时间 } char lonc[25] ; char latc[25] ; void loop() //主循环 { Get_Gps(); double lond=longitudeToOnenetFormat(longitude_old); double latd=latitudeToOnenetFormat(latitude_old); String lons= String(lond,6); String lats= String(latd,6); //Serial.print(lats); Serial.print(" "); Serial.println(lons); String showmsg=String() +String("纬度")+"-" +String(lats)+"-" +String("经度")+"-" +String(lons)+"-" +String("速度")+"-" +String(lndSpeed_old)+"-" +String("北京时间戳秒")+"-" +String(beiJingTime_old)+"-" ; Serial.println(showmsg); String msg=String() +String(lats)+"-" +String(lons)+"-" +String(lndSpeed_old)+"-" +String(beiJingTime_old)+"-" ; Serial_esp.println(msg); delay(1000); }//loop()
API_Gps.h
// GPS数据 longitude mmmm格式 转换成onenet格式 double longitudeToOnenetFormat(String lons) { if (lons==""){return 0;} double lon_temp = 0; long lon_Onenet = 0; int dd_int = 0; long mm_int = 0; double lon_Onenet_double = 0; //lon_temp = atof(lon_str); char[] char lon_str[] = "10845.55422"; lon_temp = (lons).toFloat(); lon_Onenet =lon_temp*100000; //转换为整数 dd_int = lon_Onenet/10000000; //取出dd mm_int = lon_Onenet%10000000; //取出MM部分 lon_Onenet_double = dd_int + (double)mm_int/60/100000;//换算为Onenet格式 return lon_Onenet_double; } // GPS数据 latitude mmmm格式 转换成onenet格式 double latitudeToOnenetFormat(String lat_s) { if(lat_s==""){return 0;} double lat_temp = 0; long lat_Onenet = 0; int dd_int = 0; long mm_int = 0; double lat_Onenet_double = 0; //lat_temp = atof(lat_str); ///char lat_str[] = "3402.15704"; lat_temp = (lat_s).toFloat(); lat_Onenet =lat_temp*100000; //转换为整数 dd_int = lat_Onenet/10000000; //取出dd mm_int = lat_Onenet%10000000; //取出MM部分 lat_Onenet_double = dd_int + (double)mm_int/60/100000;//换算为Onenet格式 return lat_Onenet_double; } String getBeiJingTime(String s) { int hour = s.substring(0,2).toInt(); int minute = s.substring(2,4).toInt(); int second = s.substring(4,6).toInt(); hour += 8; if(hour > 24) hour -= 24; s = String(hour) + String(minute) + String(second); return s; } //Parse GNRMC NMEA sentence data from String //String must be GNRMC or no data will be parsed //Return Latitude String parseGNRMcLat(String s) { int pLoc = 0; //paramater location pointer int lEndLoc = 0; //lat parameter end location int dEndLoc = 0; //direction parameter end location String lat; /*make sure that we are parsing the GNRMC string. Found that setting s.substring(0,5) == "GNRMC" caused a FALSE. There seemed to be a 0x0D and 0x00 character at the end. */ if(s.substring(0,4) == "GNRM") { //Serial.println(s); for(int i = 0; i < 5; i++) { if(i < 3) { pLoc = s.indexOf(',', pLoc+1); /*Serial.print("i < 3, pLoc: "); Serial.print(pLoc); Serial.print(", "); Serial.println(i);*/ } if(i == 3) { lEndLoc = s.indexOf(',', pLoc+1); lat = s.substring(pLoc+1, lEndLoc); /*Serial.print("i = 3, pLoc: "); Serial.println(pLoc); Serial.print("lEndLoc: "); Serial.println(lEndLoc);*/ } else { dEndLoc = s.indexOf(',', lEndLoc+1); // lat = lat + " " + s.substring(lEndLoc+1, dEndLoc); /*Serial.print("i = 4, lEndLoc: "); Serial.println(lEndLoc); Serial.print("dEndLoc: "); Serial.println(dEndLoc);*/ } } return lat; } //} //} } //Parse GNRMC NMEA sentence data from String //String must be GNRMC or no data will be parsed //Return Longitude String parseGNRMcLon(String s) { int pLoc = 0; //paramater location pointer int lEndLoc = 0; //lat parameter end location int dEndLoc = 0; //direction parameter end location String lon; /*make sure that we are parsing the GNRMC string. Found that setting s.substring(0,5) == "GNRMC" caused a FALSE. There seemed to be a 0x0D and 0x00 character at the end. */ if(s.substring(0,4) == "GNRM") { //Serial.println(s); for(int i = 0; i < 7; i++) { if(i < 5) { pLoc = s.indexOf(',', pLoc+1); /*Serial.print("i < 3, pLoc: "); Serial.print(pLoc); Serial.print(", "); Serial.println(i);*/ } if(i == 5) { lEndLoc = s.indexOf(',', pLoc+1); lon = s.substring(pLoc+1, lEndLoc); /*Serial.print("i = 3, pLoc: "); Serial.println(pLoc); Serial.print("lEndLoc: "); Serial.println(lEndLoc);*/ } else { dEndLoc = s.indexOf(',', lEndLoc+1); // lon = lon + " " + s.substring(lEndLoc+1, dEndLoc); /*Serial.print("i = 4, lEndLoc: "); Serial.println(lEndLoc); Serial.print("dEndLoc: "); Serial.println(dEndLoc);*/ } } return lon; } } //Parse GNRMC NMEA sentence data from String //String must be GNRMC or no data will be parsed //Return Longitude String parseGNRMcSpeed(String s) { int pLoc = 0; //paramater location pointer int lEndLoc = 0; //lat parameter end location int dEndLoc = 0; //direction parameter end location String lndSpeed; /*make sure that we are parsing the GNRMC string. Found that setting s.substring(0,5) == "GNRMC" caused a FALSE. There seemed to be a 0x0D and 0x00 character at the end. */ if(s.substring(0,4) == "GNRM") { //Serial.println(s); for(int i = 0; i < 8; i++) { if(i < 7) { pLoc = s.indexOf(',', pLoc+1); /*Serial.print("i < 8, pLoc: "); Serial.print(pLoc); Serial.print(", "); Serial.println(i);*/ } else { lEndLoc = s.indexOf(',', pLoc+1); lndSpeed = s.substring(pLoc+1, lEndLoc); /*Serial.print("i = 8, pLoc: "); Serial.println(pLoc); Serial.print("lEndLoc: "); Serial.println(lEndLoc);*/ } } return lndSpeed; } } //Parse GNRMC NMEA sentence data from String //String must be GNRMC or no data will be parsed //Return Longitude String parseGNRMcTime(String s) { int pLoc = 0; //paramater location pointer int lEndLoc = 0; //lat parameter end location int dEndLoc = 0; //direction parameter end location String gpsTime; /*make sure that we are parsing the GNRMC string. Found that setting s.substring(0,5) == "GNRMC" caused a FALSE. There seemed to be a 0x0D and 0x00 character at the end. */ if(s.substring(0,4) == "GNRM") { //Serial.println(s); for(int i = 0; i < 2; i++) { if(i < 1) { pLoc = s.indexOf(',', pLoc+1); /*Serial.print("i < 8, pLoc: "); Serial.print(pLoc); Serial.print(", "); Serial.println(i);*/ } else { lEndLoc = s.indexOf(',', pLoc+1); gpsTime = s.substring(pLoc+1, lEndLoc); /*Serial.print("i = 8, pLoc: "); Serial.println(pLoc); Serial.print("lEndLoc: "); Serial.println(lEndLoc);*/ } } return gpsTime; } } // Turn char[] array into String object String charToString(char *c) { String val = ""; for(int i = 0; i <= sizeof(c); i++) { val = val + c; } return val; }
ESP8266接收上报端
#include <ESP8266WiFi.h> #include <PubSubClient.h> #include <ArduinoJson.h> #include <Ticker.h> #include <SoftwareSerial.h> //实例化软串口 SoftwareSerial mySerial(D1, D2); // RX, TX //分割结果 #define sleng 10 //数组大小 String split_result[sleng];//手动动态调整数组大小,保证数组可以满足容量 #define WIFI_DEBUG 0 //1:使用一键配网,其它值则使用默认无线账号密码 #define ONENET_DISCONNECTED 1 //已经断开 #define ONENET_CONNECTED 2 //已经连接上 #define ONENET_RECONNECT 3 //重连成功 #define VER "ESP8266_MQTT_V1.0" //版本号 const char* ssid = "yaoyao";//wifi账号 const char* password = "love123456";//wifi密码 /*OneNet*/ PubSubClient mqttClient; const char* mqttServer = "183.230.40.39";//mqtt服务器 const uint16_t mqttPort = 6002; //端口号 #define onenet_productId "589421" //产品ID #define onenet_deviceId "1065407752" //设备ID #define onenet_apiKey "mvHyjtrjuXd=6GWhWMtQTB0nNDo=" //产品API_KEY int state; Ticker delayTimer; WiFiClient espClient; /*字符串分割 输入参数 String zifuchuan, 输入字符串 String fengefu, 分隔符号-可以是多个 String result[] 输出结果 */ void Split(String zifuchuan,String fengefu,String result[]) { int weizhi; //找查的位置 String temps;//临时字符串 int i=0; do { weizhi = zifuchuan.indexOf(fengefu);//找到位置 if(weizhi != -1)//如果位置不为空 { temps=zifuchuan.substring(0,weizhi);//打印取第一个字符 zifuchuan = zifuchuan.substring(weizhi+fengefu.length(), zifuchuan.length()); //分隔后只取后面一段内容 以方便后面找查 } else { //上面实在找不到了就把最后的 一个分割值赋值出来以免遗漏 if(zifuchuan.length() > 0) temps=zifuchuan; } result[i++]=temps; //Serial.println(result[i-1]);//在这里执行分割出来的字符下面不然又清空了 temps=""; } while(weizhi >=0); } /* 延时N秒 */ void delayNs(uint8_t m){ for(uint8_t index = 0;index<m;index ++){ delay(1000); ESP.wdtFeed(); } } /* 延时重启 */ void delayRestart(float t) { Serial.print("Restart after "); Serial.print(t); Serial.println("s"); delayTimer.attach(t, []() { Serial.println("\r\nRestart now!"); ESP.restart(); }); } /* 自动连接 */ bool autoConfig() { WiFi.begin(); for (int i = 0; i < 20; i++) { if (WiFi.status() == WL_CONNECTED) { Serial.println("AutoConfig Success"); Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str()); Serial.printf("PSW:%s\r\n", WiFi.psk().c_str()); WiFi.printDiag(Serial); return true; } else { Serial.print("AutoConfig Waiting......"); Serial.println(WiFi.status()); delay(1000); } } Serial.println("AutoConfig Faild!" ); return false; } /* 一键配网 */ void smartConfig() { WiFi.mode(WIFI_STA); Serial.println("\r\nWait for Smartconfig"); WiFi.beginSmartConfig(); while (1) { Serial.print("."); digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); if (WiFi.smartConfigDone()) { Serial.println("SmartConfig Success"); Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str()); Serial.printf("PSW:%s\r\n", WiFi.psk().c_str()); WiFi.setAutoConnect(true); // 设置自动连接 break; } delay(1000); // 这个地方一定要加延时,否则极易崩溃重启 } } /* 连接OneNet */ int connectToOneNetMqtt(){ int cnt = 0; while(!mqttClient.connected()){ ESP.wdtFeed(); cnt++; Serial.println("Connect to OneNet MQTT..."); if (mqttClient.connect(onenet_deviceId,onenet_productId,onenet_apiKey)) { Serial.println("connect success!"); return ONENET_RECONNECT; } else { Serial.print("connect fail!"); Serial.println(" try again in 5 seconds"); delay(5000); } if(cnt >=10){ //只做10次连接到OneNet,连接不上重启8266 cnt = 0; delayRestart(1); } } return ONENET_CONNECTED; } /* 云端下发 */ void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); if ((char)payload[0] == '1') { digitalWrite(LED_BUILTIN, LOW); } else { digitalWrite(LED_BUILTIN, HIGH); } } /* 发布一个传感器信息 String sensorname 传感器名字 String data 数据 int sendlen=200; 数据大小 */ void pubMQTTmsg_one_name_value(String sensorname,String data){ long lastMsg = 0; int sendlen=200;//28 //数组大小 char msg[sendlen+22]; //数组大小 char tmp[sendlen]; char d[3]; //snprintf(tmp,sizeof(tmp),String("")+"{\""+sensorname+"\":%d}",data); String sendmsg=String("")+"{\""+sensorname+"\":"+data+"}"; //String sendmsg="{\"mq2\":1234,\"mq3\":345}"; sendmsg.toCharArray(tmp, sendlen); Serial.println(tmp); uint16_t streamLen= strlen(tmp); d[0]='\x03'; d[1] = (streamLen >> 8); d[2] = (streamLen & 0xFF); snprintf(msg,sizeof(msg),"%c%c%c%s",d[0],d[1],d[2],tmp); mqttClient.publish("$dp", (uint8_t*)msg,streamLen+3,false); } /* 发布多个传感器信息 String sendmsg 打包数据 {"senseor1":1213,"senseor2":313.3,"senseor3":543.09,"senseor4":645.0} 注意 ” 转义字符串 \“ */ void pubMQTTmsg_more_name_value(String sendmsg_in){ long lastMsg = 0; int sendlen=800;//28 //数组大小 char msg[sendlen+22]; //数组大小 char tmp[sendlen]; char d[3]; //snprintf(tmp,sizeof(tmp),String("")+"{\""+sensorname+"\":%d}",data); //String sendmsg=String("")+"{\""+sensorname+"\":"+data+"}"; String sendmsg=sendmsg_in; sendmsg.toCharArray(tmp, sendlen); Serial.println(tmp); uint16_t streamLen= strlen(tmp); d[0]='\x03'; d[1] = (streamLen >> 8); d[2] = (streamLen & 0xFF); snprintf(msg,sizeof(msg),"%c%c%c%s",d[0],d[1],d[2],tmp); mqttClient.publish("$dp", (uint8_t*)msg,streamLen+3,false); } /* 初始化系统 */ void initSystem(){ int cnt = 0; Serial.begin (9600); Serial.println("\r\n\r\nStart ESP8266 MQTT"); Serial.print("Firmware Version:"); Serial.println(VER); Serial.print("SDK Version:"); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); Serial.println(ESP.getSdkVersion()); ESP.wdtEnable(5000); if(WIFI_DEBUG==1)//开启一键配网模式 { if (!autoConfig()) { Serial.println("Start smartConfig"); smartConfig(); } } else { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); cnt++; Serial.print("."); if(cnt>=40){ cnt = 0; //重启系统 delayRestart(1); } } } Serial.print("WIFI Connect \r\n"); } /* 初始化ONENET通信 */ void initOneNetMqtt(){ mqttClient.setServer(mqttServer,mqttPort); mqttClient.setClient(espClient); mqttClient.setCallback(callback); } /* 初始化 */ void setup() { initSystem(); initOneNetMqtt(); Serial.begin(9600); while (!Serial) { } Serial.println("Goodnight moon!"); mySerial.begin(115200); } /* 主函数 */ void loop() { ESP.wdtFeed(); state = connectToOneNetMqtt(); //Serial.println(WiFi.status()); //接收串口消息 if (mySerial.available()){ String split_input =mySerial.readStringUntil(';'); //Serial.println(split_input); //分割解析 Split(split_input,"-",split_result);//分割调用 Serial.println("----------------"); //打印消息 检查是否为空 for(int i=0;i<sleng;i++) { if(split_result[i]!="") { Serial.println(String(i)+"-"+split_result[i]); } else { split_result[i]="0"; } } //发送onenet ESP.wdtFeed(); state = connectToOneNetMqtt(); //Serial.println(WiFi.status()); if(state == ONENET_RECONNECT){ mqttClient.loop(); } else if(state == ONENET_CONNECTED) { //3402.16056-10845.55338-0.10-11228-4.89-18.50- String msg=String("")+"{" +"\"location\":"+"{\"lat\":"+split_result[0]+",\"lon\":"+split_result[1]+"}"+"," +"\"速度\":"+String(split_result[2]) +"}"; pubMQTTmsg_more_name_value(msg); mqttClient.loop(); } //delay(2000); } }
测试样例2 采集 紫外线 A0 + 采集DS18B20温度 + gps
ESP8266上传代码
注意软串口波特率吧 115200 适配loral
#include <ESP8266WiFi.h> #include <PubSubClient.h> #include <ArduinoJson.h> #include <Ticker.h> #include <SoftwareSerial.h> //实例化软串口 SoftwareSerial mySerial(D1, D2); // RX, TX //分割结果 #define sleng 10 //数组大小 String split_result[sleng];//手动动态调整数组大小,保证数组可以满足容量 #define WIFI_DEBUG 0 //1:使用一键配网,其它值则使用默认无线账号密码 #define ONENET_DISCONNECTED 1 //已经断开 #define ONENET_CONNECTED 2 //已经连接上 #define ONENET_RECONNECT 3 //重连成功 #define VER "ESP8266_MQTT_V1.0" //版本号 const char* ssid = "yaoyao";//wifi账号 const char* password = "love123456";//wifi密码 /*OneNet*/ PubSubClient mqttClient; const char* mqttServer = "183.230.40.39";//mqtt服务器 const uint16_t mqttPort = 6002; //端口号 #define onenet_productId "207282" //产品ID #define onenet_deviceId "515439794" //设备ID #define onenet_apiKey "ZcxLlq=Pd4t6CgaFKcB=zQXzDt8=" //产品API_KEY int state; Ticker delayTimer; WiFiClient espClient; /*字符串分割 输入参数 String zifuchuan, 输入字符串 String fengefu, 分隔符号-可以是多个 String result[] 输出结果 */ void Split(String zifuchuan,String fengefu,String result[]) { int weizhi; //找查的位置 String temps;//临时字符串 int i=0; do { weizhi = zifuchuan.indexOf(fengefu);//找到位置 if(weizhi != -1)//如果位置不为空 { temps=zifuchuan.substring(0,weizhi);//打印取第一个字符 zifuchuan = zifuchuan.substring(weizhi+fengefu.length(), zifuchuan.length()); //分隔后只取后面一段内容 以方便后面找查 } else { //上面实在找不到了就把最后的 一个分割值赋值出来以免遗漏 if(zifuchuan.length() > 0) temps=zifuchuan; } result[i++]=temps; //Serial.println(result[i-1]);//在这里执行分割出来的字符下面不然又清空了 temps=""; } while(weizhi >=0); } /* 延时N秒 */ void delayNs(uint8_t m){ for(uint8_t index = 0;index<m;index ++){ delay(1000); ESP.wdtFeed(); } } /* 延时重启 */ void delayRestart(float t) { Serial.print("Restart after "); Serial.print(t); Serial.println("s"); delayTimer.attach(t, []() { Serial.println("\r\nRestart now!"); ESP.restart(); }); } /* 自动连接 */ bool autoConfig() { WiFi.begin(); for (int i = 0; i < 20; i++) { if (WiFi.status() == WL_CONNECTED) { Serial.println("AutoConfig Success"); Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str()); Serial.printf("PSW:%s\r\n", WiFi.psk().c_str()); WiFi.printDiag(Serial); return true; } else { Serial.print("AutoConfig Waiting......"); Serial.println(WiFi.status()); delay(1000); } } Serial.println("AutoConfig Faild!" ); return false; } /* 一键配网 */ void smartConfig() { WiFi.mode(WIFI_STA); Serial.println("\r\nWait for Smartconfig"); WiFi.beginSmartConfig(); while (1) { Serial.print("."); digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); if (WiFi.smartConfigDone()) { Serial.println("SmartConfig Success"); Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str()); Serial.printf("PSW:%s\r\n", WiFi.psk().c_str()); WiFi.setAutoConnect(true); // 设置自动连接 break; } delay(1000); // 这个地方一定要加延时,否则极易崩溃重启 } } /* 连接OneNet */ int connectToOneNetMqtt(){ int cnt = 0; while(!mqttClient.connected()){ ESP.wdtFeed(); cnt++; Serial.println("Connect to OneNet MQTT..."); if (mqttClient.connect(onenet_deviceId,onenet_productId,onenet_apiKey)) { Serial.println("connect success!"); return ONENET_RECONNECT; } else { Serial.print("connect fail!"); Serial.println(" try again in 5 seconds"); delay(5000); } if(cnt >=10){ //只做10次连接到OneNet,连接不上重启8266 cnt = 0; delayRestart(1); } } return ONENET_CONNECTED; } /* 云端下发 */ void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); if ((char)payload[0] == '1') { digitalWrite(LED_BUILTIN, LOW); } else { digitalWrite(LED_BUILTIN, HIGH); } } /* 发布一个传感器信息 String sensorname 传感器名字 String data 数据 int sendlen=200; 数据大小 */ void pubMQTTmsg_one_name_value(String sensorname,String data){ long lastMsg = 0; int sendlen=200;//28 //数组大小 char msg[sendlen+22]; //数组大小 char tmp[sendlen]; char d[3]; //snprintf(tmp,sizeof(tmp),String("")+"{\""+sensorname+"\":%d}",data); String sendmsg=String("")+"{\""+sensorname+"\":"+data+"}"; //String sendmsg="{\"mq2\":1234,\"mq3\":345}"; sendmsg.toCharArray(tmp, sendlen); Serial.println(tmp); uint16_t streamLen= strlen(tmp); d[0]='\x03'; d[1] = (streamLen >> 8); d[2] = (streamLen & 0xFF); snprintf(msg,sizeof(msg),"%c%c%c%s",d[0],d[1],d[2],tmp); mqttClient.publish("$dp", (uint8_t*)msg,streamLen+3,false); } /* 发布多个传感器信息 String sendmsg 打包数据 {"senseor1":1213,"senseor2":313.3,"senseor3":543.09,"senseor4":645.0} 注意 ” 转义字符串 \“ */ void pubMQTTmsg_more_name_value(String sendmsg_in){ long lastMsg = 0; int sendlen=800;//28 //数组大小 char msg[sendlen+22]; //数组大小 char tmp[sendlen]; char d[3]; //snprintf(tmp,sizeof(tmp),String("")+"{\""+sensorname+"\":%d}",data); //String sendmsg=String("")+"{\""+sensorname+"\":"+data+"}"; String sendmsg=sendmsg_in; sendmsg.toCharArray(tmp, sendlen); Serial.println(tmp); uint16_t streamLen= strlen(tmp); d[0]='\x03'; d[1] = (streamLen >> 8); d[2] = (streamLen & 0xFF); snprintf(msg,sizeof(msg),"%c%c%c%s",d[0],d[1],d[2],tmp); mqttClient.publish("$dp", (uint8_t*)msg,streamLen+3,false); } /* 初始化系统 */ void initSystem(){ int cnt = 0; Serial.begin (9600); Serial.println("\r\n\r\nStart ESP8266 MQTT"); Serial.print("Firmware Version:"); Serial.println(VER); Serial.print("SDK Version:"); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); Serial.println(ESP.getSdkVersion()); ESP.wdtEnable(5000); if(WIFI_DEBUG==1)//开启一键配网模式 { if (!autoConfig()) { Serial.println("Start smartConfig"); smartConfig(); } } else { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); cnt++; Serial.print("."); if(cnt>=40){ cnt = 0; //重启系统 delayRestart(1); } } } Serial.print("WIFI Connect \r\n"); } /* 初始化ONENET通信 */ void initOneNetMqtt(){ mqttClient.setServer(mqttServer,mqttPort); mqttClient.setClient(espClient); mqttClient.setCallback(callback); } /* 初始化 */ void setup() { initSystem(); initOneNetMqtt(); Serial.begin(9600); while (!Serial) { } Serial.println("Goodnight moon!"); mySerial.begin(115200); } /* 主函数 */ void loop() { ESP.wdtFeed(); state = connectToOneNetMqtt(); //Serial.println(WiFi.status()); //接收串口消息 if (mySerial.available()){ String split_input =mySerial.readStringUntil(';'); //Serial.println(split_input); //分割解析 Split(split_input,"-",split_result);//分割调用 Serial.println("----------------"); //打印消息 检查是否为空 for(int i=0;i<sleng;i++) { if(split_result[i]!="") { Serial.println(String(i)+"-"+split_result[i]); } else { split_result[i]="0"; } } //发送onenet ESP.wdtFeed(); state = connectToOneNetMqtt(); //Serial.println(WiFi.status()); if(state == ONENET_RECONNECT){ mqttClient.loop(); } else if(state == ONENET_CONNECTED) { //3402.16056-10845.55338-0.10-11228-4.89-18.50- String msg=String("")+"{" +"\"location\":"+"{\"lat\":"+split_result[0]+",\"lon\":"+split_result[1]+"}"+"," +"\"速度\":"+String(split_result[2])+"," +"\"紫外线\":"+String(split_result[4])+"," +"\"温度\":"+String(split_result[5]) +"}"; pubMQTTmsg_more_name_value(msg); mqttClient.loop(); } //delay(2000); } }
arduino采集
{"location":{"lat":34.0215704,"lon":108.4555422},"速度":28,"紫外线":28,"温度":28} {"location":{"lat":34.0215704,"lon":108.4555422},"速度":29,"紫外线":29,"温度":29} {"location":{"lat":34.0215704,"lon":108.4555422},"速度":30,"紫外线":30,"温度":30} {"location":{"lat":34.0215704,"lon":108.4555422},"速度":31,"紫外线":31,"温度":31}
v1_send.ino
#define pin_light A0 #include <DS18B20.h> DS18B20 ds(8); #include <SoftwareSerial.h> SoftwareSerial Serial_Gps(4, 5); SoftwareSerial Serial_esp(6, 7); #define GNRMC_TERM "$GNRMC," //定义要解析的指令,因为这条指令包含定位和时间信息 char nmeaSentence[68]; String latitude_msg; //纬度 String longitude_msg; //经度 String lndSpeed; //速度 String gpsTime; //UTC时间,本初子午线经度0度的时间,和北京时间差8小时 String beiJingTime; //北京时间 String latitude_old; //纬度 String longitude_old; //经度 String lndSpeed_old; //速度 String gpsTime_old; //UTC时间,本初子午线经度0度的时间,和北京时间差8小时 String beiJingTime_old; //北京时间 #include "API_Gps.h" void Get_Gps(){ // For one second we parse GPS data and report some key values for (unsigned long start = millis(); millis() - start < 3000;) //一秒钟内不停扫描GPS信息 { while (Serial_Gps.available()) //串口获取到数据开始解析 { char c = Serial_Gps.read(); //读取一个字节获取的数据 switch(c) //判断该字节的值 { case '$': //若是$,则说明是一帧数据的开始 Serial_Gps.readBytesUntil('*', nmeaSentence, 67); //读取接下来的数据,存放在nmeaSentence字符数组中,最大存放67个字节 //Serial_Gps.println(nmeaSentence); latitude_msg = parseGNRMcLat(nmeaSentence); //获取纬度值 longitude_msg = parseGNRMcLon(nmeaSentence);//获取经度值 lndSpeed = parseGNRMcSpeed(nmeaSentence);//获取速度值 gpsTime = parseGNRMcTime(nmeaSentence);//获取GPS时间 if(latitude_msg > "") //当不是空时候打印输出 { //Serial.println("------------------------------------"); //Serial.println("latitude_msg: " + latitude_msg); latitude_old=latitude_msg; } if(longitude_msg > "") //当不是空时候打印输出 { //Serial.println("longitude_msg: " + longitude_msg); longitude_old=longitude_msg; } if(lndSpeed > "") //当不是空时候打印输出 { //Serial.println("Speed (knots): " + lndSpeed); lndSpeed_old=lndSpeed; } if(gpsTime > "") //当不是空时候打印输出 { //Serial.println("gpsTime: " + gpsTime); beiJingTime = getBeiJingTime(gpsTime); //获取北京时间 //Serial.println("beiJingTime: " + beiJingTime); beiJingTime_old=beiJingTime; } }//switch(c) }// while }//for } //char lon_str[] = "10845.55422"; //char lat_str[] = "3402.15704"; //String lon_str = "10845.55422"; //String lat_str = "3402.15704"; // double 转化 string char* dtostr(char *strc, double d) { sprintf(strc, "%f", d); return strc; } // GPS数据 mmmm格式 抓换位 double longitudeToOnenetFormat(String lons) { if (lons==""){return 0;} double lon_temp = 0; long lon_Onenet = 0; int dd_int = 0; long mm_int = 0; double lon_Onenet_double = 0; //lon_temp = atof(lon_str); char[] char lon_str[] = "10845.55422"; lon_temp = (lons).toFloat(); lon_Onenet =lon_temp*100000; //转换为整数 dd_int = lon_Onenet/10000000; //取出dd mm_int = lon_Onenet%10000000; //取出MM部分 lon_Onenet_double = dd_int + (double)mm_int/60/100000;//换算为Onenet格式 return lon_Onenet_double; } double latitudeToOnenetFormat(String lat_s) { if(lat_s==""){return 0;} double lat_temp = 0; long lat_Onenet = 0; int dd_int = 0; long mm_int = 0; double lat_Onenet_double = 0; //lat_temp = atof(lat_str); ///char lat_str[] = "3402.15704"; lat_temp = (lat_s).toFloat(); lat_Onenet =lat_temp*100000; //转换为整数 dd_int = lat_Onenet/10000000; //取出dd mm_int = lat_Onenet%10000000; //取出MM部分 lat_Onenet_double = dd_int + (double)mm_int/60/100000;//换算为Onenet格式 return lat_Onenet_double; } // 紫外线等级转换 // 0-11+ int LightDengji(int light_mv){ int dengji=0; //紫外线等级 if(light_mv<50){ dengji=0; } else if( light_mv>=50 && light_mv<227){ dengji=1; } else if( light_mv>=227 && light_mv<318){ dengji=2; } else if( light_mv>=318 && light_mv<408){ dengji=3; } else if( light_mv>=408 && light_mv<503){ dengji=4; } else if( light_mv>=503 && light_mv<606){ dengji=5; } else if( light_mv>=606 && light_mv<696){ dengji=6; } else if( light_mv>=696 && light_mv<795){ dengji=7; } else if( light_mv>=795 && light_mv<881){ dengji=8; } else if( light_mv>=881 && light_mv<976){ dengji=9; } else if( light_mv>=976 && light_mv<1079){ dengji=10; } else if( light_mv>=1079 && light_mv<1170){ dengji=11; } else if( light_mv>=1170 ){ dengji=12; } return dengji; } void setup() //初始化内容 { Serial.begin(9600); //pinMode(pin_light, INPUT); Serial_esp.begin(115200); //定义波特率9600, Serial_Gps.begin(9600); //定义波特率9600, Serial.println("开始运行"); latitude_msg="0"; //纬度 longitude_msg="0"; //经度 lndSpeed="0"; //速度 gpsTime="0"; //UTC时间,本初子午线经度0度的时间,和北京时间差8小时 beiJingTime="0"; //北京时间 } char lonc[25] ; char latc[25] ; void loop() //主循环 { Get_Gps(); int light_svalue=analogRead(pin_light); float light_value=light_svalue*5000/1023.0; float tem=float(ds.getTempC()); double lond=longitudeToOnenetFormat(longitude_old); double latd=latitudeToOnenetFormat(latitude_old); //dtostr(lonc,lons); //dtostr(latc,lats); String lons= String(lond,6); String lats= String(latd,6); //Serial.print(lats); Serial.print(" "); Serial.println(lons); String showmsg=String() +String("纬度")+"-" +String(lats)+"-" +String("经度")+"-" +String(lons)+"-" +String("速度")+"-" +String(lndSpeed_old)+"-" +String("北京时间戳秒")+"-" +String(beiJingTime_old)+"-" +String("紫外线mv")+"-" +String((light_value))+"-" +String("紫外线等级")+"-" +String(LightDengji(light_value))+"-" +String("温度")+"-" +String(ds.getTempC())+"-" ; Serial.println(showmsg); String msg=String() +String(lats)+"-" +String(lons)+"-" +String(lndSpeed_old)+"-" +String(beiJingTime_old)+"-" +String(LightDengji(light_value))+"-" +String(ds.getTempC())+"-" ; Serial_esp.println(msg); delay(1000); }//loop()
API_Gps.h
String getBeiJingTime(String s) { int hour = s.substring(0,2).toInt(); int minute = s.substring(2,4).toInt(); int second = s.substring(4,6).toInt(); hour += 8; if(hour > 24) hour -= 24; s = String(hour) + String(minute) + String(second); return s; } //Parse GNRMC NMEA sentence data from String //String must be GNRMC or no data will be parsed //Return Latitude String parseGNRMcLat(String s) { int pLoc = 0; //paramater location pointer int lEndLoc = 0; //lat parameter end location int dEndLoc = 0; //direction parameter end location String lat; /*make sure that we are parsing the GNRMC string. Found that setting s.substring(0,5) == "GNRMC" caused a FALSE. There seemed to be a 0x0D and 0x00 character at the end. */ if(s.substring(0,4) == "GNRM") { //Serial.println(s); for(int i = 0; i < 5; i++) { if(i < 3) { pLoc = s.indexOf(',', pLoc+1); /*Serial.print("i < 3, pLoc: "); Serial.print(pLoc); Serial.print(", "); Serial.println(i);*/ } if(i == 3) { lEndLoc = s.indexOf(',', pLoc+1); lat = s.substring(pLoc+1, lEndLoc); /*Serial.print("i = 3, pLoc: "); Serial.println(pLoc); Serial.print("lEndLoc: "); Serial.println(lEndLoc);*/ } else { dEndLoc = s.indexOf(',', lEndLoc+1); // lat = lat + " " + s.substring(lEndLoc+1, dEndLoc); /*Serial.print("i = 4, lEndLoc: "); Serial.println(lEndLoc); Serial.print("dEndLoc: "); Serial.println(dEndLoc);*/ } } return lat; } //} //} } //Parse GNRMC NMEA sentence data from String //String must be GNRMC or no data will be parsed //Return Longitude String parseGNRMcLon(String s) { int pLoc = 0; //paramater location pointer int lEndLoc = 0; //lat parameter end location int dEndLoc = 0; //direction parameter end location String lon; /*make sure that we are parsing the GNRMC string. Found that setting s.substring(0,5) == "GNRMC" caused a FALSE. There seemed to be a 0x0D and 0x00 character at the end. */ if(s.substring(0,4) == "GNRM") { //Serial.println(s); for(int i = 0; i < 7; i++) { if(i < 5) { pLoc = s.indexOf(',', pLoc+1); /*Serial.print("i < 3, pLoc: "); Serial.print(pLoc); Serial.print(", "); Serial.println(i);*/ } if(i == 5) { lEndLoc = s.indexOf(',', pLoc+1); lon = s.substring(pLoc+1, lEndLoc); /*Serial.print("i = 3, pLoc: "); Serial.println(pLoc); Serial.print("lEndLoc: "); Serial.println(lEndLoc);*/ } else { dEndLoc = s.indexOf(',', lEndLoc+1); // lon = lon + " " + s.substring(lEndLoc+1, dEndLoc); /*Serial.print("i = 4, lEndLoc: "); Serial.println(lEndLoc); Serial.print("dEndLoc: "); Serial.println(dEndLoc);*/ } } return lon; } } //Parse GNRMC NMEA sentence data from String //String must be GNRMC or no data will be parsed //Return Longitude String parseGNRMcSpeed(String s) { int pLoc = 0; //paramater location pointer int lEndLoc = 0; //lat parameter end location int dEndLoc = 0; //direction parameter end location String lndSpeed; /*make sure that we are parsing the GNRMC string. Found that setting s.substring(0,5) == "GNRMC" caused a FALSE. There seemed to be a 0x0D and 0x00 character at the end. */ if(s.substring(0,4) == "GNRM") { //Serial.println(s); for(int i = 0; i < 8; i++) { if(i < 7) { pLoc = s.indexOf(',', pLoc+1); /*Serial.print("i < 8, pLoc: "); Serial.print(pLoc); Serial.print(", "); Serial.println(i);*/ } else { lEndLoc = s.indexOf(',', pLoc+1); lndSpeed = s.substring(pLoc+1, lEndLoc); /*Serial.print("i = 8, pLoc: "); Serial.println(pLoc); Serial.print("lEndLoc: "); Serial.println(lEndLoc);*/ } } return lndSpeed; } } //Parse GNRMC NMEA sentence data from String //String must be GNRMC or no data will be parsed //Return Longitude String parseGNRMcTime(String s) { int pLoc = 0; //paramater location pointer int lEndLoc = 0; //lat parameter end location int dEndLoc = 0; //direction parameter end location String gpsTime; /*make sure that we are parsing the GNRMC string. Found that setting s.substring(0,5) == "GNRMC" caused a FALSE. There seemed to be a 0x0D and 0x00 character at the end. */ if(s.substring(0,4) == "GNRM") { //Serial.println(s); for(int i = 0; i < 2; i++) { if(i < 1) { pLoc = s.indexOf(',', pLoc+1); /*Serial.print("i < 8, pLoc: "); Serial.print(pLoc); Serial.print(", "); Serial.println(i);*/ } else { lEndLoc = s.indexOf(',', pLoc+1); gpsTime = s.substring(pLoc+1, lEndLoc); /*Serial.print("i = 8, pLoc: "); Serial.println(pLoc); Serial.print("lEndLoc: "); Serial.println(lEndLoc);*/ } } return gpsTime; } } // Turn char[] array into String object String charToString(char *c) { String val = ""; for(int i = 0; i <= sizeof(c); i++) { val = val + c; } return val; }