智能硬件 · 2026/5/24

ESP32-C3 家庭灌溉主机接入 RS485 土壤传感器的排障记录

记录 ESP32-C3 家庭灌溉主机接入 RS485 土壤温湿度/多参数传感器时的接线、Modbus 读取、OTA 固件基线和现场排障要点。

tips-onlyESP32-C3RS485Modbus智能灌溉土壤传感器Arduino

这是一篇现场排障记录,主题是把 ESP32-C3 家庭灌溉主机接入 RS485 土壤温湿度/多参数传感器,并让传感器数据稳定进入浇灌策略。最终稳定结论并不复杂:协议先回到已验证的稳定基线,硬件接线必须按实测确认,ESP32-C3、TTL-RS485 模块和传感器必须共地。

最终稳定结论

本次稳定基线为 garden-home-485-1.0.14.1。它保留 1.0.14 已验证的 RS485/Modbus 读取逻辑,只调整现场确认有效的 UART 引脚方向和界面展示。

为什么这次排障容易绕弯

RS485 本身只是物理层,真正决定能不能读到数据的是三件事:UART 接线方向、Modbus 参数、传感器寄存器表。只要其中一个不对,表现就可能是“完全没有回包”“只有温湿度没有 NPK”“某些模块能读某些模块不能读”。

这次现场最关键的发现是:不同 TTL-RS485 转接板的丝印和收发方向未必符合我们脑子里的“标准交叉接法”。有的自动收发方向模块,按常规 TX 接 RX、RX 接 TX 反而不能读,必须按模块实际行为验证。

硬件接线图

下面是最终稳定接线的逻辑图。实际电源电压要以传感器铭牌为准,很多土壤多参数传感器不是 3.3V 供电。

ESP32-C3 主控                TTL-RS485 转接板                 RS485 土壤传感器
------------                ----------------                 ----------------
GND      ------------------> GND ---------------------------> 电源负 / GND
供电      ------------------> VCC                             传感器按铭牌供电

GPIO0 TX ------------------> TXD
GPIO1 RX <------------------ RXD

                              A+  --------------------------> A+
                              B-  --------------------------> B-

如果使用备用 A 接口,可以把 UART 改为:

ESP32-C3 GPIO6 作为 TX
ESP32-C3 GPIO7 作为 RX

现场经验是:一定要让 ESP32-C3、RS485 模块、传感器电源共地。之前出现过“接线看起来都对,但完全没有数据”的情况,最后发现是两端 GND 没有联通。

程序运行架构

家庭灌溉主机不是只读一个传感器,它同时承担本地配网、远程控制、OTA 升级、继电器控制和智能策略计算。因此 RS485 读取必须是非阻塞、可恢复、可被页面和中心同步的一个子模块。

手机 / 浏览器 / 家庭中心
        |
        v
ESP32-C3 家庭灌溉主机
  |-- Wi-Fi:联网、天气、远程控制
  |-- MQTT:状态上报、远程指令、参数同步
  |-- 本地 Web:配网、状态查看、本地控制
  |-- OTA:厂家固件更新
  |-- GPIO:继电器控制水泵或电磁阀
  |-- UART:读取 RS485 土壤传感器
  |-- Watchdog / 自恢复:异常时尽量自动恢复
        |
        v
RS485 土壤温湿度 / 土壤多参数传感器

程序启动后会初始化 RS485 总线,并按配置的接口选择 UART 引脚。默认启用 B 接口,也就是 TX=GPIO0RX=GPIO1。本地完整设置页里保留 A/B 接口选择,方便现场在两组引脚之间切换。

Modbus 读取方式

固件没有继续使用过大的自动探测矩阵,而是回到现场已经验证稳定的两类设备读取策略。这样做的好处是响应快、误判少、调试边界清晰。

轮询开始
  |
  |-- 读取温湿度传感器
  |     地址:1
  |     波特率:4800bps
  |     功能码:03
  |     起始寄存器:0x0000
  |     寄存器数量:2
  |     结果:土壤湿度、土壤温度
  |
  |-- 读取多参数传感器
        地址:4
        波特率:9600bps
        功能码:03
        起始寄存器:0x0000
        寄存器数量:8
        结果:温度、湿度、电导率、盐分、N、P、K、pH

典型的 Modbus RTU 请求帧由设备地址、功能码、起始寄存器、寄存器数量和 CRC 组成。固件每次请求后会等待回包,检查长度、地址、功能码、字节数和 CRC,再把寄存器解析成业务数据。

请求帧结构

[地址] [功能码] [起始寄存器高位] [起始寄存器低位] [数量高位] [数量低位] [CRC低位] [CRC高位]

多参数传感器读取到的 8 个寄存器按下面的顺序进入系统:

0: 温度
1: 湿度
2: 电导率
3: 盐分
4: 氮
5: 磷
6: 钾
7: pH

程序会做基本合理性校验,例如土壤湿度应在 0%100%,温度应在合理范围,pH 应在 014。这些校验不能代替传感器标定,但能过滤明显错误的回包。

本地页面和中心同步

传感器数据读取成功后,主机会同时更新三类状态:

为了避免用户误解,界面上不再展示过多调试字段,例如原始请求帧、原始回包和协议矩阵。面向最终用户时,重点显示湿度、温度、pH、EC、盐分、NPK 和通信状态;面向维护人员时,再通过日志或调试版本看原始帧。

OTA 与版本基线

这次最终保留的稳定版本是 garden-home-485-1.0.14.1。之所以没有继续沿用后续实验版本,是因为后续版本为了兼容更多传感器尝试了更宽的自动探测组合,但现场表现不如固定基线稳定。

对商用设备来说,固件升级策略应当优先考虑稳定性:

编译时要使用 ESP32-C3 对应板型,并保留 OTA 双分区能力:

arduino-cli compile --fqbn esp32:esp32:esp32c3:PartitionScheme=min_spiffs --export-binaries .

上传到本地开发板时使用:

arduino-cli upload -p <串口设备> --fqbn esp32:esp32:esp32c3:PartitionScheme=min_spiffs .

排障清单

如果 RS485 土壤传感器读不到数据,可以按下面顺序排查。

这次得到的可复用经验

第一,RS485 项目不要一上来追求“万能自动识别”。自动识别有价值,但必须建立在已验证协议的基础上,否则它会把硬件接线问题、传感器协议问题和程序逻辑问题混在一起。

第二,最终用户界面要隐藏调试噪声。客户关心的是土壤湿度、温度、pH、肥力指标和设备是否正常,不关心最近请求帧和 CRC。

第三,硬件接线说明必须写得非常具体。尤其是 GND 共地、A/B 极性、TX/RX 方向,这些问题在实验室里很容易被忽略,但到了现场就是稳定性的分水岭。

第四,商用固件要有清晰版本基线。遇到回归时,能快速回退到稳定版本,再在稳定版本上做最小增量修复,这比不断叠加实验逻辑可靠得多。

简化版接线备忘

默认 B 接口

ESP32-C3 GPIO0  ->  RS485 模块 TXD
ESP32-C3 GPIO1  ->  RS485 模块 RXD
ESP32-C3 GND    ->  RS485 模块 GND  ->  传感器电源负 / GND
RS485 模块 A+   ->  传感器 A+
RS485 模块 B-   ->  传感器 B-

如果按上面接法没有数据,不要急着改程序。先确认模块丝印、A/B、共地和传感器供电。RS485 的很多问题,看起来像软件 bug,最后往往是硬件细节。