Modbus RTU 配置
Modbus RTU 配置与详解
适用于 FastBee IoT Platform — ESP32 固件
默认适配:国产通用型 Modbus RTU 继电器模块(闪开型)
当前版本提示
- 精简版默认关闭 Modbus RTU;需要 Modbus 主站请使用 Standard/Full 固件,或在自定义构建中启用
FASTBEE_ENABLE_MODBUS=1并重新做内存和长稳验证。 - Modbus 子设备编辑、映射和删除操作都在 Web 页面内完成;删除会先弹出确认窗口,确认后再删除。
- 电机类子设备控制面板提供正转、停止、反转等默认按钮样式,适合快速调试方向控制。
- Modbus RTU 配置、子设备和映射保存在
/config/protocol.json,可在"设备配置 > 高级配置 > 配置导入/导出"中按"通信协议"单独备份或恢复。 - 导入
protocol.json后建议重启设备,确保串口、主站任务和子设备映射从新配置重新初始化。
Modbus 调试主要在"通信协议 / Modbus RTU"页面完成;涉及联动时,再到"外设执行"页面创建轮询或控制规则。
快速参考
系统架构
调试时建议先让主站稳定读到单个从站,再扩展到多从站轮询;涉及控制动作时,再接入外设执行规则并观察日志。
遇到超时或异常码时按闭环图逐层排查:先物理层,再串口参数和从站映射,最后才检查外设执行控制动作和业务规则。
串口配置
| 配置项 | 说明 | 默认值 |
|---|---|---|
| 串口端口 | UART1/UART2 | UART1 |
| TX 引脚 | 发送引脚 | GPIO16 |
| RX 引脚 | 接收引脚 | GPIO17 |
| 波特率 | 通信速率 | 9600 |
| 数据位 | 数据位数 | 8 |
| 停止位 | 停止位数 | 1 |
| 校验 | 校验方式 | 无(0) |
支持的功能码
| 功能码 | 说明 | 操作 |
|---|---|---|
| 0x01 | 读线圈 | 读取开关量 |
| 0x02 | 读离散输入 | 读取输入状态 |
| 0x03 | 读保持寄存器 | 读取数据(常用) |
| 0x04 | 读输入寄存器 | 读取只读数据 |
| 0x05 | 写单线圈 | 控制单个开关 |
| 0x06 | 写单寄存器 | 写入单个值 |
| 0x10 | 写多寄存器 | 批量写入 |
故障排除
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 通信超时 | 接线错误/波特率不匹配 | 检查 TX-RX 交叉接线和波特率 |
| CRC 错误 | 电气干扰/线路过长 | 缩短线路或添加终端电阻(120Ω) |
| 从站无响应 | 地址错误 | 确认从站地址(使用扫描功能) |
| 数据异常 | 数据类型/字节序错误 | 检查 INT16/FLOAT32 和大小端设置 |
| 只能读不能写 | 功能码错误 | 读用03/04,写用05/06/10 |
Modbus RTU 寄存器映射地图
| 数据区 | 地址表示 | 常用功能码 | 读写能力 | FastBee 配置关注点 |
|---|---|---|---|---|
| Coils | 00001+ | FC01 读、FC05 写单线圈、FC0F 批量写 | 读/写 | 常用于继电器、开关量输出。 |
| Discrete Inputs | 10001+ | FC02 | 只读 | 常用于开关量输入状态。 |
| Holding Registers | 40001+ | FC03 读、FC06 写单寄存器、FC10 批量写 | 读/写 | 常用于参数、设定值、控制寄存器。 |
| Input Registers | 30001+ | FC04 | 只读 | 常用于测量值。 |
| RTU 请求帧 | Slave / Func / Addr / Value / CRC | 由设备手册决定 | - | 手册地址常与协议地址相差 1,需现场核对。 |
配置寄存器前先对照映射地图确认三件事:功能码是否匹配目标数据区,手册地址是显示地址还是协议地址,FastBee API 中的 address 是否需要减 1。多数"读数偏一位"或"能读不能写"都出在这三处。
REST API 快速参考
| 页面/API 动作 | REST API | 常用功能码 | 数据区 | 排查重点 |
|---|---|---|---|---|
| 刷新状态 | GET /api/modbus/status | - | 连接状态 | 先确认串口参数、总线方向和从站在线。 |
| 开关线圈 | POST /api/modbus/coil | FC05 / FC0F | Coils | 确认线圈地址是否需要减 1。 |
| 读寄存器 | POST /api/modbus/read | FC03 / FC04 | Holding/Input Registers | 核对功能码、起始地址、数量和字节序。 |
| 写参数 | POST /api/modbus/write | FC06 / FC10 | Holding Registers | 确认设备允许写入,并先在安全状态验证。 |
| 原生私有帧 | POST /api/modbus/native | 0xB0 / 原生 | 设备私有帧 | 核对厂商协议、CRC 和响应格式。 |
当你从 Web 面板或 REST API 发起控制时,可用上图快速定位对应功能码和数据区。调试时先确认 API 参数和功能码匹配,再检查地址偏移、串口参数和从站响应。
1. 概述
Modbus 调试与控制面板是 FastBee Arduino内置的 Modbus RTU 操作工具,集成在 Web 管理界面的「协议配置 > Modbus RTU」标签页中。
它基于标准 Modbus RTU 功能码实现,并针对国产通用型 Modbus RTU 继电器模块(闪开型)进行了默认适配,支持其原生指令集。同时兼容标准 Modbus RTU 数字量输入输出模块(如中盛科技4路继电器等),支持 FC 0x06 寄存器模式控制。主要功能:
- 继电器模块的线圈开关控制(原生翻转指令 0x5500)
- 闪开延时控制(硬件定时,FC 0x05 地址 0x0200+通道)
- 硬件寄存器延时(FC 0x06 写延时值,设备自动延时翻转)
- 批量开/关/翻转操作(原生全翻转指令 0x5A00 / 寄存器批量控制)
- 离散输入(DI)状态读取
- 从站设备地址管理(广播读取/写入)
- 从站设备波特率配置(FC 0xB0 专有指令 / FC 0x06 寄存器模式)
- 通信调试和设备排查
支持的 Modbus 功能码
| 功能码 | 名称 | 用途 |
|---|---|---|
| FC 0x01 | Read Coils | 读取线圈状态 |
| FC 0x02 | Read Discrete Inputs | 读取离散输入状态 |
| FC 0x03 | Read Holding Registers | 读取保持寄存器(含广播读地址) |
| FC 0x05 | Write Single Coil | 写单个线圈 / 原生翻转 / 闪开延时 |
| FC 0x06 | Write Single Register | 写单个保持寄存器 |
| FC 0x0F | Write Multiple Coils | 写多个线圈(批量开/关) |
| FC 0x10 | Write Multiple Registers | 写多个保持寄存器(含广播写地址) |
| FC 0xB0 | Set Baud Rate (专有) | 修改从站波特率(继电器板专有指令) |
2. 前置条件
2.1 硬件连接
ESP32 Modbus从站设备
┌──────────┐ ┌──────────────┐
│ TX Pin ├───→│ RX (A+/B-) │
│ RX Pin │←───│ TX (A+/B-) │
│ DE Pin ├───→│ DE (可选) │
│ GND ├────────────│ GND │
└──────────┘ └──────────────┘- RS485 模块:需要连接 DE(方向控制)引脚。如使用自动收发的 RS485 模块,DE 引脚设为
-1即可。 - TTL 直连:适用于 TTL 电平的 Modbus 设备,无需 DE 引脚。
- 供电:确保从站设备与 ESP32 共地。
2.2 软件配置
- 固件已上传至 ESP32,文件系统已同步
- ESP32 已连接 WiFi,可通过浏览器访问 Web 界面
- 在 Web 界面中进入 协议配置 页面
2.3 外设配置
在 Modbus RTU 标签页中,需先选择或配置 UART 外设:
| 参数 | 说明 | 典型值 |
|---|---|---|
| 外设配置选择 | 选择已配置的 UART 外设实例 | 下拉选择 |
| DE 引脚 (RS485) | RS485 方向控制引脚号 | 14(无 DE 设 -1) |
| 传输类型 | JSON 结构化 / 透传原始帧 | JSON |
工作模式说明:工作模式不再手动配置,系统根据轮询任务自动推导:有已启用的轮询任务时为「主动轮询模式」,无轮询任务时为「MQTT 指令模式」。可在外设执行页面创建轮询触发器来切换。
配置完基础参数后需点击页面底部的「保存配置」按钮,然后重启设备使配置生效。
3. Modbus RTU 基础配置
3.1 主站运行状态栏
页面顶部状态栏实时显示 Modbus 主站运行指标,帮助用户快速评估总线健康状态:
| 指标 | 说明 |
|---|---|
| 风险等级 | 总线负载评估(LOW/MEDIUM/HIGH) |
| 启用任务 | 当前已启用的采集任务数 |
| 最小间隔 | 所有任务中最短轮询间隔 |
| 最近轮询 | 距离上次轮询的时间 |
| 超时率 | 超时次数占比,反映通信质量 |
| 总轮询/成功/失败/超时 | 累计通信统计 |
3.2 Modbus 子设备配置
在「Modbus 子设备」区域可以添加、编辑和删除子设备。每个子设备代表总线上的一个物理设备,支持四种类型:
| 设备类型 | deviceType | 说明 | 特有参数 |
|---|---|---|---|
| 继电器 | relay | 开关量控制(线圈/寄存器) | 批量寄存器、延时模式、NC 模式 |
| PWM | pwm | 占空比输出 | 寄存器基地址、分辨率(8/10/16 位) |
| PID | pid | 闭环控制 | PV/SV/OUT/P/I/D 寄存器地址、小数位 |
| 电机 | motor | 步进/伺服电机 | 正转/反转/停止/速度/脉冲寄存器、软限位 |
子设备通用参数:
| 字段 | 说明 |
|---|---|
| 名称 | 设备可读名称,用于控制面板显示 |
| 传感器 ID | 平台上报用的标识符(支持中文) |
| 从站地址 | Modbus 地址(1-247) |
| 通道数 | 设备的通道/路数 |
| 线圈/寄存器基地址 | 控制命令的起始地址 |
| 控制协议 | 0=线圈(FC01/FC05),1=寄存器(FC03/FC06) |
| 批量寄存器 | 批量控制地址(0=不使用),支持位图/命令两种类型 |
继电器类子设备还支持延时模式(FC05 闪开 / 软件延时 / 硬件寄存器延时)和 NC 常闭模式配置。PWM 子设备需要配置寄存器基地址和分辨率(8/10/16 位)。PID 子设备需要配置 6 个寄存器地址(PV、SV、OUT、P、I、D)和小数位数。电机子设备需要配置 5 个寄存器地址(正转、反转、停止、速度、脉冲),支持位置软限位(最小/最大位置)和默认移动步数。
3.3 寄存器映射配置
每个轮询任务可以配置多个寄存器映射,将原始寄存器值转换为有意义的传感器数据:
| 字段 | 说明 | 范围/默认值 |
|---|---|---|
| regOffset | 寄存器偏移量(相对于任务起始地址) | 0 至 quantity-1 |
| dataType | 数据类型 | 0=uint16, 1=int16, 2=uint32, 3=int32, 4=float32 |
| scaleFactor | 缩放因子(原始值 × scaleFactor = 最终值) | 默认 1.0 |
| decimalPlaces | 小数位数(JSON 格式化用) | 默认 1 |
| sensorId | 传感器标识符(平台上报用) | 自定义文本 |
| unit | 显示单位(°C、%RH、ppm 等) | 自定义文本 |
配置寄存器映射时,需对照设备手册确定每个寄存器对应的传感器物理量,然后选择正确的数据类型和字节序,最后设置缩放因子和小数位数以确保上报值的精度。
3.4 轮询任务高级特性
- 死区过滤:可设置死区百分比(如 0.5 表示 0.5%),当寄存器原始值变化幅度小于死区阈值时不上报,减少 MQTT 消息量。设为 0 则禁用死区,每次轮询都上报。
- 心跳上报:即使数据持续不变,系统每 60 秒仍会强制上报一次最新值,确保平台数据不会因长时间无变化而被判定为离线。
- 自适应间隔:连续通信错误时,系统自动逐步延长轮询间隔以降低总线负载;恢复正常后立即回到原始间隔。连续无变化时也会适当延长间隔,优化总线利用率。
3.5 配置示例:protocol.json
以下是典型的 Modbus RTU 配置文件结构(保存在 /config/protocol.json):
{
"version": 2,
"modbusRtu": {
"enabled": true,
"peripheralId": "modbus_rtu",
"mode": "master",
"dePin": 14,
"transferType": 0,
"master": {
"responseTimeout": 1000,
"maxRetries": 2,
"interPollDelay": 100,
"tasks": [
{
"name": "温湿度采集",
"slaveAddress": 1,
"functionCode": 3,
"startAddress": 0,
"quantity": 4,
"pollInterval": 10,
"enabled": true,
"deadband": 0.5,
"mappings": [
{ "regOffset": 0, "dataType": 1, "scaleFactor": 0.1, "decimalPlaces": 1, "sensorId": "temperature", "unit": "°C" },
{ "regOffset": 1, "dataType": 1, "scaleFactor": 0.1, "decimalPlaces": 1, "sensorId": "humidity", "unit": "%RH" }
]
}
],
"devices": [
{
"name": "4路继电器",
"deviceType": "relay",
"slaveAddress": 2,
"channelCount": 4,
"coilBase": 0,
"controlProtocol": 1,
"batchRegister": 52,
"delayMode": 2,
"enabled": true
}
]
}
}
}4. 传感器状态与子设备管理
启用 Modbus RTU 并完成子设备配置后,页面会展示传感器实时状态和子设备管理列表,方便查看数据采集情况和管理子设备。

