智能硬件 · 2026/5/24
ESP32-C3 家庭灌溉主机接入 RS485 土壤传感器的排障记录
记录 ESP32-C3 家庭灌溉主机接入 RS485 土壤温湿度/多参数传感器时的接线、Modbus 读取、OTA 固件基线和现场排障要点。
这是一篇现场排障记录,主题是把 ESP32-C3 家庭灌溉主机接入 RS485 土壤温湿度/多参数传感器,并让传感器数据稳定进入浇灌策略。最终稳定结论并不复杂:协议先回到已验证的稳定基线,硬件接线必须按实测确认,ESP32-C3、TTL-RS485 模块和传感器必须共地。
最终稳定结论
本次稳定基线为 garden-home-485-1.0.14.1。它保留 1.0.14 已验证的 RS485/Modbus 读取逻辑,只调整现场确认有效的 UART 引脚方向和界面展示。
- 默认 B 接口:
TX=GPIO0,RX=GPIO1 - 可选 A 接口:
TX=GPIO6,RX=GPIO7 - 温湿度传感器:地址
1,4800bps,Modbus RTU 8N1,功能码03,读取0x0000起始的 2 个寄存器 - 多参数传感器:地址
4,9600bps,Modbus RTU 8N1,功能码03,读取0x0000起始的 8 个寄存器 - 多参数寄存器顺序:温度、湿度、电导率、盐分、氮、磷、钾、pH
- 轮询结果会进入本地页面、远程中心和智能浇灌策略
为什么这次排障容易绕弯
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=GPIO0、RX=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 应在 0 到 14。这些校验不能代替传感器标定,但能过滤明显错误的回包。
本地页面和中心同步
传感器数据读取成功后,主机会同时更新三类状态:
- 本地网页里的实时土壤数据
- 家庭中心里的设备状态和传感器摘要
- 智能浇灌策略的判断因子
为了避免用户误解,界面上不再展示过多调试字段,例如原始请求帧、原始回包和协议矩阵。面向最终用户时,重点显示湿度、温度、pH、EC、盐分、NPK 和通信状态;面向维护人员时,再通过日志或调试版本看原始帧。
OTA 与版本基线
这次最终保留的稳定版本是 garden-home-485-1.0.14.1。之所以没有继续沿用后续实验版本,是因为后续版本为了兼容更多传感器尝试了更宽的自动探测组合,但现场表现不如固定基线稳定。
对商用设备来说,固件升级策略应当优先考虑稳定性:
- 已验证的协议基线不要频繁变动
- 传感器兼容扩展应逐个加入,而不是一次性扩大扫描矩阵
- OTA 清单应由厂家维护,普通用户不需要手动输入固件地址
- 本地页面可以提供更新入口,但真正的固件源应固定在厂家侧
- 每次 OTA 发布都应记录版本号、适用硬件和核心变更
编译时要使用 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 土壤传感器读不到数据,可以按下面顺序排查。
- 先确认传感器供电是否符合铭牌要求,不要默认 3.3V 一定够用
- 确认 ESP32-C3、TTL-RS485 模块、传感器电源是否共地
- 确认 A/B 是否接反,必要时交换 A/B 测试
- 确认 TXD/RXD 是否需要交叉,尤其要注意自动收发方向模块的实际行为
- 确认当前固件选择的接口是 A 还是 B
- 确认传感器地址、波特率、功能码和寄存器表
- 如果只有温湿度没有 NPK,优先检查是否读错了寄存器数量或设备地址
- 如果某块 485 模块能读、另一块不能读,优先比较模块是否需要共地、是否支持自动方向控制、是否存在丝印方向差异
- 如果现场设备离线但本地热点还在,优先检查 MQTT 连接健康、自恢复和 OTA 版本是否一致
这次得到的可复用经验
第一,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,最后往往是硬件细节。