• 方案介紹
    • 前言
    • 一、芯片介紹
    • 二、材料準(zhǔn)備
    • 三、代碼編寫(xiě)
    • 四、實(shí)現(xiàn)效果
    • 五、 參考
  • 附件下載
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

【ESP32/ESP8266】GPS定位數(shù)據(jù)解析與超聲測(cè)距(ATGM336H+HC-SR04)

02/28 08:39
907
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

聯(lián)系方式.docx

共1個(gè)文件

前言

做拓展項(xiàng)目需要要用GPS定位數(shù)據(jù)以及超聲設(shè)計(jì),之前沒(méi)有用過(guò)ESP-12F這個(gè)開(kāi)發(fā)板去做過(guò),都是用到STM32板子,今天嘗試用Arduino環(huán)境進(jìn)行開(kāi)發(fā),并實(shí)現(xiàn)GPS經(jīng)緯度數(shù)據(jù)獲取以及超聲測(cè)距

一、芯片介紹

這款芯片的可用io口還是比較少的,只適合做小型的設(shè)備控制,不用看圖上有很多io口,其實(shí)他很多都不能用,否則就會(huì)導(dǎo)致啟動(dòng)錯(cuò)誤,我已經(jīng)踩過(guò)坑了

ESP-12F可用輸出引腳列表

GPIO編號(hào) 物理引腳 特殊限制 最大輸出電流 PWM支持 推薦用途
GPIO4 Pin 10 無(wú) 12mA ?? LED控制、傳感器驅(qū)動(dòng)
GPIO5 Pin 11 啟動(dòng)時(shí)需高電平 12mA ?? 繼電器、數(shù)字輸出
GPIO12 Pin 14 啟動(dòng)時(shí)需低電平 12mA ?? 按鍵輸入、低功耗設(shè)備
GPIO13 Pin 15 無(wú) 12mA ?? SPI MOSI、數(shù)據(jù)總線
GPIO14 Pin 16 啟動(dòng)時(shí)需高電平 12mA ?? SPI CLK、高速信號(hào)
GPIO15 Pin 17 必須啟動(dòng)時(shí)低電平 12mA ?? 接地設(shè)備控制

禁止使用的輸出引腳

GPIO編號(hào) 限制原因
GPIO0 啟動(dòng)模式選擇(需外部上拉)
GPIO2 內(nèi)部上拉,啟動(dòng)時(shí)需高電平
GPIO16 僅支持開(kāi)漏輸出

二、材料準(zhǔn)備

準(zhǔn)備這是四個(gè)材料就行了

ESP8266開(kāi)發(fā)板 ESP8266-Node
顯示屏-0.96寸 顯示屏-0.96寸

GPS模塊 ATGM336H

GPS是每一秒自動(dòng)進(jìn)行發(fā)送數(shù)據(jù),當(dāng)GPS狀態(tài)的閃爍,就說(shuō)明獲取到了衛(wèi)星定位

超聲波模塊 HC-SR04

三、代碼編寫(xiě)

這個(gè)的話,我主要調(diào)一個(gè)重要部分,最后會(huì)附上源碼,因?yàn)槲掖a里面帶了聯(lián)網(wǎng)部分,我這邊就先暫時(shí)把聯(lián)網(wǎng)部分屏蔽掉的

1 超聲測(cè)距部分

一個(gè)io設(shè)置為輸入,一個(gè)設(shè)置為輸出

// 檢測(cè)距離
void Distance_text(void) {

  // 發(fā)送觸發(fā)信號(hào)
  digitalWrite(trigPin, LOW);   // 確保先拉低Trig引腳
  delayMicroseconds(2);         // 維持2微秒
  digitalWrite(trigPin, HIGH);  // 觸發(fā)脈沖
  delayMicroseconds(10);        // 維持10微秒
  digitalWrite(trigPin, LOW);   // 結(jié)束觸發(fā)
  // 測(cè)量回波脈沖持續(xù)時(shí)間
  distance = float(pulseIn(echoPin, HIGH) * 17) / 1000;
  if ((int)distance < 50) {

  } else {

  }
  // 顯示結(jié)果
  // Serial.print("disc:");
  // if (distance > 0) {
  //   Serial.print(distance);
  //   Serial.println(" cm");
  // } else {
  //   Serial.println("out");
  // }
}