4.1 传感器状态卡片
页面顶部以卡片形式展示所有已映射传感器的实时数据:
| 信息项 | 说明 |
|---|---|
| 传感器名称 | 如 temperature、humidity、pm25 等 |
| 当前数值 | 最新采集值(经过映射和缩放后的实际值) |
| 状态标签 | 正常(绿色):数据正常更新;等待(灰色):尚未采集到数据 |
| 更新时间 | 距离上次数据更新的时长(如 2m 表示 2 分钟前) |
提示:传感器状态卡片仅显示已配置寄存器映射的采集点位。未映射的传感器显示
--和「等待」状态,待轮询成功后自动刷新。
4.2 子设备列表
子设备列表统一管理所有采集设备和控制设备,操作按钮包括「+ 添加设备」和「刷新」。
列表字段说明
| 列名 | 说明 |
|---|---|
| 名称 | 子设备名称,如「温湿度」「PM25-10」「气象百叶箱」 |
| 类型 | 采集(轮询任务)或 控制(子设备) |
| 从站地址 | Modbus 从站地址(1-247) |
| 设备信息 | 功能码 + 起始地址 + 寄存器数量 + 映射数,如 FC04 @0 x2 [2映射] |
| 启用 | 是否启用该子设备(开关切换) |
| 操作 | 编辑 / 映射 / 删除(采集设备)或 编辑 / 控制 / 删除(控制设备) |
设备信息字段格式
设备信息列以紧凑格式显示设备的关键参数:
FC04 @0 x2 [2映射] → 功能码04, 起始地址0, 2个寄存器, 2个映射
FC03 @500 x8 [6映射] → 功能码03, 起始地址500, 8个寄存器, 6个映射操作说明
- 编辑:打开设备编辑弹窗,修改名称、从站地址、功能码、起始地址、寄存器数量等参数
- 映射:打开寄存器映射弹窗,配置每个寄存器的传感器名称、数据类型、缩放因子等(详见 3.3 寄存器映射配置)
- 控制:打开设备控制弹窗(仅控制设备显示),进行继电器开关、PWM 调节等操作
- 删除:移除该子设备及其关联配置
- + 添加设备:添加新的采集设备或控制设备
- 刷新:手动刷新子设备列表和传感器状态
5. REST API 参考
所有 API 需要登录认证(Bearer Token 或 Session Cookie)。
REST API 章节建议配合这张图阅读:线圈类接口对应 Coils 数据区,寄存器读写接口对应 Holding/Input Registers,设备参数和专有命令可能走私有帧或特定功能码。
5.1 线圈控制 API
POST /api/modbus/coil/control — 单个线圈控制
权限:config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| channel | int | 是 | 通道号 (0-based) |
| coilBase | int | 否 | 线圈基地址,默认 0 |
| action | string | 否 | on/off/toggle,默认 toggle |
toggle 操作说明:使用设备原生翻转指令(FC 0x05, 值 0x5500),然后回读状态。
成功响应:
{
"success": true,
"data": {
"channel": 0,
"coilAddress": 0,
"state": true,
"action": "toggle"
}
}POST /api/modbus/coil/batch — 批量线圈控制
权限:config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| channelCount | int | 是 | 通道数量 (1-32) |
| coilBase | int | 否 | 线圈基地址,默认 0 |
| action | string | 是 | allOn/allOff/allToggle |
allToggle 操作说明:使用设备原生全翻转指令(FC 0x05, 地址=coilBase, 值 0x5A00),然后回读状态。
成功响应:
{
"success": true,
"data": {
"channelCount": 8,
"action": "allOn",
"states": [true, true, true, true, true, true, true, true]
}
}POST /api/modbus/coil/delay — 闪开延时控制
权限:config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| channel | int | 是 | 通道号 (0-based) |
| delayBase | int | 否 | 延时地址基址,默认 0x0200 (512) |
| delayUnits | int | 是 | 延时值 (1-255),单位 x100ms |
| delayMode | int | 否 | 0=FC05闪开(默认), 1=软件延时, 2=硬件寄存器延时 |
| ncMode | bool | 否 | NC常闭模式 |
| coilBase | int | 否 | 线圈基地址 |
| mode | string | 否 | coil/register,控制模式 |
delayMode=0(默认):使用 FC 0x05 闪开指令(继电器板专有),地址=delayBase+channel,值=delayUnits<<8。
delayMode=1:软件延时,先写ON,ESP32软件定时器到期后写OFF。
delayMode=2:硬件寄存器延时,向通道寄存器写入值>1,设备自动延时(N-1)×0.01s后翻转。适用于中盛科技等支持寄存器延时翻转的模块。
当设备配置了
delayMode=2时,API 自动使用硬件寄存器延时模式,无需手动指定 delayMode 参数。
成功响应:
{
"success": true,
"data": {
"channel": 3,
"delayAddress": 515,
"delayUnits": 50,
"delayMs": 5000
}
}说明:
- 实际 Modbus 地址 =
delayBase + channel(如 0x0200 + 3 = 0x0203) - 实际写入值 =
delayUnits << 8(如 50 → 0x3200) - 硬件延时由继电器板执行,ESP32 仅发送指令
GET /api/modbus/coil/status — 查询线圈状态
权限:config.view 或 config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| channelCount | int | 否 | 通道数量,默认 8 |
| coilBase | int | 否 | 线圈基地址,默认 0 |
成功响应:
{
"success": true,
"data": {
"channelCount": 8,
"coilBase": 0,
"states": [false, true, false, false, true, false, false, false]
}
}5.2 设备参数 API
POST /api/modbus/device/address — 读取/设置从站地址
权限:config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 当前从站地址(读取/写入时均使用广播 0x00) |
| addressRegister | int | 否 | 地址寄存器,默认 0 (0x0000) |
| newAddress | int | 否 | 新地址 (1-255)。不填则为读取,填则为设置 |
读取说明:通过广播地址 0x00 发送 FC 0x03 读取地址寄存器。
设置说明:通过广播地址 0x00 发送 FC 0x10 写入新地址到地址寄存器。
读取响应:
{
"success": true,
"data": { "currentAddress": 1, "register": 0 }
}设置响应:
{
"success": true,
"data": { "previousAddress": 1, "newAddress": 5, "register": 0 }
}POST /api/modbus/device/baudrate — 设置波特率
权限:config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| baudRate | int | 是 | 波特率 |
| mode | int | 否 | 0=FC 0xB0专有(默认), 1=FC06写寄存器 |
| baudRateReg | int | 否 | FC06模式波特率寄存器地址(默认0x0033) |
| baudCode | int | 否 | 直接指定波特率编码值 |
mode=0(默认):使用 FC 0xB0 专有指令,帧格式 [SlaveAddr, 0xB0, 0x00, 0x00, BaudCode, 0x00, CRC]。波特率编码:0=1200, 1=2400, 2=4800, 3=9600, 4=19200, 5=115200。
mode=1:使用 FC 0x06 写保持寄存器(标准 Modbus,兼容中盛科技等品牌)。波特率编码:0=4800, 1=9600, 2=14400, 3=19200, 4=38400, 5=56000, 6=57600, 7=115200。
当设备配置了
baudRateMode=1时,API 自动使用 FC06 寄存器模式,无需手动指定 mode 参数。
成功响应:
{
"success": true,
"data": { "baudRate": 9600, "baudCode": 1, "mode": "register", "register": 51 }
}GET /api/modbus/device/inputs — 读取离散输入
权限:config.view 或 config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| inputCount | int | 否 | 输入数量,默认 4 |
| inputBase | int | 否 | 输入基地址,默认 0 |
成功响应:
{
"success": true,
"data": {
"inputCount": 4,
"inputBase": 0,
"states": [false, true, false, true]
}
}5.3 通用寄存器与状态 API
GET /api/modbus/status — 获取 Modbus 运行状态
权限:config.view
返回当前 Modbus 模式、通信统计、任务概览等信息(500ms 内部缓存)。常用于 Web 面板实时状态显示。
成功响应(示例):
{
"success": true,
"data": {
"mode": "master",
"running": true,
"stats": { "txCount": 123, "rxCount": 120, "timeoutCount": 3 },
"tasks": [ /* 主站轮询任务运行态 */ ]
}
}POST /api/modbus/write — 队列写单个保持寄存器(FC 0x06,入队)
权限:config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| regAddress | int | 是 | 寄存器地址 |
| value | int | 是 | 写入值 (0-65535) |
与
/api/modbus/register/write区别:此接口将写请求入队(受 Modbus 调度器排程),适用于非阻塞的主站控制场景;后者走 one-shot 接口直接发送并等待应答。
成功响应:{"success": true, "message": "Write request queued"}
GET /api/modbus/register/read — 读保持/输入寄存器(one-shot)
权限:config.view 或 config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| startAddress | int | 是 | 起始寄存器地址 |
| quantity | int | 是 | 数量 (1-125) |
| functionCode | int | 否 | 3=Holding(默认)/ 4=Input |
成功响应:
{
"success": true,
"data": {
"count": 4,
"startAddress": 0,
"values": [100, 200, 0, 1]
}
}POST /api/modbus/register/write — 写单个保持寄存器(FC 0x06,one-shot)
权限:config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| registerAddress | int | 是 | 寄存器地址 |
| value | int | 是 | 写入值 (0-65535) |
写入成功后,若寄存器落在某个 Modbus 子设备的 coilBase 控制区间内,会自动发布 MQTT 控制上报。
成功响应:
{ "success": true, "data": { "register": 5, "value": 100 } }POST /api/modbus/register/batch-write — 批量写保持寄存器(FC 0x10)
权限:config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| startAddress | int | 是 | 起始寄存器地址 |
| values | string (JSON数组) | 是 | 要写入的值数组,如 "[100,200,300]",长度 1-125 |
成功响应:
{
"success": true,
"data": { "startAddress": 0, "quantity": 3, "values": [100,200,300] }
}5.4 电机控制 API
POST /api/modbus/motor/control — Modbus 电机控制(正反转/停止/调速/脉冲)
权限:config.edit
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slaveAddress | int | 是 | 从站地址 (1-247) |
| action | string | 是 | forward/reverse/stop/setSpeed/setPulse/readStatus |
| value | int | 否 | setSpeed/setPulse 时的写入值 |
| registers | string (JSON数组) | 否 | 覆盖默认寄存器映射 [forward, reverse, stop, speed, pulse](缺省为 [0x0000,0x0001,0x0002,0x0005,0x0007],兼容 YF-53 等) |
优先从设备配置的 motorRegs 读取寄存器映射;若设备未配置,则使用默认或 registers 参数覆盖。readStatus 会读取速度/脉冲寄存器区间用于前端面板状态刷新。
成功响应(forward 示例):
{
"success": true,
"data": { "action": "forward", "register": 0, "value": 1 }
}5.5 错误响应格式
所有 API 在操作失败时返回统一格式:
{
"success": false,
"error": "错误描述",
"errorCode": "TIMEOUT"
}错误码说明:
| errorCode | HTTP 状态码 | 说明 |
|---|---|---|
TIMEOUT | 504 | 从站无响应,检查线路和地址 |
CRC_ERROR | 502 | CRC 校验失败,可能线路干扰 |
EXCEPTION | 502 | 从站返回异常码(附 exceptionCode 字段) |
NOT_INITIALIZED | 503 | Modbus 未初始化或未启用 |
BUSY | 503 | 总线正忙(另一操作进行中),稍后重试 |
Modbus 异常码:
| exceptionCode | 含义 |
|---|---|
| 0x01 | Illegal function — 功能码不受支持 |
| 0x02 | Illegal data address — 地址不存在 |
| 0x03 | Illegal data value — 数据值非法 |
| 0x04 | Slave device failure — 从站内部故障 |
6. Modbus 功能码说明
6.1 FC 0x01 — Read Coils(读线圈)
- 用途:读取从站的线圈(DO 输出)状态
- 本面板使用场景:「刷新状态」、「自动刷新」、翻转操作后的状态回读
- 数据含义:每个线圈 1 bit,0=OFF,1=ON
6.2 FC 0x02 — Read Discrete Inputs(读离散输入)
- 用途:读取从站的数字输入(DI)状态
- 本面板使用场景:设备参数 > 离散输入 > 读取
- 数据含义:每个输入 1 bit,0=OFF,1=ON
6.3 FC 0x03 — Read Holding Registers(读保持寄存器)
- 用途:读取从站的保持寄存器值
- 本面板使用场景:广播读取设备地址(从站地址 0x00,寄存器 0x0000)
- 数据含义:每个寄存器 16 bit 无符号整数
6.4 FC 0x05 — Write Single Coil(写单线圈 / 原生指令载体)
- 用途:控制单个线圈开/关,同时作为继电器板原生指令的载体
- 本面板使用场景:
- 标准开/关:值 0xFF00 = ON,0x0000 = OFF
- 原生翻转:值 0x5500,发送到目标线圈地址,设备自动翻转状态
- 原生全翻转:值 0x5A00,发送到线圈基地址(地址 0),设备翻转所有通道
- 闪开延时:地址 = 0x0200 + 通道号,值 = (延时值 << 8),设备硬件定时开启后关闭
- 帧格式:
[SlaveAddr, 0x05, AddrH, AddrL, ValueH, ValueL, CRC]
6.5 FC 0x06 — Write Single Register(写单寄存器)
- 用途:写入单个保持寄存器
- 本面板使用场景:预留接口(当前 UI 未直接使用)
- 帧格式:
[SlaveAddr, 0x06, AddrH, AddrL, ValueH, ValueL, CRC]
6.6 FC 0x0F — Write Multiple Coils(写多线圈)
- 用途:一次性写入多个线圈
- 本面板使用场景:「全部开启」「全部关闭」
- 特点:一帧完成所有通道的写入,比逐个 FC 0x05 效率更高
6.7 FC 0x10 — Write Multiple Registers(写多寄存器)
- 用途:一次性写入多个保持寄存器
- 本面板使用场景:广播写入设备新地址(从站地址 0x00,寄存器 0x0000)
6.8 FC 0xB0 — Set Baud Rate(专有指令)
- 用途:修改继电器板从站的通信波特率
- 本面板使用场景:设备参数 > 波特率配置 > 设置
- 帧格式:
[SlaveAddr, 0xB0, 0x00, 0x00, BaudCode, 0x00, CRC] - 波特率编码:0=1200, 1=2400, 2=4800, 3=9600, 4=19200, 5=115200
- 说明:这是继电器板的专有指令,不属于标准 Modbus 协议。非此类设备可能不支持。
7. 典型使用场景
场景二:控制 8 路继电器模块
设备:国产通用型 Modbus RTU 8 路继电器板,地址 1,波特率 9600,线圈地址从 0 开始。
操作步骤:
- 确认 Modbus RTU 基础配置已保存并重启
- 在调试与控制面板中设置:
- 从站地址:
1 - 通道数:
8 - 线圈基地址:
0
- 从站地址:
- 点击「刷新状态」→ 网格显示 8 个通道当前状态
- 点击某个灰色的通道卡片 → 该继电器翻转吸合(变绿)
- 再次点击 → 继电器翻转断开(变灰)
场景三:走廊灯闪开延时
需求:按下开关后灯亮 5 秒自动熄灭。
操作步骤:
- 设置闪开延时控制区域:
- 选择目标通道(如 CH0)
- 延时值输入
50(50 x 100ms = 5 秒)
- 点击「启动延时」
- 结果:CH0 继电器立即吸合(灯亮),5 秒后由继电器板硬件自动断开(灯灭)
长延时示例:
- 需要 10 秒延时 → 输入
100 - 需要 20 秒延时 → 输入
200 - 最大 25.5 秒延时 → 输入
255
场景四:修改从站地址
需求:将设备地址修改为 5(不知道当前地址也可以操作)。
操作步骤:
- 展开「设备参数配置」
- 地址寄存器确认为
0(国产继电器板默认值) - 点击「读取」→ 下方显示
Current: 1(通过广播地址 0x00 读取,无需知道当前地址) - 「新地址」输入
5 - 点击「设置」→ 通过广播地址 0x00 + FC 0x10 写入,操作成功
- 立即将面板顶部「从站地址」改为
5
注意:广播读取/写入时,总线上只能连接一个从站设备。如果有多个设备,会导致通信冲突。
场景五:批量初始化
需求:一键关闭所有继电器(设备上电安全检查)。
操作步骤:
- 配置好连接参数
- 点击「全部关闭」按钮
- 网格中所有通道变为灰色
场景六:读取传感器 DI 状态
需求:查看 4 路数字输入传感器的当前状态。
操作步骤:
- 展开「设备参数配置」
- 输入数量:
4,输入基地址:0 - 点击「读取」
- 下方显示 IN0:ON IN1:OFF IN2:OFF IN3:ON 等状态标签
场景七:控制 4 路标准继电器模块(中盛科技等)
设备:标准 Modbus RTU 4路继电器模块(如中盛科技数字量输入输出系列),默认地址 1,波特率 38400,保持寄存器控制。
设备配置:
| 参数 | 值 | 说明 |
|---|---|---|
| 设备类型 | relay | 继电器 |
| 从站地址 | 1 | 默认地址 |
| 通道数 | 4 | 4路继电器 |
| 线圈基地址 | 0 | 寄存器从0开始 |
| 控制模式 | 寄存器模式 | FC03/FC06 |
| 批量寄存器 | 52 (0x0034) | 全开/全关寄存器 |
| 延时模式 | 2(硬件寄存器) | 设备内置延时功能 |
| 波特率模式 | 1(FC06寄存器) | 标准写寄存器配置波特率 |
| 波特率寄存器 | 51 (0x0033) | 波特率设置寄存器 |
| 地址寄存器 | 50 (0x0032) | 地址设置寄存器 |
保持寄存器功能定义:
| 协议地址 | PLC地址 | 功能描述 |
|---|---|---|
| 0x0000-0x0003 | 40001-40004 | 通道1-4控制(0=关, 1=开, >1=延时翻转) |
| 0x0030 | 40049 | 通讯检测时间(N×0.1秒) |
| 0x0031 | 40050 | 输入口状态主动上传控制 |
| 0x0032 | 40051 | RS485地址/站号(1-255) |
| 0x0033 | 40052 | 波特率设置 |
| 0x0034 | 40053 | 批量控制(0=全关, 1=全开) |
| 0x0035 | 40054 | 按位控制通道1-16 |
| 0x003D | 40062 | 奇偶校验设置(0=无, 1=奇, 2=偶) |
| 0x0096-0x0099 | 40151-40154 | 通道1-4控制模式设置 |
波特率编码映射(寄存器 0x0033):
| 编码值 | 波特率 |
|---|---|
| 0 | 4800 |
| 1 | 9600 |
| 2 | 14400 |
| 3 | 19200 |
| 4 | 38400(出厂默认) |
| 5 | 56000 |
| 6 | 57600 |
| 7 | 115200 |
硬件寄存器延时:
向通道寄存器写入值 > 1,设备自动延时 (N-1)×0.01秒后翻转:
- 写 1:立即开启
- 写 0:立即关闭
- 写 501:延时 (501-1)×0.01 = 5秒后翻转
- 写 1001:延时 (1001-1)×0.01 = 10秒后翻转
操作步骤:
- 在外设管理中将 Modbus RTU 波特率修改为 38400(设备出厂默认)
- 保存配置并重启 ESP32
- 在设备控制页面可看到「4路继电器」控制面板
- 点击继电器卡片即可开关控制
- 延时控制:选择通道和延时值,点击「启动延时」,设备硬件定时自动关闭
8. 常见问题与故障排除
Q1:点击线圈卡片后提示「操作失败」
可能原因及排查:
| 检查项 | 排查方法 |
|---|---|
| 从站地址错误 | 使用广播读取地址功能确认设备实际地址 |
| 线路连接问题 | 检查 TX/RX 接线,RS485 A+/B- 是否接反 |
| 波特率不匹配 | ESP32 外设配置的波特率需与从站一致 |
| DE 引脚配置 | RS485 模块需正确配置 DE 引脚号 |
| 设备未上电 | 确认从站设备电源正常 |
| Modbus 未初始化 | 检查是否已保存 RTU 配置并重启 ESP32 |
| 设备不支持 0x5500 | 非国产通用继电器板可能不支持原生翻转指令 |
Q2:状态读取正常但无法控制(写操作失败)
可能原因:
- 从站设备线圈为只读(部分设备的状态线圈不可写)
- 线圈地址不正确(某些设备线圈地址不从 0 开始)
- 从站返回异常码 0x02(地址非法),检查设备手册中线圈地址范围
Q3:提示「Modbus busy, try again」
原因:另一个 Modbus 操作正在进行中(如轮询任务、其他 API 请求)。
解决:稍等 1-2 秒后重试。总线是半双工的,一次只能执行一个操作。
Q4:闪开延时不生效
可能原因:
- 设备不支持闪开功能(非国产通用继电器板)→ 查看设备手册确认是否支持 0x0200 地址段
- 延时值超出范围(必须 1-255)→ UI 已限制,API 调用时注意
- 通道号错误 → 确认通道号在 0 到(通道数-1)范围内
Q5:自动刷新不工作
排查:
- 确认复选框已勾选
- 检查浏览器控制台是否有 JS 错误
- 确认 Modbus 不处于频繁 BUSY 状态
Q6:波特率修改后设备无响应
原因:从站波特率已改变(通过 FC 0xB0 专有指令),但 ESP32 侧仍使用旧波特率。
解决:
- 在外设管理中修改 UART 外设的波特率为新值
- 保存 Modbus RTU 配置
- 重启 ESP32
Q7:通道数选择 16 或 32 后,读取状态很慢
原因:FC 0x01 读取多线圈需要更长的通信时间,且从站处理也更慢。
建议:仅选择设备实际的通道数,避免读取不存在的线圈导致错误或延迟。
Q8:广播读取地址时返回错误
可能原因:
- 总线上连接了多个从站设备 → 广播操作时只能连接一个设备
- 设备不支持广播地址 0x00 → 非国产通用继电器板可能不支持
- 线路问题导致响应丢失
9. 技术规格与限制
系统限制
| 项目 | 限制 |
|---|---|
| 最大通道数 | 32(单次写入线圈上限) |
| 闪开延时范围 | 1 - 255(x100ms,即 100ms - 25.5s) |
| 从站地址范围 | 1 - 255(控制操作),0x00(广播读写地址) |
| 线圈/寄存器地址范围 | 0 - 65535 |
| 自动刷新间隔 | 固定 3 秒 |
| API 并发限制 | Modbus 总线同一时刻仅支持一个操作 |
设备原生指令汇总
| 指令 | FC | 地址 | 值 | 说明 |
|---|---|---|---|---|
| 单通道翻转 | 0x05 | 线圈地址 | 0x5500 | 硬件翻转指定通道 |
| 全通道翻转 | 0x05 | 线圈基地址 | 0x5A00 | 硬件翻转所有通道 |
| 闪开延时 | 0x05 | 0x0200+ch | (delay<<8) | 硬件延时开启后自动关闭 |
| 读取地址 | 0x03 | 0x0000 | - | 广播(0x00)读取设备地址 |
| 设置地址 | 0x10 | 0x0000 | 新地址 | 广播(0x00)写入新地址 |
| 设置波特率 | 0xB0 | - | BaudCode | 专有指令修改波特率 |
通信参数
| 参数 | 说明 |
|---|---|
| 协议 | Modbus RTU (串行二进制) |
| 校验 | CRC-16/Modbus |
| 默认超时 | 1000ms(可配置) |
| 默认重试 | 2 次(可配置) |
| 帧间延迟 | 5ms(可配置) |
国际化支持
精简版默认使用中文界面并移除语言切换入口,以减少首屏资源和运行时加载压力;完整版可保留多语言资源。
浏览器兼容性
支持所有现代浏览器(Chrome、Firefox、Edge、Safari),推荐使用 Chrome 系浏览器获得最佳体验。
相关文档
- Modbus 子设备外设 — 外设类型配置与 GPIO 分配
- Modbus 动作 — 外设执行规则中的 Modbus 动作配置
- Modbus 监控场景 — 使用外设执行实现自动监控
- 外设执行配置指南 — 轮询触发器与控制规则详解
附录
附录 A:Modbus RTU 帧结构
帧结构排查建议结合前文的"Modbus RTU 寄存器映射地图":先确认从站地址和功能码,再确认 Addr 字段是否使用协议地址。很多继电器板手册会把 00001、40001 当作人类可读地址,实际 RTU 帧中对应地址可能是 0x0000。
请求帧(Master -> Slave)
| 从站地址 | 功能码 | 数据区 | CRC低 | CRC高 |
| 1 byte | 1 byte | N bytes| 1 byte| 1 byte|正常响应帧(Slave -> Master)
| 从站地址 | 功能码 | 数据区 | CRC低 | CRC高 |
| 1 byte | 1 byte | N bytes| 1 byte| 1 byte|异常响应帧(Slave -> Master)
| 从站地址 | 功能码+0x80 | 异常码 | CRC低 | CRC高 |
| 1 byte | 1 byte | 1 byte | 1 byte| 1 byte|附录 B:继电器板原生指令帧示例
翻转通道 3(从站地址 1)
请求:01 05 00 03 55 00 [CRC]
响应:01 05 00 03 55 00 [CRC]翻转所有通道(从站地址 1)
请求:01 05 00 00 5A 00 [CRC]
响应:01 05 00 00 5A 00 [CRC]闪开通道 2,延时 5 秒(从站地址 1)
请求:01 05 02 02 32 00 [CRC]
│ │ │ │ │ └─ 低字节 0x00
│ │ │ │ └──── 高字节 0x32 (50 x 100ms = 5s)
│ │ │ └─────── 通道 2
│ │ └────────── 0x02 (延时地址高字节)
│ └───────────── FC 0x05
└──────────────── 从站地址 1广播读取设备地址
请求:00 03 00 00 00 01 [CRC]
响应:00 03 02 00 01 [CRC] → 地址 = 1广播设置新地址为 5
请求:00 10 00 00 00 01 02 00 05 [CRC]
响应:00 10 00 00 00 01 [CRC]修改波特率为 9600(从站地址 1)
请求:01 B0 00 00 03 00 [CRC]
│ │ │ │ │ └─ 固定 0x00
│ │ │ │ └──── 编码 3 = 9600
│ │ │ └─────── 固定 0x00
│ │ └────────── 固定 0x00
│ └───────────── FC 0xB0
└──────────────── 从站地址 1附录 C:快速检查清单
开始使用前,请逐项确认:
