• 方案介绍
    • 前言
    • 一、芯片介绍
    • 二、材料准备
    • 三、代码编写
    • 四、实现效果
    • 五、 参考
  • 附件下载
  • 相关推荐
申请入驻 产业图谱

【ESP32/ESP8266】GPS定位数据解析与超声测距(ATGM336H+HC-SR04)

02/28 08:39
822
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

联系方式.docx

共1个文件

[相关器件] RRM12120 Evaluation Board

Highly Integrated 20A Digital Power Module for High Current Applications Evaluation Board

前言

做拓展项目需要要用GPS定位数据以及超声设计,之前没有用过ESP-12F这个开发板去做过,都是用到STM32板子,今天尝试用Arduino环境进行开发,并实现GPS经纬度数据获取以及超声测距

一、芯片介绍

这款芯片的可用io口还是比较少的,只适合做小型的设备控制,不用看图上有很多io口,其实他很多都不能用,否则就会导致启动错误,我已经踩过坑了

ESP-12F可用输出引脚列表

GPIO编号 物理引脚 特殊限制 最大输出电流 PWM支持 推荐用途
GPIO4 Pin 10 12mA ✔️ LED控制、传感器驱动
GPIO5 Pin 11 启动时需高电平 12mA ✔️ 继电器、数字输出
GPIO12 Pin 14 启动时需低电平 12mA ✔️ 按键输入、低功耗设备
GPIO13 Pin 15 12mA ✔️ SPI MOSI、数据总线
GPIO14 Pin 16 启动时需高电平 12mA ✔️ SPI CLK、高速信号
GPIO15 Pin 17 必须启动时低电平 12mA ✔️ 接地设备控制

禁止使用的输出引脚

GPIO编号 限制原因
GPIO0 启动模式选择(需外部上拉)
GPIO2 内部上拉,启动时需高电平
GPIO16 仅支持开漏输出

二、材料准备

准备这是四个材料就行了

ESP8266开发板 ESP8266-Node
显示屏-0.96寸 显示屏-0.96寸

GPS模块 ATGM336H

GPS是每一秒自动进行发送数据,当GPS状态的闪烁,就说明获取到了卫星定位

超声波模块 HC-SR04

三、代码编写

这个的话,我主要调一个重要部分,最后会附上源码,因为我代码里面带了联网部分,我这边就先暂时把联网部分屏蔽掉的

1 超声测距部分

一个io设置为输入,一个设置为输出

// 检测距离
void Distance_text(void) {

  // 发送触发信号
  digitalWrite(trigPin, LOW);   // 确保先拉低Trig引脚
  delayMicroseconds(2);         // 维持2微秒
  digitalWrite(trigPin, HIGH);  // 触发脉冲
  delayMicroseconds(10);        // 维持10微秒
  digitalWrite(trigPin, LOW);   // 结束触发
  // 测量回波脉冲持续时间
  distance = float(pulseIn(echoPin, HIGH) * 17) / 1000;
  if ((int)distance < 50) {

  } else {

  }
  // 显示结果
  // Serial.print("disc:");
  // if (distance > 0) {
  //   Serial.print(distance);
  //   Serial.println(" cm");
  // } else {
  //   Serial.println("out");
  // }
}

2 GPS部分