2 GPS部分

使用模擬串口,進(jìn)行數(shù)據(jù)接收和解析。并且這里利用了顯示了時(shí)區(qū),我們的時(shí)區(qū)需要+8H,就是當(dāng)前時(shí)間,程序已經(jīng)完成這部分

void gpsParser() {
  while (gpsSerial.available()) {
    char Res = gpsSerial.read();

    if (Res == '$') {
      point1 = 0;
      memset(USART_RX2_BUF, 0, sizeof(USART_RX2_BUF));
    }

    USART_RX2_BUF[point1++] = Res;

    // 檢測(cè)GPRMC/GNRMC語(yǔ)句
    if (point1 >= 6 && USART_RX2_BUF[3] == 'R' && USART_RX2_BUF[4] == 'M' && USART_RX2_BUF[5] == 'C') {

      if (Res == 'n') {
        memset(Save_Data.GPS_Buffer, 0, sizeof(Save_Data.GPS_Buffer));
        memcpy(Save_Data.GPS_Buffer, USART_RX2_BUF, point1);
        Save_Data.isGetData = true;
        point1 = 0;
      }
    }

    if (point1 >= sizeof(USART_RX2_BUF) - 1) {
      point1 = 0;
    }
  }
}

void parseGpsBuffer() {
  char* subString;
  char* subStringNext;
  char usefullBuffer[2] = { 0 };
  int commaCount = 0;

  subString = strtok(Save_Data.GPS_Buffer, ",");
  while (subString != NULL) {
    switch (commaCount) {
      case 1:  // UTC時(shí)間
        strncpy(Save_Data.UTCTime, subString, sizeof(Save_Data.UTCTime));
        break;
      case 2:  // 數(shù)據(jù)有效性
        strncpy(usefullBuffer, subString, sizeof(usefullBuffer));
        break;
      case 3:  // 緯度
        strncpy(Save_Data.latitude, subString, sizeof(Save_Data.latitude));
        break;
      case 4:  // N/S
        strncpy(Save_Data.N_S, subString, sizeof(Save_Data.N_S));
        break;
      case 5:  // 經(jīng)度
        strncpy(Save_Data.longitude, subString, sizeof(Save_Data.longitude));
        break;
      case 6:  // E/W
        strncpy(Save_Data.E_W, subString, sizeof(Save_Data.E_W));
        break;
    }
    subString = strtok(NULL, ",");
    commaCount++;
  }

  Save_Data.isUsefull = (usefullBuffer[0] == 'A');
  Save_Data.isParseData = true;
}

void printGpsBuffer() {
  if (Save_Data.isUsefull) {
    // 轉(zhuǎn)換經(jīng)度
    longitude_sum = atof(Save_Data.longitude);
    int longitude_int = (int)(longitude_sum / 100);
    float longitude = longitude_int + (longitude_sum - longitude_int * 100) / 60;

    // 轉(zhuǎn)換緯度
    latitude_sum = atof(Save_Data.latitude);
    int latitude_int = (int)(latitude_sum / 100);
    float latitude = latitude_int + (latitude_sum - latitude_int * 100) / 60;
    // 轉(zhuǎn)化為經(jīng)緯度
    longitude_sum = longitude_int + ((longitude_sum / 100 - longitude_int) * 100) / 60;
    latitude_sum = latitude_int + ((latitude_sum / 100 - latitude_int) * 100) / 60;


    // 時(shí)間解析修正
    String utcTime = Save_Data.UTCTime;
    if (utcTime.length() >= 6) {
      // 安全解析
      hour = utcTime.substring(0, 2).toInt();    // 小時(shí)
      minute = utcTime.substring(2, 4).toInt();  // 分鐘
      second = utcTime.substring(4, 6).toInt();  // 秒
      // 時(shí)區(qū)調(diào)整(UTC+8)
      hour += 8;
      // 處理溢出
      if (hour >= 24) {
        hour -= 24;
        // 日期+1(需補(bǔ)充日期處理邏輯)
      } else if (hour < 0) {
        hour += 24;
        // 日期-1
      }

      // 時(shí)間有效性驗(yàn)證
      if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60) {
        Serial.println("Invalid Time Data");
        return;
      }

      格式化輸出
      Serial.printf("Local Time: %02d:%02d:%02dn", hour, minute, second);
    } else {
      Serial.println("UTC Time Format Error");
    }

    Serial.print("Latitude: ");
    Serial.print(latitude, 6);
    Serial.print(" ");
    Serial.println(Save_Data.N_S);

    Serial.print("Longitude: ");
    Serial.print(longitude, 6);
    Serial.print(" ");
    Serial.println(Save_Data.E_W);
    Serial.println("---------------------");
  } else {
    Serial.println("GPS Data Invalid");
  }
}

