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
相关产品推荐
相关产品推荐

