Files
DLD154Pro/docs/modbus-active-report-analysis.md
T
wangfq 2142674c3e refactor: Modbus 默认波特率 115200 + 资源分析重评估
分析结论 (115200 vs 9600):
- TX 阻塞: 4.3ms (曾 44.8ms) → 活动态 CPU 仅 +2.9%
- 主循环延迟 < 半个测量窗, 不影响线圈检测/光耦/BLE
- 从"临界可用"变为"完全充裕"

固件修复:
- rs485_init: 硬编码 RS485_BAUD → 使用 g_storage_uart_baud (flash 可配)
- 协议文档: Modbus 默认 115200
- DLD154Tool: 串口默认 115200
2026-07-30 17:39:27 +08:00

9.0 KiB
Raw Blame History

DLD154Pro Modbus 主动上报 — MCU 资源占用分析

CH591R RISC-V @60MHz | 18KB RAM | BLE + 单路线圈 + RS485 700BS 默认 9600 baud | Modbus 默认 115200 baud


1. 系统并发任务概览

┌──────────────────────────────────────────────────────┐
│ ISR 层 (抢占式, 不受主循环阻塞影响)                    │
│                                                      │
│  TMR0 捕获 ISR  ──── 线圈频率测量 (每周期触发)        │
│  TMR1 5ms ISR    ──── 50ms tick / 继电器 / LED / PWM │
│  UART0 RX ISR    ──── RS485 接收缓冲                  │
│  BLE RF ISR      ──── 蓝牙链路层                      │
│                                                      │
├──────────────────────────────────────────────────────┤
│ 主循环 (round-robin, 被 rs485_send 阻塞时可暂停 45ms) │
│                                                      │
│  TMOS_SystemProcess()  ── BLE 协议栈调度              │
│  poll_dbn_ble()        ── BLE 数据收发                │
│  cjq_srv()             ── 线圈算法 / 进出车检测        │
│  opt_input_poll()      ── 光耦防抖 / 状态机           │
│  modbus_poll()         ── Modbus 帧处理 + 主动上报 TX  │
└──────────────────────────────────────────────────────┘

关键事实: ISR 层永远不受 rs485_send 阻塞影响。线圈捕获/继电器输出/光耦消抖(TMR1 部分)在中断上下文运行,实时性有保证。


2. CPU 时间预算分析

2.1 中断负载 (固定开销,不可压缩)

中断源 频率 单次耗时 CPU 占比
TMR0 捕获 ~60 kHz (50120 kHz 线圈) ~25 cycles ~2.5%
TMR1 5ms 200 Hz ~200 cycles (含 PWM 呼吸) ~0.07%
UART0 RX 主机轮询时偶发 ~50 cycles 可忽略
BLE RF 连接维护 ~30ms 间隔 ~500 cycles ~0.03%
ISR 合计 ~2.6%

TMR0 捕获 ISR 是最重的固定负载。线圈频率越高,中断越密。

2.2 主循环 (正常状态,无主动上报 TX)

任务 单次耗时 说明
TMOS_SystemProcess ~1.5 ms BLE 协议栈 (底层在 ISR,这里是调度)
poll_dbn_ble ~0.5 ms 无待发数据时快速返回
cjq_srv ~1.0 ms CAP_OK 触发时跑 vd1_task (IIR+基线+检测)
opt_input_poll ~0.3 ms 3 样本多数表决 + 状态机分支
modbus_poll (RX only) ~0.1 ms 检查缓冲 + CRC 校验

主循环一次约 3.4 ms。两次 CAP_OK 间隔 ~8.74ms,主循环约跑 2.5 次/测量窗,时间充裕。

2.3 主动上报 TX 阻塞时间

rs485_send 是逐字节忙等的:

for (i = 0; i < len; i++) {
    while (R8_UART0_TFC != 0);  // ← 等 TX FIFO 全空 (→ 等上一个字节发完)
    R8_UART0_THR = data[i];     // 写 1 字节到 FIFO
}

UART0 TX FIFO 容量 8 字节,但代码不等 FIFO 有空间就写满 8 字节,而是每写 1 字节就等 FIFO 全空。这意味着每字节都经历完整的 1.04ms 传输等待。

帧类型 字节数 传输时间 @9600 (700BS) 传输时间 @115200 (Modbus)
全数据块上报 (FC 0x04) 43B 44.8 ms 4.3 ms
异常响应 5B 5.2 ms 0.5 ms
写回显 8B 8.3 ms 0.8 ms

2.4 主动上报各速率下的 CPU 占用

150ms 活动间隔:

每 150ms 窗口:
  TX 阻塞        4.3 ms  ← rs485_send(43B) @115200
  主循环正常计算  ~50 ms  ← 算法 + BLE + 光耦
  剩余预算       ~95 ms

主循环 CPU 占比: (4.3 + 50) / 150 = 36%
其中 TX 阻塞占比: 4.3 / 150 = 2.9%

800ms 空闲间隔:

TX 阻塞占比: 4.3 / 800 = 0.5%
主循环 CPU 占比: ~30%

继电器翻转事件 (立即上报):

TX 阻塞 4.3ms,单次冲击可忽略。

3. 关键风险点

3.1 主循环阻塞 4.3ms 期间的影响 (@115200)

rs485_send 阻塞仅 4.3ms,不到半个 CAP_OK 测量窗 (8.74ms)。