3 完整代碼

編譯芯片的選擇:ESPino(ESP-12)Module

#include <SoftwareSerial.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <ESP8266WiFi.h>
//OLED
#include <U8g2lib.h>
#include <Wire.h>
//JSON
#include <ArduinoJson.h>

// 設(shè)置wifi接入信息(請(qǐng)根據(jù)您的WiFi信息進(jìn)行修改)
const char* ssid = "NET";
const char* password = "12345678";
const char* mqttServer = "iot-06z00axdhgfk24n.mqtt.iothub.aliyuncs.com";
// 如以上MQTT服務(wù)器無(wú)法正常連接,請(qǐng)前往以下頁(yè)面尋找解決方案
// http://www.taichi-maker.com/public-mqtt-broker/

Ticker ticker;
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
int count;  // Ticker計(jì)數(shù)用變量
int count_2;
// ****************************************************
// 注意!以下需要用戶根據(jù)然也物聯(lián)平臺(tái)信息進(jìn)行修改!否則無(wú)法工作!
// ****************************************************
const char* mqttUserName = "smartdevice&h9sjy2rtcTI";                                                          // 服務(wù)端連接用戶名(需要修改)
const char* mqttPassword = "5ba9463de09043190a8a743647518c46b1db6e1bfc2e0021198efe3384580772";                 // 服務(wù)端連接密碼(需要修改)
const char* clientId = "h9sjy2rtcTI.smartdevice|securemode=2,signmethod=hmacsha256,timestamp=1739158837609|";  // 客戶端id (需要修改)
const char* subTopic = "/broadcast/h9sjy2rtcTI/test1";                                                         // 訂閱主題(需要修改)
const char* pubTopic = "/broadcast/h9sjy2rtcTI/test2";                                                         // 訂閱主題(需要修改)
const char* willTopic = "/broadcast/h9sjy2rtcTI/test2";                                                        // 遺囑主題名稱(需要修改)
// ****************************************************

//遺囑相關(guān)信息
const char* willMsg = "esp8266 offline";  // 遺囑主題信息
const int willQos = 0;                    // 遺囑QoS
const int willRetain = false;             // 遺囑保留

const int subQoS = 1;            // 客戶端訂閱主題時(shí)使用的QoS級(jí)別(截止2020-10-07,僅支持QoS = 1,不支持QoS = 2)
const bool cleanSession = true;  // 清除會(huì)話(如QoS>0必須要設(shè)為false)


// LED 配置
#define LED_BUILTIN 15
#define LED 2
bool ledStatus = HIGH;
int Waning = 0;
int Ledstate = 0;
// OLED
#define SCL 14
#define SDA 12
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, SCL, SDA, /*reset=*/U8X8_PIN_NONE);
char str[50];  //拼接字符使用
// 定義超聲波傳感器引腳
#define trigPin 5
#define echoPin 4
float distance;

// 配置軟串口(根據(jù)實(shí)際接線修改引腳)
SoftwareSerial gpsSerial(15, 13);  // RX: D8, TX: D7
// GPS數(shù)據(jù)結(jié)構(gòu)
struct {
  char GPS_Buffer[128];
  char UTCTime[12];
  char latitude[16];
  char N_S[2];
  char longitude[16];
  char E_W[2];
  bool isGetData = false;
  bool isParseData = false;
  bool isUsefull = false;
} Save_Data;
// 全局變量
char USART_RX2_BUF[256];
unsigned char point1 = 0;
float longitude_sum, latitude_sum;
int hour, minute, second;

