分析结论 (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
250 lines
9.0 KiB
Markdown
250 lines
9.0 KiB
Markdown
# 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 (50–120 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` 是逐字节忙等的:
|
||
|
||
```c
|
||
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.3ms,BLE 连接超时 ≥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 baud**,TX 阻塞仅 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 字节后再等:
|
||
|
||
```c
|
||
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 独立,不丢边沿 |
|