任务 影响 严重程度
cjq_srv (线圈算法) CAP_OK 最多积压 1 次。无实质延迟 🟢 无影响
opt_input_poll (光耦) 防抖采样暂停 4.3ms。光耦 3 样本防抖窗 ~30ms,不受影响 🟢 无影响
TMOS_SystemProcess (BLE) 延迟 4.3msBLE 连接超时 ≥2s 🟢 无影响
modbus_poll (RX) 主机命令响应延迟 +4.3ms 🟢 无影响

3.2 不受影响的部分

机制 原因
继电器输出 TMR1 ISR (5ms) 独立运行,不经过主循环
线圈频率测量 TMR0 捕获 ISR 独立运行
光耦复位 (模式 6) opt_input_poll 中的复位逻辑暂停 45ms,但 400ms 的复位门槛远大于阻塞时间
UART 接收 ISR 独立填充 _rx_buf

3.3 🟢 结论

@115200 波特率,主动上报对系统几乎无影响。 TX 阻塞仅 4.3ms(不到半个测量窗),主循环 CPU 占比从 30% 小幅升至 36%,余量充裕。不会丢检测事件,不会断蓝牙,继电器输出不受影响。


4. RAM 占用

4.1 新增静态变量 (BSS)

变量 大小 说明
_auto_rpt_enable 1B 主动上报使能标志
_active_threshold 2B 活动阈值
_rpt_last_ms 4B 上次上报时刻
_rpt_active / _rpt_hyst_cnt 2B 速率状态机
_last_relay_off_10ms 4B 继电器释放时刻
_last_relay_on_10ms 4B 继电器吸合时刻
_last_relay_state 1B 继电器边沿检测
_misc_time_type 2B 时间类型
_misc_time_value 4B 时间值 10ms
_relay_engage_cnt 4B 继电器累计次数
合计 28B

4.2 栈峰值

调用链 栈占用
modbus_poll() 局部变量 ~20B
send_full_data() 局部 buf[43] 43B
build_full_data() 局部 buf[38] + 临时变量 ~60B
rs485_send() 局部变量 ~10B
crc16() 局部变量 ~4B
调用链合计 ~140B

加中断嵌套预留 ~200B,栈峰值约 350B。CH591R 默认栈 2KB(可配置),余量充足。

4.3 总体 RAM

项目 大小
新增 BSS 28B
栈峰值增量 ~140B (Modbus 调用链)
CRC16 表 512B (const → Flash,不计 RAM)
RAM 增量 ~170B

CH591R 共 18KB RAM(含 BLE 协议栈 + 应用),Modbus 模块新增 < 1%。


5. Flash 占用

文件 大小
rs485_modbus.c ~8.5 KB
rs485_modbus.h ~2.2 KB
rs485_700bs.c 增量 (去 static) ~0
peripheral_main.c 增量 (分派) ~20B
合计 ~8.5 KB

CH591R Flash: 256KB (应用区 28KB 或 18KB,取决于 OTA 配置)。增量约占应用区 30%28KB 配置)或 47%18KB 配置)。18KB OTA 配置下偏紧


6. 优化建议

6.1 波特率选择 (已解决)

Modbus 默认使用 115200 baudTX 阻塞仅 4.3ms(2.9% CPU),不需要进一步优化。

波特率 TX 阻塞 (43B) 活动态 CPU 占比
9600 44.8 ms 30%
19200 22.4 ms 15%
115200 4.3 ms 2.9% ← Modbus 默认

700BS 保持 9600(协议兼容;心跳帧仅 9B,TX 阻塞 9.4ms,也不成问题)。

6.2 优化 TX FIFO 利用率 (代码级)

当前每字节等 FIFO 全空,改为填充 8 字节后再等:

void rs485_send_fast(const uint8_t *data, uint8_t len) {
    RS485_RE_TX();
    mDelayuS(100);
    uint8_t i = 0;
    while (i < len) {
        uint8_t space = 8 - R8_UART0_TFC;  // FIFO 剩余空间
        uint8_t chunk = (len - i < space) ? (len - i) : space;
        for (uint8_t j = 0; j < chunk; j++)
            R8_UART0_THR = data[i + j];
        i += chunk;
        if (i < len)
            while (R8_UART0_TFC >= 8);  // 等至少 1 字节空间
    }
    while (R8_UART0_TFC != 0);
    mDelayuS(500);
    RS485_RE_RX();
}

效果:不减少总 TX 时间(波特率决定),但减少忙等循环次数 43→6 次,降低指令开销。

6.3 活动上报间隔可调

当前硬编码 150ms/800ms。可考虑通过 HR 寄存器暴露间隔参数,让主机根据场景调优。


7. 总结

维度 评估 说明
实时性 安全 ISR 层不受 TX 阻塞影响;主循环延迟 4.3ms 可忽略
CPU 🟢 充裕 活动态 TX 阻塞仅 2.9%,主循环余量 >60%
RAM 🟢 充裕 增量 < 170B, < 1% 总 RAM
Flash 🟡 18KB OTA 配置偏紧 增量 ~8.5KB,占应用区 47%
BLE 🟢 安全 4.3ms 远小于连接超时 (≥2s)
线圈检测 🟢 安全 TMR0/TMR1 ISR 独立,不丢边沿