void setup() {

  Serial.begin(9600);     // 啟動(dòng)串口通訊
  gpsSerial.begin(9600);  // GPS模塊常用波特率
  gpsSerial.println("GPS Parser Started");
  //OELD
  u8g2.begin();
  u8g2.setFont(u8g2_font_t0_16_tf);  //設(shè)定字體  u8g2_font_ncenB08_tr

  // //設(shè)置ESP8266工作模式為無(wú)線終端模式
  // WiFi.mode(WIFI_STA);
  // // 連接WiFi
  // connectWifi();
  // // 設(shè)置MQTT服務(wù)器和端口號(hào)
  // mqttClient.setServer(mqttServer, 1883);
  // mqttClient.setCallback(receiveCallback);
  // // 連接MQTT服務(wù)器
  // connectMQTTserver();

  // Ticker定時(shí)對(duì)象
  ticker.attach(1, tickerCount);
  // LED和蜂鳴器
  pinMode(LED_BUILTIN, OUTPUT);          // 設(shè)置板上LED引腳為輸出模式
  pinMode(LED, OUTPUT);                 // 設(shè)置板上LED引腳為輸出模式
  digitalWrite(LED, ledStatus);  // 啟動(dòng)后關(guān)閉板上LED
  digitalWrite(LED_BUILTIN, ledStatus);  // 啟動(dòng)后關(guān)閉板上LED

  pinMode(trigPin, OUTPUT);  // 設(shè)置Trig引腳為輸出模式
  pinMode(echoPin, INPUT);   // 設(shè)置Echo引腳為輸入模式

}
void loop() {
  // // 如果開(kāi)發(fā)板未能成功連接服務(wù)器,則嘗試連接服務(wù)器
  // if (!mqttClient.connected()) {
  //   connectMQTTserver();
  // } else {
    //1秒更新一次
    if (count_2 >= 1) {

      Distance_text();  // 測(cè)量距離
      u8g2.clearBuffer();
      // 解析 GPS
      if (Save_Data.isGetData) {
        parseGpsBuffer();
        Save_Data.isGetData = false;
      }
      if (Save_Data.isParseData) {
        printGpsBuffer();
        Save_Data.isParseData = false;
      }
      // LED
      if (Ledstate) {
        digitalWrite(LED_BUILTIN, HIGH);  // 啟動(dòng)
      } else {
        digitalWrite(LED_BUILTIN, LOW);
        gpsSerial.println("歡迎使用");
        Serial.print("歡迎使用");  
      }
      if (ledStatus == LOW) {
        ledStatus = HIGH;
        digitalWrite(LED, ledStatus);

      } else {
        ledStatus = LOW;
        digitalWrite(LED, ledStatus);
      }
      if ((int)longitude_sum > 1) {
        sprintf(str, "Log: %.6f", longitude_sum);
        u8g2.drawStr(0, 16, str);
        sprintf(str, "Lat: %.6f", latitude_sum);
        u8g2.drawStr(0, 32, str);
        sprintf(str, "Time: %02d:%02d:%02d", hour, minute, second);
        u8g2.drawStr(0, 48, str);
      } else {
        sprintf(str, "Log: error", longitude_sum);
        u8g2.drawStr(0, 16, str);
        sprintf(str, "Lat: error", latitude_sum);
        u8g2.drawStr(0, 32, str);
        sprintf(str, "Time:error", hour, minute, second);
        u8g2.drawStr(0, 48, str);
      }

      sprintf(str, "Disc: %.2f CM", distance);
      u8g2.drawStr(0, 64, str);
      u8g2.sendBuffer();  //顯示

      count_2 = 0;
    }
    //4秒發(fā)送一次
    if (count >= 4) {
      // 每隔4秒鐘發(fā)布一次信息
      // pubMQTTmsg();
      count = 0;
    }
  }

  gpsParser();
  // 處理信息以及心跳
  mqttClient.loop();
}
// 連接WiFi
void connectWiFi() {
  WiFi.begin(ssid, password);
  //Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    
  }
 // Serial.println("nConnected! IP: " + WiFi.localIP().toString());
}
//計(jì)時(shí)器
void tickerCount() {
  count++;
  count_2++;
}
// 連接MQTT服務(wù)器并訂閱信息
void connectMQTTserver() {
  // 根據(jù)ESP8266的MAC地址生成客戶端ID(避免與其它ESP8266的客戶端ID重名)
  /* 連接MQTT服務(wù)器
  boolean connect(const char* id, const char* user, 
                  const char* pass, const char* willTopic, 
                  uint8_t willQos, boolean willRetain, 
                  const char* willMessage, boolean cleanSession); 
  若讓設(shè)備在離線時(shí)仍然能夠讓qos1工作,則connect時(shí)的cleanSession需要設(shè)置為false                
                  */
  if (mqttClient.connect(clientId, mqttUserName,
                         mqttPassword, willTopic,
                         willQos, willRetain, willMsg, cleanSession)) {
    // Serial.print("MQTT Server Connected. ClientId: ");
    // Serial.println(clientId);
    // Serial.print("MQTT Server: ");
    // Serial.println(mqttServer);

    subscribeTopic();  // 訂閱指定主題

  } else {
    // Serial.print("MQTT Server Connect Failed. Client State:");
    // Serial.println(mqttClient.state());
    delay(5000);
  }
}

