diff --git a/docs/rs485-modbus-protocol.md b/docs/rs485-modbus-protocol.md index af69e71..ff8201a 100644 --- a/docs/rs485-modbus-protocol.md +++ b/docs/rs485-modbus-protocol.md @@ -1,6 +1,6 @@ # DLD154Pro RS485 Modbus RTU 协议 -> 版本: V1.3 | 日期: 2026-07-29 | 状态: 定稿(待编码实现) +> 版本: V1.6 | 日期: 2026-07-30 | 状态: 定稿(待编码实现) > > 适用产品: DLD154Pro (CH591R, 单路线圈车检器) > @@ -86,6 +86,39 @@ | 0x000B | Condition | uint16 | 1 寄存器 | 环境活跃度 (0=安静, 1–100=嘈杂) | | 0x000C | DIP Virtual | uint16 | 1 寄存器 | 虚拟拨码(700BS 兼容): bit[7:4]=function_mode, bit[3:0]=fusion_mode | +### 3.2.1 全数据块 (Input Registers 0x0100+) — 功能码 0x04 + +> 可供主动上报和单次查询使用。一次读取 19 个寄存器获取设备完整快照。 + +| 地址 | 名称 | 类型 | 宽度 | 说明 | +|------|------|------|------|------| +| 0x0100 | Sensitivity | uint16 | 1 | 灵敏度等级 (0=低, 1=中低, 2=中高, 3=高) | +| 0x0101 | Freq Level | uint16 | 1 | 频率档位 (0=高频, 1=低频) | +| 0x0102 | Fusion Mode | uint16 | 1 | 输出融合模式 (0=或, 1=混行, 2=ETC, 3=且, 4=仅地感, 5=仅光耦, 6=复位) | +| 0x0103 | Car State | uint16 | 1 | 有车状态 (0=无车, 1=有车) | +| 0x0104 | Loop Status | uint16 | 1 | bit0=线圈断开(1=故障), bit1=基线稳定(1=就绪) | +| 0x0105 | Opto Status | uint16 | 1 | 光耦输入状态 (0=无效/高电平, 1=有效/低电平) | +| 0x0106 | Loop Freq Hi | uint16 | **2** | 线圈振荡频率 (Hz),高 16 位 | +| 0x0107 | Loop Freq Lo | uint16 | | 线圈振荡频率,低 16 位 | +| 0x0108 | CAPVD Hi | uint16 | **2** | 归一化周期值 (32-bit),高 16 位 | +| 0x0109 | CAPVD Lo | uint16 | | 归一化周期值,低 16 位 | +| 0x010A | Variation Hi | int16 | **2** | 变化量 = CAPVD − Origin (32-bit 有符号),高 16 位 | +| 0x010B | Variation Lo | int16 | | 变化量,低 16 位 | +| 0x010C | Cut Cnt Hi | uint16 | **2** | 线圈断开累计次数 (32-bit, 上电清零),高 16 位 | +| 0x010D | Cut Cnt Lo | uint16 | | 线圈断开累计次数,低 16 位 | +| 0x010E | Relay Cnt Hi | uint16 | **2** | 继电器吸合累计次数 (32-bit, 上电清零),高 16 位 | +| 0x010F | Relay Cnt Lo | uint16 | | 继电器吸合累计次数,低 16 位 | +| 0x0110 | Time Type | uint16 | 1 | 时间值类型: 0=车间距(间隙), 1=通过时间; 无有效值时 0xFFFF | +| 0x0111 | Misc Time Hi | uint16 | **2** | 时间值 (10ms 单位, 32-bit),高 16 位 | +| 0x0112 | Misc Time Lo | uint16 | | 时间值,低 16 位 | + +> **时间类型说明**: +> - **车间距 (Time Type=0)**:从上次继电器释放到本次继电器吸合的时间。当 `car_state` 从 0→1(上升沿)时更新。 +> - **通过时间 (Time Type=1)**:从继电器吸合到继电器释放的时间。当 `car_state` 从 1→0(下降沿)时更新。 +> - 上述两个值写入同一对寄存器 (0x0111–0x0112),`Time Type` 指示当前存储的是哪种。 + +> **32-bit 计数器回绕**:`Cut Cnt` 和 `Relay Cnt` 为 32-bit 无符号整数,最大值 4,294,967,295,上电清零。日常使用不会溢出。 + > **32-bit 值换算**: > - 频率:`freq_hz = (reg[0x0000] << 16) | reg[0x0001]`,单位 Hz。典型空线圈 50–120kHz。 > - CAPVD:`capvd = (reg[0x0002] << 16) | reg[0x0003]`,归一化到 `MEASUREMENT_BASE = 524288`。 @@ -108,6 +141,8 @@ | 0x0009 | BT Timeout | 0–255 | 0 | R/W | 蓝牙空闲关闭超时 (分钟), 0=不关闭 | | 0x000A | Safe Timeout | 0–255 | 0 | R/W | 安全模式超时 (×10s), 0=关闭 | | 0x000B | Opto Func | 0–1 | 0 | **R** | 光耦功能: 0=雷达输入, 1=复位 | +| 0x0010 | Auto Rpt Enable | 0–1 | 0 | R/W | 全数据主动上报: 0=关闭, 1=使能(见 §4.9) | +| 0x0011 | Active Thr | 0–65535 | 10 | R/W | 活动状态阈值: |Variation| ≥ 该值时进入活动上报速率 (150ms) | | 0x00FE | Init Flag Clear | 0–1 | — | **W** | 写 1 清零 Init Flag (DI 0x0008) | | 0x00FF | Device Reset | — | — | **W** | 写入 `0x5A5A` 触发复位初始化线圈(等效 700BS 0x2C) | @@ -202,6 +237,61 @@ <<< 01 06 00 FE 00 01 xx xx (Init Flag → 0) ``` +### 4.9 全数据块查询 — 读 IR 0x0100 起 19 个寄存器 + +一次读取设备完整快照(灵敏度/频率档/融合模式/车辆状态/光耦/频率/CAPVD/Variation/断开次数/继电器次数/时间): + +``` +>>> 01 04 01 00 00 13 B1 FA (从机1, 读 0x0100, 19 个寄存器) +<<< 01 04 26 + 00 01 ← Sensitivity = 1 (中低) + 00 00 ← Freq Level = 0 (高频) + 00 04 ← Fusion Mode = 4 (仅地感) + 00 01 ← Car State = 1 (有车) + 00 02 ← Loop Status = 0x0002 (bit1: 基线稳定) + 00 00 ← Opto Status = 0 (光耦无效) + 00 01 38 80 ← Freq = 80000 Hz + 00 07 FF C8 ← CAPVD = 524200 + 00 00 00 58 ← Variation = +88 (频率降低, 有车) + 00 00 00 03 ← Cut Cnt = 3 (累计断开 3 次) + 00 00 00 7B ← Relay Cnt = 123 (累计吸合 123 次) + 00 01 ← Time Type = 1 (通过时间) + 00 00 03 84 ← Misc Time = 900 (900×10ms = 9s) + XX XX +``` + +> 解析:灵敏度中低,高频档,仅地感模式,当前有车且基线稳定,频率 80kHz,CAPVD=524200,变化量 +88,断开过 3 次线圈,继电器已动作 123 次,最近一次通过时间 9 秒。 + +### 4.10 使能/关闭主动上报 — 写 HR 0x0010 + +``` +>>> 01 06 00 10 00 01 C8 1B (写 0x0010=1, 使能主动上报) +<<< 01 06 00 10 00 01 C8 1B +``` + +关闭: +``` +>>> 01 06 00 10 00 00 88 1A (写 0x0010=0, 关闭) +<<< 01 06 00 10 00 00 88 1A +``` + +### 4.11 设置活动阈值 — 写 HR 0x0011 + +``` +>>> 01 06 00 11 00 14 59 D9 (写 0x0011=20, |Variation|≥20 → 活动上报) +<<< 01 06 00 11 00 14 59 D9 +``` + +### 4.12 主动上报帧格式 + +当 `Auto Rpt Enable=1` 时,设备自发发送全数据块。帧格式与 §4.9 的响应完全一致: + +``` + 04 26 <38 bytes data, same as 0x0100-0x0112 big-endian> +``` + +主机接收时无需区分——无论是轮询响应还是主动推送,数据格式和寄存器映射完全相同。 + --- ## 5. 功能码支持矩阵 @@ -217,6 +307,9 @@ | 0x0F | Write Multiple Coils | ✗ | 不使用 | | 0x10 | Write Multiple Registers | ✓ | 批量写参数 | | 0x11 | Report Slave ID | ✓ | 返回设备型号 + 运行状态 | +| N/A | **Active Push** | ✓ | 主动上报全数据块(格式同 FC 0x04 响应),需 HR 0x0010=1 使能 | + +> **主动上报**:非标准 Modbus 功能。设备在 `Auto Rpt Enable=1` 时根据变化量阈值自动调速发送数据帧,帧格式与 FC 0x04 读 0x0100 起 19 个寄存器的响应一致。总线上的其他从机在上报期间保持静默,主机需在接收逻辑中处理非请求响应。 --- @@ -299,6 +392,55 @@ reg[1] = (uint16_t)(capvd & 0xFFFF); RS485 半双工时序:发送最后一字节后等待 **1 字节时间** 再切换 RE 为接收, 避免 RE 过早翻转导致最后一个字节被截断。 +### 6.7 主动上报机制 + +#### 使能条件 + +`Auto Rpt Enable` (HR 0x0010) = 1 时,设备自动按速率调度发送全数据块(§3.2.1 的 0x0100–0x0112)。默认关闭(0)。 + +#### 上报速率 + +| 状态 | 条件 | 上报间隔 | 说明 | +|------|------|---------|------| +| **事件** | 继电器状态翻转(吸合↔释放) | **立即** | 最高优先级,不等待间隔 | +| **活动** | \|Variation\| ≥ Active Thr (HR 0x0011) | **150ms** | 车辆进出或干扰期间快速跟踪 | +| **空闲** | \|Variation\| < Active Thr | **800ms** | 无车或稳定时的慢速心跳 | + +#### 速率切换 + +设备在每个上报间隔结束时评估当前状态,决定下一个间隔: +- 继电器翻转事件 → 立即发送,重置计时器 → 按变化量重新判断进入活动/空闲间隔 +- 活动态连续 \|Variation\| < 阈值满 2 个间隔 → 降速到空闲 800ms +- 空闲态一旦 \|Variation\| ≥ 阈值 → 立即升速到活动 150ms + +#### 车间距 / 通过时间测量 + +设备内部跟踪两个 tick 计数器(10ms 单位): + +``` +last_relay_off_tick — 上次继电器释放的时刻 +last_relay_on_tick — 上次继电器吸合的时刻 +``` + +- 继电器吸合沿 → `Misc Time = now − last_relay_off_tick`, `Time Type = 0`(车间距) +- 继电器释放沿 → `Misc Time = now − last_relay_on_tick`, `Time Type = 1`(通过时间) +- 上电后首次事件前,`Time Type = 0xFFFF`,`Misc Time = 0` + +**注意**:车间距/通过时间写入全数据块的 0x0110–0x0112,主动上报或轮询时一并读出。 + +#### 总线仲裁 + +主动上报期间,设备在发送数据前监听总线(检测 RX 是否有数据),仅在总线空闲时发送。若与主机轮询冲突(极低概率,因为主机需准备接收),以主机轮询优先——设备检测到冲突后推迟上报至下一个间隔。 + +#### 与 700BS 主动上报的对照 + +| 特性 | 700BS 主动上报 | Modbus 主动上报 (本扩展) | +|------|---------------|------------------------| +| 心跳间隔 | 5s 空闲 / 1s 故障 / 事件立即 | 800ms 空闲 / 150ms 活动 / 事件立即 | +| 触发条件 | 固定时间 + 故障状态 | 变化量阈值动态调速 | +| 数据格式 | 0xAA 自定义帧 | FC 0x04 响应格式 (与轮询一致) | +| 主机兼容 | 700BS 主机原生支持 | 需 Modbus 主机适配非请求响应 | + --- ## 7. 700BS 协议兼容对照 @@ -316,11 +458,11 @@ DLD154Pro RS485 同时支持 700BS 协议(`g_fm_700bs_disable=0`)和 Modbus | 0xAA 心跳 Init_B | A1=首次 | **DI 0x0008 Init Flag** | ✅ V1.2 新增 | | 0xAA 心跳 Fre_Err | bit0=下限异常 | **DI 0x0006 Freq Low Fault** | ✅ V1.2 新增 | | | bit4=上限异常 | **DI 0x0007 Freq High Fault** | ✅ V1.2 新增 | -| 0xAA 心跳 主动上报 | 5s/1s/事件 | — | ⚠️ Modbus 主从架构不支持 push,上位机周期性轮询 DI+IR 等价 | +| 0xAA 心跳 主动上报 | 5s/1s/事件 | — | ✅ V1.6: Modbus 新增主动上报 (FC 0x04 响应格式, 800ms/150ms/事件立即) | > **主动上报限制**:Modbus RTU 为严格主从协议,从机不能主动发送数据。 -> 700BS 的心跳/事件上报在 Modbus 模式下不可用。需上位机以 >=1s 周期轮询 DI 0x0000–01 -> 并通过边沿检测模拟事件触发。 +> V1.6 起通过私有扩展实现主动上报(需 `Auto Rpt Enable=1`),帧格式与 FC 0x04 响应一致。 +> 主机需适配非请求响应的接收逻辑。关闭主动上报后,仍可通过轮询 DI+IR 等价获取状态。 --- @@ -328,6 +470,7 @@ DLD154Pro RS485 同时支持 700BS 协议(`g_fm_700bs_disable=0`)和 Modbus | 版本 | 日期 | 作者 | 变更 | |------|------|------|------| +| V1.6 | 2026-07-30 | wangfq | 新增主动上报 & 全数据块: +IR 0x0100–0x0112 全数据块(19 reg, 含灵敏度/频率/融合模式/car_state/线圈/光耦/频率/CAPVD/Variation/断开计数/继电器计数/通过时间); +HR 0x0010 上报使能, +HR 0x0011 活动阈值; +§4.9–4.12 命令示例; +§6.7 主动上报机制(3 级速率: 空闲800ms/活动150ms/事件立即); 车间距/通过时间(10ms单位); 700BS 对照表更新 | | V1.5 | 2026-07-30 | wangfq | 枚举再次重排: 且后移 (0=或,1=混行,2=ETC,3=且,4=仅地感,5=仅光耦,6=复位); 模式号引用同步更新 | | V1.4 | 2026-07-29 | wangfq | 枚举重排: 融合模式值重新分配 (0=或,1=且,2=混行,3=ETC,4=仅地感,5=仅光耦,6=复位); 默认融合模式 0→4(仅地感); 修正所有示例和说明文本 | | V1.3 | 2026-07-29 | wangfq | 修正: 灵敏度档位 3→4 (范围 0–3, 默认 1); MEASUREMENT_BASE 131072→524288; Origin 窗口 100→500; 融合模式 5/6 待定义→已实现+状态机; 命令示例数值对齐实际硬件; 700BS 标注为已完成; 版本号 FW 3.00→3.01 |