You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32读取Makel M600电表数据出现串口乱码问题求助

问题分析与解决方案

你的核心问题集中在RS485收发控制缺失、IEC 62056-21协议指令格式错误、初始波特率不匹配这几个关键点,以下是针对性的解决步骤:

1. 必须添加RS485收发控制引脚

RS485是半双工通信,必须通过DE/RE引脚切换收发状态:

  • 发送数据时,将DE/RE置为高电平
  • 发送完成后立即置为低电平,才能接收电表返回的数据

修改步骤:

  • 选择ESP32的一个GPIO作为DE/RE控制引脚(例:GPIO4)
  • 在代码中初始化该引脚为输出模式
  • 发送指令前后切换引脚状态

2. 修正IEC 62056-21协议的指令格式

你的代码中发送的是字符串字面量(如<CR><LF>、[SOH]),这些不是协议要求的控制字符,必须替换为对应ASCII控制码:

  • <CR>对应\r(ASCII 0x0D),<LF>对应\n(ASCII 0x0A)
  • SOH为0x01,STX为0x02,ETX为0x03
  • 初始识别指令应为/?!\r\n,而非字符串"/?!<CR><LF>"
  • BCC校验位需计算:从STX到ETX所有字节的异或值,不能直接写[BCC]

3. 匹配电表初始波特率

Makel M600电表的IEC 62056-21初始波特率默认是300bps(协议规定的Baud rate A),你一开始用9600bps会直接导致通信乱码,必须先以300bps完成识别,再协商切换到更高波特率。

4. 修正代码中的其他问题

  • 移除重复的Serial.begin(9600)调用
  • 优先使用ESP32的硬件串口(HardwareSerial),比SoftwareSerial更稳定

修改后的示例代码

#include <WiFi.h>

// 定义RS485控制引脚
#define RS485_DE_RE 4
// 使用硬件串口2(GPIO16=RX, GPIO17=TX)
HardwareSerial rs485Serial(2);

const char* ssid = "--";
const char* password = "--";

void setup() {
  Serial.begin(9600);
  
  // 初始化RS485控制引脚
  pinMode(RS485_DE_RE, OUTPUT);
  digitalWrite(RS485_DE_RE, LOW); // 默认处于接收状态

  // 连接WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // 初始化RS485串口,初始波特率300bps(IEC 62056-21默认)
  rs485Serial.begin(300, SERIAL_8N1);
  
  delay(1000);
  sendIdentificationCommand();
}

void loop() {
  if (rs485Serial.available()) {
    String response = rs485Serial.readStringUntil('\n');
    Serial.println("Received: " + response);

    // 识别响应格式为 /METER_ADDRESS\r\n,比如/SAT...
    if (response.startsWith("/")) {
      // 协商切换到9600bps(协议帧格式:050代表9600)
      sendBaudRateChangeCommand();
      // 切换本地串口波特率到9600
      rs485Serial.end();
      rs485Serial.begin(9600, SERIAL_8N1);
      delay(500);
      // 发送读取有功电能的指令
      sendReadEnergyCommand();
    }
  }
}

// 发送设备识别指令 /?!\r\n
void sendIdentificationCommand() {
  digitalWrite(RS485_DE_RE, HIGH);
  rs485Serial.print("/?!\r\n");
  rs485Serial.flush(); // 等待发送完成
  digitalWrite(RS485_DE_RE, LOW);
}

// 发送波特率切换指令 [DATA]050\r\n
void sendBaudRateChangeCommand() {
  digitalWrite(RS485_DE_RE, HIGH);
  rs485Serial.print("\x10\x02050\x03\x1B\r\n"); // DATA对应ASCII 0x10
  rs485Serial.flush();
  digitalWrite(RS485_DE_RE, LOW);
}

// 发送读取有功电能(1.8.0)的指令,带BCC校验
void sendReadEnergyCommand() {
  digitalWrite(RS485_DE_RE, HIGH);
  // 构造指令:SOH(0x01) + R2 + STX(0x02) + 1.8.0 + ETX(0x03) + BCC
  byte cmd[] = {0x01, 'R', '2', 0x02, '1', '.', '8', '.', '0', 0x03};
  // 计算BCC:从STX到ETX的异或
  byte bcc = 0;
  for (int i=3; i<sizeof(cmd); i++) {
    bcc ^= cmd[i];
  }
  // 发送指令
  rs485Serial.write(cmd, sizeof(cmd));
  rs485Serial.write(bcc);
  rs485Serial.print("\r\n");
  rs485Serial.flush();
  digitalWrite(RS485_DE_RE, LOW);
}

额外调试建议

  • 用示波器或逻辑分析仪检测RS485总线波形,确认发送的指令是否正确
  • 检查RS485模块接线:A接A,B接B,必须共地(无共地极易出现乱码)
  • 确保RS485模块工作电压与ESP32匹配(通常为3.3V或5V)

内容的提问来源于stack exchange,提问作者Nur Guzay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 18:32:06