// 收到信息后的回調(diào)函數(shù)
void receiveCallback(char* topic, byte* payload, unsigned int length) {
  // Serial.print("Message Received [");
  // Serial.print(topic);
  // Serial.print("] ");
  // for (int i = 0; i < length; i++) {
  //   Serial.print((char)payload[i]);
  // }
  //解析數(shù)據(jù)
  massage_parse_json((char*)payload);
  //回傳數(shù)據(jù)
  // pubMQTTmsg();
}

// 訂閱指定主題
void subscribeTopic() {
  // 通過(guò)串口監(jiān)視器輸出是否成功訂閱主題以及訂閱的主題名稱
  // 請(qǐng)注意subscribe函數(shù)第二個(gè)參數(shù)數(shù)字為QoS級(jí)別。這里為QoS = 1
  if (mqttClient.subscribe(subTopic, subQoS)) {
    //Serial.println(subTopic);
  } else {
    //Serial.print("Subscribe Fail...");
    connectMQTTserver();  // 則嘗試連接服務(wù)器
  }
}

// 發(fā)布信息
void pubMQTTmsg() {
  char pubMessage[254];
  // 數(shù)據(jù)流
  MQTT_FillBuf(pubMessage);

  // 實(shí)現(xiàn)ESP8266向主題發(fā)布信息
  if (mqttClient.publish(pubTopic, pubMessage)) {
    //Serial.println("Publish Topic:");Serial.println(pubTopic);
    //Serial.println("Publish message:");
    //Serial.println(pubMessage);
  } else {
    subscribeTopic();  // 則嘗試連接服務(wù)器
    //Serial.println("Message Publish Failed.");
  }
}

// ESP8266連接wifi
void connectWifi() {

  u8g2.clearDisplay();  // 清屏
  sprintf(str, "Wait ...  ");
  u8g2.drawStr(0, 32, str);
  u8g2.sendBuffer();  //顯示
  WiFi.begin(ssid, password);

  //等待WiFi連接,成功連接后輸出成功信息
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    // Serial.print(".");
  }

  //Serial.println("WiFi Connected!");
}

// 數(shù)據(jù)封裝
unsigned char MQTT_FillBuf(char* buf) {

  char text[256];
  memset(text, 0, sizeof(text));

  strcpy(buf, "{");
  if ((int)latitude_sum > 1) {
    memset(text, 0, sizeof(text));
    sprintf(text, ""lat":"%.6f",", latitude_sum);  // Temp是數(shù)據(jù)流的一個(gè)名稱,temper是溫度值
    strcat(buf, text);
    memset(text, 0, sizeof(text));
    sprintf(text, ""log":"%.6f",", longitude_sum);  // Temp是數(shù)據(jù)流的一個(gè)名稱,temper是溫度值
    strcat(buf, text);
  }


  memset(text, 0, sizeof(text));
  sprintf(text, ""disc":"%d",", (int)distance);  // Temp是數(shù)據(jù)流的一個(gè)名稱,temper是溫度值
  strcat(buf, text);

  memset(text, 0, sizeof(text));
  sprintf(text, ""waring":"%d",", Waning);  // Temp是數(shù)據(jù)流的一個(gè)名稱,temper是溫度值
  strcat(buf, text);

  memset(text, 0, sizeof(text));
  sprintf(text, ""led":"%d"", digitalRead(LED_BUILTIN));  // Temp是數(shù)據(jù)流的一個(gè)名稱,temper是溫度值
  strcat(buf, text);

  memset(text, 0, sizeof(text));
  sprintf(text, "}");
  strcat(buf, text);

  return strlen(buf);
}

// 解析json數(shù)據(jù)
void massage_parse_json(char* message) {
  // 聲明一個(gè) JSON 文檔對(duì)象
  StaticJsonDocument<200> doc;
  // 解析 JSON 數(shù)據(jù)
  DeserializationError error = deserializeJson(doc, (const char*)message);
  // 檢查解析是否成功
  if (error) {
    // Serial.print("Failed to parse JSON: ");
    // Serial.println(error.c_str());
    return;
  }
  // 從解析后的 JSON 文檔中獲取鍵值對(duì)
  int cmd = doc["cmd"];
  JsonObject data = doc["data"];
  switch (cmd) {
    case 1:
      Ledstate = data["led"];
      count = 1;
      break;
    case 2:
      if((int)latitude_sum > 1){
        sprintf(str, "當(dāng)前時(shí)間:%02d:%02d:%02d", hour, minute, second);
        gpsSerial.println(str);
      }else{
        sprintf(str, "請(qǐng)先到開(kāi)闊地帶進(jìn)行定位定位", hour, minute, second);
        gpsSerial.println(str);
      }
      count = 1;
      break;
    case 3:

      count = 1;
      break;
  }
}
// 檢測(cè)距離
void Distance_text(void) {

  // 發(fā)送觸發(fā)信號(hào)
  digitalWrite(trigPin, LOW);   // 確保先拉低Trig引腳
  delayMicroseconds(2);         // 維持2微秒
  digitalWrite(trigPin, HIGH);  // 觸發(fā)脈沖
  delayMicroseconds(10);        // 維持10微秒
  digitalWrite(trigPin, LOW);   // 結(jié)束觸發(fā)
  // 測(cè)量回波脈沖持續(xù)時(shí)間
  distance = float(pulseIn(echoPin, HIGH) * 17) / 1000;
  if ((int)distance < 50) {

  } else {

  }
  // 顯示結(jié)果
  // Serial.print("disc:");
  // if (distance > 0) {
  //   Serial.print(distance);
  //   Serial.println(" cm");
  // } else {
  //   Serial.println("out");
  // }
}

void gpsParser() {
  while (gpsSerial.available()) {
    char Res = gpsSerial.read();

    if (Res == '$') {
      point1 = 0;
      memset(USART_RX2_BUF, 0, sizeof(USART_RX2_BUF));
    }

    USART_RX2_BUF[point1++] = Res;

    // 檢測(cè)GPRMC/GNRMC語(yǔ)句
    if (point1 >= 6 && USART_RX2_BUF[3] == 'R' && USART_RX2_BUF[4] == 'M' && USART_RX2_BUF[5] == 'C') {

      if (Res == 'n') {
        memset(Save_Data.GPS_Buffer, 0, sizeof(Save_Data.GPS_Buffer));
        memcpy(Save_Data.GPS_Buffer, USART_RX2_BUF, point1);
        Save_Data.isGetData = true;
        point1 = 0;
      }
    }

    if (point1 >= sizeof(USART_RX2_BUF) - 1) {
      point1 = 0;
    }
  }
}

void parseGpsBuffer() {
  char* subString;
  char* subStringNext;
  char usefullBuffer[2] = { 0 };
  int commaCount = 0;

  subString = strtok(Save_Data.GPS_Buffer, ",");
  while (subString != NULL) {
    switch (commaCount) {
      case 1:  // UTC時(shí)間
        strncpy(Save_Data.UTCTime, subString, sizeof(Save_Data.UTCTime));
        break;
      case 2:  // 數(shù)據(jù)有效性
        strncpy(usefullBuffer, subString, sizeof(usefullBuffer));
        break;
      case 3:  // 緯度
        strncpy(Save_Data.latitude, subString, sizeof(Save_Data.latitude));
        break;
      case 4:  // N/S
        strncpy(Save_Data.N_S, subString, sizeof(Save_Data.N_S));
        break;
      case 5:  // 經(jīng)度
        strncpy(Save_Data.longitude, subString, sizeof(Save_Data.longitude));
        break;
      case 6:  // E/W
        strncpy(Save_Data.E_W, subString, sizeof(Save_Data.E_W));
        break;
    }
    subString = strtok(NULL, ",");
    commaCount++;
  }

  Save_Data.isUsefull = (usefullBuffer[0] == 'A');
  Save_Data.isParseData = true;
}