使用模拟串口,进行数据接收和解析。并且这里利用了显示了时区,我们的时区需要+8H,就是当前时间,程序已经完成这部分

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;

    // 检测GPRMC/GNRMC语句
    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时间
        strncpy(Save_Data.UTCTime, subString, sizeof(Save_Data.UTCTime));
        break;
      case 2:  // 数据有效性
        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:  // 经度
        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) {
    // 转换经度
    longitude_sum = atof(Save_Data.longitude);
    int longitude_int = (int)(longitude_sum / 100);
    float longitude = longitude_int + (longitude_sum - longitude_int * 100) / 60;

    // 转换纬度
    latitude_sum = atof(Save_Data.latitude);
    int latitude_int = (int)(latitude_sum / 100);
    float latitude = latitude_int + (latitude_sum - latitude_int * 100) / 60;
    // 转化为经纬度
    longitude_sum = longitude_int + ((longitude_sum / 100 - longitude_int) * 100) / 60;
    latitude_sum = latitude_int + ((latitude_sum / 100 - latitude_int) * 100) / 60;


    // 时间解析修正
    String utcTime = Save_Data.UTCTime;
    if (utcTime.length() >= 6) {
      // 安全解析
      hour = utcTime.substring(0, 2).toInt();    // 小时
      minute = utcTime.substring(2, 4).toInt();  // 分钟
      second = utcTime.substring(4, 6).toInt();  // 秒
      // 时区调整(UTC+8)
      hour += 8;
      // 处理溢出
      if (hour >= 24) {
        hour -= 24;
        // 日期+1(需补充日期处理逻辑)
      } else if (hour < 0) {
        hour += 24;
        // 日期-1
      }

      // 时间有效性验证
      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>

// 设置wifi接入信息(请根据您的WiFi信息进行修改)
const char* ssid = "NET";
const char* password = "12345678";
const char* mqttServer = "iot-06z00axdhgfk24n.mqtt.iothub.aliyuncs.com";
// 如以上MQTT服务器无法正常连接,请前往以下页面寻找解决方案
// http://www.taichi-maker.com/public-mqtt-broker/

Ticker ticker;
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
int count;  // Ticker计数用变量
int count_2;
// ****************************************************
// 注意!以下需要用户根据然也物联平台信息进行修改!否则无法工作!
// ****************************************************
const char* mqttUserName = "smartdevice&h9sjy2rtcTI";                                                          // 服务端连接用户名(需要修改)
const char* mqttPassword = "5ba9463de09043190a8a743647518c46b1db6e1bfc2e0021198efe3384580772";                 // 服务端连接密码(需要修改)
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";                                                        // 遗嘱主题名称(需要修改)
// ****************************************************

//遗嘱相关信息
const char* willMsg = "esp8266 offline";  // 遗嘱主题信息
const int willQos = 0;                    // 遗嘱QoS
const int willRetain = false;             // 遗嘱保留

const int subQoS = 1;            // 客户端订阅主题时使用的QoS级别(截止2020-10-07,仅支持QoS = 1,不支持QoS = 2)
const bool cleanSession = true;  // 清除会话(如QoS>0必须要设为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;

// 配置软串口(根据实际接线修改引脚)
SoftwareSerial gpsSerial(15, 13);  // RX: D8, TX: D7
// GPS数据结构
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);     // 启动串口通讯
  gpsSerial.begin(9600);  // GPS模块常用波特率
  gpsSerial.println("GPS Parser Started");
  //OELD
  u8g2.begin();
  u8g2.setFont(u8g2_font_t0_16_tf);  //设定字体  u8g2_font_ncenB08_tr

  // //设置ESP8266工作模式为无线终端模式
  // WiFi.mode(WIFI_STA);
  // // 连接WiFi
  // connectWifi();
  // // 设置MQTT服务器和端口号
  // mqttClient.setServer(mqttServer, 1883);
  // mqttClient.setCallback(receiveCallback);
  // // 连接MQTT服务器
  // connectMQTTserver();

  // Ticker定时对象
  ticker.attach(1, tickerCount);
  // LED和蜂鸣器
  pinMode(LED_BUILTIN, OUTPUT);          // 设置板上LED引脚为输出模式
  pinMode(LED, OUTPUT);                 // 设置板上LED引脚为输出模式
  digitalWrite(LED, ledStatus);  // 启动后关闭板上LED
  digitalWrite(LED_BUILTIN, ledStatus);  // 启动后关闭板上LED

  pinMode(trigPin, OUTPUT);  // 设置Trig引脚为输出模式
  pinMode(echoPin, INPUT);   // 设置Echo引脚为输入模式

}
void loop() {
  // // 如果开发板未能成功连接服务器,则尝试连接服务器
  // if (!mqttClient.connected()) {
  //   connectMQTTserver();
  // } else {
    //1秒更新一次
    if (count_2 >= 1) {

      Distance_text();  // 测量距离
      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);  // 启动
      } 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秒发送一次
    if (count >= 4) {
      // 每隔4秒钟发布一次信息
      // 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());
}
//计时器
void tickerCount() {
  count++;
  count_2++;
}
// 连接MQTT服务器并订阅信息
void connectMQTTserver() {
  // 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)
  /* 连接MQTT服务器
  boolean connect(const char* id, const char* user, 
                  const char* pass, const char* willTopic, 
                  uint8_t willQos, boolean willRetain, 
                  const char* willMessage, boolean cleanSession); 
  若让设备在离线时仍然能够让qos1工作,则connect时的cleanSession需要设置为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);
  }
}

// 收到信息后的回调函数
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]);
  // }
  //解析数据
  massage_parse_json((char*)payload);
  //回传数据
  // pubMQTTmsg();
}

// 订阅指定主题
void subscribeTopic() {
  // 通过串口监视器输出是否成功订阅主题以及订阅的主题名称
  // 请注意subscribe函数第二个参数数字为QoS级别。这里为QoS = 1
  if (mqttClient.subscribe(subTopic, subQoS)) {
    //Serial.println(subTopic);
  } else {
    //Serial.print("Subscribe Fail...");
    connectMQTTserver();  // 则尝试连接服务器
  }
}

// 发布信息
void pubMQTTmsg() {
  char pubMessage[254];
  // 数据流
  MQTT_FillBuf(pubMessage);

  // 实现ESP8266向主题发布信息
  if (mqttClient.publish(pubTopic, pubMessage)) {
    //Serial.println("Publish Topic:");Serial.println(pubTopic);
    //Serial.println("Publish message:");
    //Serial.println(pubMessage);
  } else {
    subscribeTopic();  // 则尝试连接服务器
    //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!");
}

// 数据封装
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是数据流的一个名称,temper是温度值
    strcat(buf, text);
    memset(text, 0, sizeof(text));
    sprintf(text, ""log":"%.6f",", longitude_sum);  // Temp是数据流的一个名称,temper是温度值
    strcat(buf, text);
  }


  memset(text, 0, sizeof(text));
  sprintf(text, ""disc":"%d",", (int)distance);  // Temp是数据流的一个名称,temper是温度值
  strcat(buf, text);

  memset(text, 0, sizeof(text));
  sprintf(text, ""waring":"%d",", Waning);  // Temp是数据流的一个名称,temper是温度值
  strcat(buf, text);

  memset(text, 0, sizeof(text));
  sprintf(text, ""led":"%d"", digitalRead(LED_BUILTIN));  // Temp是数据流的一个名称,temper是温度值
  strcat(buf, text);

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

  return strlen(buf);
}

// 解析json数据
void massage_parse_json(char* message) {
  // 声明一个 JSON 文档对象
  StaticJsonDocument<200> doc;
  // 解析 JSON 数据
  DeserializationError error = deserializeJson(doc, (const char*)message);
  // 检查解析是否成功
  if (error) {
    // Serial.print("Failed to parse JSON: ");
    // Serial.println(error.c_str());
    return;
  }
  // 从解析后的 JSON 文档中获取键值对
  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, "当前时间:%02d:%02d:%02d", hour, minute, second);
        gpsSerial.println(str);
      }else{
        sprintf(str, "请先到开阔地带进行定位定位", hour, minute, second);
        gpsSerial.println(str);
      }
      count = 1;
      break;
    case 3:

      count = 1;
      break;
  }
}
// 检测距离
void Distance_text(void) {

  // 发送触发信号
  digitalWrite(trigPin, LOW);   // 确保先拉低Trig引脚
  delayMicroseconds(2);         // 维持2微秒
  digitalWrite(trigPin, HIGH);  // 触发脉冲
  delayMicroseconds(10);        // 维持10微秒
  digitalWrite(trigPin, LOW);   // 结束触发
  // 测量回波脉冲持续时间
  distance = float(pulseIn(echoPin, HIGH) * 17) / 1000;
  if ((int)distance < 50) {

  } else {

  }
  // 显示结果
  // 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;

    // 检测GPRMC/GNRMC语句
    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时间
        strncpy(Save_Data.UTCTime, subString, sizeof(Save_Data.UTCTime));
        break;
      case 2:  // 数据有效性
        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:  // 经度
        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) {
    // 转换经度
    longitude_sum = atof(Save_Data.longitude);
    int longitude_int = (int)(longitude_sum / 100);
    float longitude = longitude_int + (longitude_sum - longitude_int * 100) / 60;

    // 转换纬度
    latitude_sum = atof(Save_Data.latitude);
    int latitude_int = (int)(latitude_sum / 100);
    float latitude = latitude_int + (latitude_sum - latitude_int * 100) / 60;
    // 转化为经纬度
    longitude_sum = longitude_int + ((longitude_sum / 100 - longitude_int) * 100) / 60;
    latitude_sum = latitude_int + ((latitude_sum / 100 - latitude_int) * 100) / 60;


    // 时间解析修正
    String utcTime = Save_Data.UTCTime;
    if (utcTime.length() >= 6) {
      // 安全解析
      hour = utcTime.substring(0, 2).toInt();    // 小时
      minute = utcTime.substring(2, 4).toInt();  // 分钟
      second = utcTime.substring(4, 6).toInt();  // 秒
      // 时区调整(UTC+8)
      hour += 8;
      // 处理溢出
      if (hour >= 24) {
        hour -= 24;
        // 日期+1(需补充日期处理逻辑)
      } else if (hour < 0) {
        hour += 24;
        // 日期-1
      }

      // 时间有效性验证
      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");
  }
}

编译完成后图片

四、实现效果

开启串口会输出

五、 参考

Arduino IDE 使用安装以及ESP32库的导入(离线)https://blog.csdn.net/herui_2/article/details/135296814?spm=1001.2014.3001.5501

ESP32/ESP8622 -- 使用MQTT协议连接云平台(带图文说明)https://herui.blog.csdn.net/article/details/135317019?spm=1001.2014.3001.5502


联系方式 微信号:13648103287

  • 联系方式.docx
    下载
[相关器件] RRM12120 Evaluation Board

Highly Integrated 20A Digital Power Module for High Current Applications Evaluation Board

点赞
收藏
评论
分享
加入交流群
举报

相关推荐

方案定制

去合作
方案开发定制化,2000+方案商即时响应!

方案定制,程序设计方案、单片机程序设计与讲解、APP定制开发。本公众号致力于向读者传递关于程序设计和开发的相关知识,并分享一些关于软件开发的最佳实践。如果您有什么问题或建议,请随时联系我们。我们将竭诚为您服务