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

ESP32与RS485土壤pH传感器配置故障求助:串口乱码

土壤pH传感器RS485转ESP32通信乱码问题排查

我使用带RS485输出的土壤pH传感器,通过MAX485与ESP32连接,但串口监视器无法显示正确数值,仅出现随机乱码。已尝试更换数据手册中的其他查询帧、插拔引脚,问题仍存在。

硬件连接信息

  • MAX485与ESP32引脚对应:
    • DI → GPIO19
    • DE → GPIO6
    • RE → GPIO5
    • RO → GPIO21

当前代码

#include <ModbusMaster.h>

#define RE 5   // GPIO 5
#define DE 6   // GPIO 6

const byte ph[] = {0x01, 0x03, 0x00, 0x0D, 0x00, 0x01, 0x15, 0xC9};
byte values[2];  // Assuming the response is 2 bytes
ModbusMaster node;

void setup() {
  Serial.begin(4800);  // Adjust the baud rate to 4800
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  digitalWrite(RE, LOW);   // Set RE low for receiving data
  digitalWrite(DE, LOW);   // Set DE low for receiving data
  node.begin(1, Serial);    // Node ID 1, use hardware serial for communication

  // Wait for the serial connection to be established
  while (!Serial) {
    delay(10);
  }

  Serial.println("Serial communication established.");
}

void loop() {
  // Send inquiry frame to the soil pH sensor
  sendInquiryFrame();

  // Wait for a response from the soil pH sensor
  delay(500);  // Adjust the delay as needed

  // Read and process the response
  if (readResponse()) {
    // Calculate pH value from the received data
    uint16_t pHRaw = (values[0] << 8) | values[1];
    float pHValue = pHRaw / 100.0;  // Assuming the pH value is represented as a two-decimal fixed-point number

    Serial.print("Soil pH: ");
    Serial.println(pHValue, 2);  // Print pH value with 2 decimal places
  } else {
    Serial.println("Failed to read from the soil pH sensor.");
  }

  delay(3000);
}

void sendInquiryFrame() {
  // Enable DE to send data
  digitalWrite(DE, HIGH);

  // Send inquiry frame to the soil pH sensor
  if (Serial.write(ph, sizeof(ph)) != sizeof(ph)) {
    Serial.println("Failed to send inquiry frame.");
  }

  delay(2);  // Allow time for transmission to complete
  digitalWrite(DE, LOW);  // Disable DE to receive data
}

bool readResponse() {
  digitalWrite(DE, LOW);
  digitalWrite(RE, HIGH);
  delay(10);
  
  // Read the response from the soil pH sensor
  for (byte i = 0; i < 2; i++) {
    if (Serial.available()) {
      values[i] = Serial.read();
      Serial.print(values[i], HEX);
    } else {
      Serial.println("Timeout waiting for response byte.");
      return false;
    }
  }
  Serial.println();

  digitalWrite(RE, LOW);

  // Check if the expected number of bytes are received
  return (Serial.available() == 0);
}

排查与改进建议

1. 解决串口资源冲突

当前用Serial(ESP32硬件串口0,对应GPIO1/GPIO3)同时做调试输出和RS485通信,会导致数据冲突乱码。ESP32有多组硬件串口,建议把RS485通信切换到Serial2(正好匹配你的DI/GPIO19、RO/GPIO21引脚),调试输出保留Serial:

void setup() {
  Serial.begin(115200); // 调试串口用更高波特率,不干扰RS485
  Serial2.begin(4800);   // RS485通信串口
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  digitalWrite(RE, LOW);
  digitalWrite(DE, LOW);
  node.begin(1, Serial2); // ModbusMaster绑定Serial2
  // 其余代码不变
}

同时修改sendInquiryFrame和readResponse里的Serial.write/Serial.read为Serial2。

2. 修正RE/DE控制逻辑

readResponse里把RE设为HIGH会让MAX485处于发送模式,根本无法接收数据。正确的状态是:

  • 接收时:RE=LOW且DE=LOW
  • 发送时:RE=HIGH且DE=HIGH

修正发送函数:

void sendInquiryFrame() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH); // 发送时两个引脚都要拉高
  if (Serial2.write(ph, sizeof(ph)) != sizeof(ph)) {
    Serial.println("Failed to send inquiry frame.");
  }
  Serial2.flush(); // 等待发送完成,比固定delay更可靠
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
}

修正接收函数开头:

bool readResponse() {
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW); // 必须设为LOW才能接收
  delay(10);
  // 其余代码不变
}

3. 完整读取Modbus响应帧

你查询的0x0D寄存器响应帧完整长度是7字节(地址1+功能码1+字节数1+数据2+CRC2),只读2字节会丢失关键信息且无法校验CRC。修改readResponse读取完整帧并校验:

bool readResponse() {
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
  delay(10);

  byte response[7];
  int bytesRead = 0;
  unsigned long startTime = millis();
  // 等待接收完整7字节,超时1000ms
  while (bytesRead < 7 && millis() - startTime < 1000) {
    if (Serial2.available()) {
      response[bytesRead++] = Serial2.read();
    }
  }

  if (bytesRead != 7) {
    Serial.println("Response incomplete or timeout.");
    return false;
  }

  // 打印完整响应帧方便调试
  Serial.print("Response: ");
  for (int i=0; i<7; i++) {
    Serial.print(response[i], HEX);
    Serial.print(" ");
  }
  Serial.println();

  // 校验CRC
  uint16_t calculatedCRC = node.calculateCRC(response, 5);
  uint16_t receivedCRC = (response[5] << 8) | response[6];
  if (calculatedCRC != receivedCRC) {
    Serial.println("CRC check failed.");
    return false;
  }

  // 提取有效数据
  values[0] = response[3];
  values[1] = response[4];
  return true;
}

4. 硬件层面检查

  • 确认MAX485供电电压:若MAX485是5V供电,RO与GPIO21之间需加电平转换模块,否则3.3V的ESP32无法正确识别5V电平信号。
  • 检查RS485总线A/B线是否接反,传感器与MAX485必须A-A、B-B对应。
  • 总线两端建议添加120Ω终端电阻,减少信号反射导致的乱码。

内容的提问来源于stack exchange,提问作者Rafael Pascua

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 07:00:57