void printGpsBuffer() {
  if (Save_Data.isUsefull) {
    // 轉(zhuǎn)換經(jīng)度
    longitude_sum = atof(Save_Data.longitude);
    int longitude_int = (int)(longitude_sum / 100);
    float longitude = longitude_int + (longitude_sum - longitude_int * 100) / 60;

    // 轉(zhuǎn)換緯度
    latitude_sum = atof(Save_Data.latitude);
    int latitude_int = (int)(latitude_sum / 100);
    float latitude = latitude_int + (latitude_sum - latitude_int * 100) / 60;
    // 轉(zhuǎn)化為經(jīng)緯度
    longitude_sum = longitude_int + ((longitude_sum / 100 - longitude_int) * 100) / 60;
    latitude_sum = latitude_int + ((latitude_sum / 100 - latitude_int) * 100) / 60;


    // 時(shí)間解析修正
    String utcTime = Save_Data.UTCTime;
    if (utcTime.length() >= 6) {
      // 安全解析
      hour = utcTime.substring(0, 2).toInt();    // 小時(shí)
      minute = utcTime.substring(2, 4).toInt();  // 分鐘
      second = utcTime.substring(4, 6).toInt();  // 秒
      // 時(shí)區(qū)調(diào)整(UTC+8)
      hour += 8;
      // 處理溢出
      if (hour >= 24) {
        hour -= 24;
        // 日期+1(需補(bǔ)充日期處理邏輯)
      } else if (hour < 0) {
        hour += 24;
        // 日期-1
      }

      // 時(shí)間有效性驗(yàn)證
      if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60) {
        Serial.println("Invalid Time Data");
        return;
      }

      格式化輸出
      Serial.printf("Local Time: %02d:%02d:%02dn", hour, minute, second);
    } else {
      Serial.println("UTC Time Format Error");
    }

    Serial.print("Latitude: ");
    Serial.print(latitude, 6);
    Serial.print(" ");
    Serial.println(Save_Data.N_S);

    Serial.print("Longitude: ");
    Serial.print(longitude, 6);
    Serial.print(" ");
    Serial.println(Save_Data.E_W);
    Serial.println("---------------------");
  } else {
    Serial.println("GPS Data Invalid");
  }
}

編譯完成后圖片

四、實(shí)現(xiàn)效果

開(kāi)啟串口會(huì)輸出

五、 參考

Arduino IDE 使用安裝以及ESP32庫(kù)的導(dǎo)入(離線)https://blog.csdn.net/herui_2/article/details/135296814?spm=1001.2014.3001.5501

ESP32/ESP8622 -- 使用MQTT協(xié)議連接云平臺(tái)(帶圖文說(shuō)明)https://herui.blog.csdn.net/article/details/135317019?spm=1001.2014.3001.5502


聯(lián)系方式 微信號(hào):13648103287

  • 聯(lián)系方式.docx
    下載

相關(guān)推薦

方案定制

去合作
方案開(kāi)發(fā)定制化,2000+方案商即時(shí)響應(yīng)!

方案定制,程序設(shè)計(jì)方案、單片機(jī)程序設(shè)計(jì)與講解、APP定制開(kāi)發(fā)。本公眾號(hào)致力于向讀者傳遞關(guān)于程序設(shè)計(jì)和開(kāi)發(fā)的相關(guān)知識(shí),并分享一些關(guān)于軟件開(kāi)發(fā)的最佳實(shí)踐。如果您有什么問(wèn)題或建議,請(qǐng)隨時(shí)聯(lián)系我們。我們將竭誠(chéng)為您服務(wù)