Files
DLD154Pro/docs/modbus-tx-blocking-worst-case.md
T
wangfq 0be7af8aa3 docs: 活动上报+继电器翻转 最坏情况对线圈检测的影响分析
关键发现:
- 两个 TX 不会背靠背: relay flip TX 在入口处 return, 活动 TX 在下方
  必然间隔一次 cjq_srv (≥3ms)
- @115200: 总干扰窗口 11.6ms, CAP_OK 最多积压 1 次, 检测延迟 +16%
- @9600:  总干扰窗口 92ms, CAP_OK 积压 5 次, 检测延迟 +170% ← 不可接受
- loop1_CAP_OK 是 ISR 标志位, 不会因主循环阻塞丢失
2026-07-30 17:52:01 +08:00

143 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 最坏情况:活动上报 + 继电器翻转 对线圈检测的影响
> 场景:变化量持续活跃 (150ms 上报) + 车辆进出触发继电器翻转 (即时上报)
> 波特率:115200 (Modbus 默认)
---
## 1. 为什么两个 TX 不会背靠背?
`modbus_report_schedule()` 的结构:
```c
void modbus_report_schedule(void)
{
// ① 先检查继电器翻转 (入口判断)
if (relay != _last_relay_state) {
send_full_data(); // 4.3ms TX
return; // ← 立即返回,不往下走
}
// ② 再检查活动/空闲定时器
if (is_active() && elapsed >= 150ms) {
send_full_data(); // 4.3ms TX
// ← 返回后,函数继续到末尾,退出
}
}
```
**两个 `send_full_data()` 不在同一次 `modbus_poll` 调用中**。继电器翻转的 TX 在入口处拦截后直接 `return`,不会同时走活动上报路径。
---
## 2. 最坏情况时序
假设 t=0 时活动定时器到期,同时 TMR1 ISR 在 TX 期间翻转了继电器:
```
t=0.0 Main_Circulation:
cjq_srv() ← 正常处理 CAP_OK
opt_input_poll()
modbus_poll()
→ modbus_report_schedule()
→ relay 未翻转, 活动定时器到期
→ send_full_data() ─────────── TX 阻塞 4.3ms ─┐
t=1.5 [TMR1 ISR] relay 翻转 (cjq_srv 上次已判定进车) │ ISR 不受阻
t=4.3 TX 结束 ──────────────────────────────────────────┘
→ _rpt_last_ms = now, 函数返回
t=7.5 下一次 Main_Circulation (间隔 ~3ms):
TMOS_SystemProcess()
poll_dbn_ble()
cjq_srv() ← 处理中间的 CAP_OK (最多积压 1 次)
opt_input_poll()
modbus_poll()
→ modbus_report_schedule()
→ relay != _last_relay_state ← 翻转被检测到
→ update_misc_time() ← 算车间距/通过时间
→ send_full_data() ─────────── TX 阻塞 4.3ms ─┐
t=11.8 TX 结束 ──────────────────────────────────────────┘
t=11.8+ 正常恢复
```
**关键**t=4.3 到 t=7.5 之间有 ~3ms 的正常主循环,`cjq_srv` 在这个窗口内运行。
---
## 3. 对线圈检测的量化影响
| 参数 | 值 | 说明 |
|------|-----|------|
| 单次 TX 阻塞 | **4.3 ms** | 115200, 43 字节 |
| 两次 TX 间隔 | **≥3 ms** | 主循环其他任务 (cjq_srv + opt + BLE) |
| 总干扰窗口 | **~11.6 ms** | 含中间的 3ms 正常处理 |
| CAP_OK 周期 | **8.74 ms** | 测量窗长度 |
| 最多积压 CAP_OK | **1 次** | 11.6ms ÷ 8.74ms = 1.3 |
| cjq_srv 处理机会 | **窗口中间有 1 次** | 两次 TX 之间 |
### 3.1 检测延迟
```
正常路径: CAP_OK → cjq_srv(立即) → 判定进出车
阻塞路径: CAP_OK → 等待 ≤4.3ms → cjq_srv → 判定进出车
额外延迟: ≤4.3ms
```
进出车检测本身需要 **3 次连续确认 ≈ 26ms**ENTRY_CONFIRM=3 × 8.74ms)。
4.3ms 额外延迟 / 26ms 确认窗口 = **+16%**。
### 3.2 会丢边沿吗?
**不会。** CAP_OK 是 TMR0 ISR 置位的标志位,`cjq_srv``if(loop1_CAP_OK)` 检测。TX 阻塞期间 ISR 照常运行,标志位被置起,TX 结束后 `cjq_srv` 立即处理。
---
## 4. 极限压测:连续进出车
假设车辆快速连续进出(罕见,需要车长极短或车速极高):
```
进车检测 → relay ON → TX(4.3ms) → gap(3ms) → 出车检测 → relay OFF → TX(4.3ms)
↑ ↑ ↑
cjq_srv判定 cjq_srv正常处理 cjq_srv判定
```
每次继电器翻转触发一次 4.3ms TX。两次 TX 之间有 ≥3ms 的 cjq_srv 窗口。
| 连续翻转次数 | 总 TX 阻塞 | CAP_OK 总延迟 | 影响 |
|-------------|-----------|--------------|------|
| 1 次 | 4.3ms | +4.3ms | 可忽略 |
| 2 次 (一进一出) | 8.6ms | +8.6ms | 可忽略 |
| 5 次/秒 | 21.5ms/s | 平均 +4.3ms/次 | 🟢 |
---
## 5. 与 9600 波特率的对比
| | @9600 | @115200 |
|--|-------|---------|
| 单次 TX | **44.8ms** | **4.3ms** |
| 两次 TX 间隔 | ~3ms | ~3ms |
| 总干扰窗口 | **~92ms** | **~11.6ms** |
| CAP_OK 积压 | **5 次** | **1 次** |
| cjq_srv 处理机会 | **TX 之间有 1 次** | TX 之间有 1 次 |
| 进出车额外延迟 | +45ms (+170%) | **+4.3ms (+16%)** |
> @9600 下两次 TX 占满 92ms`cjq_srv` 只在中间的 3ms 跑了一次,算法面临 5 个 CAP_OK 的积压。@115200 下仅 1 次积压。
---
## 6. 结论
**@115200,活动上报 + 继电器翻转叠加场景下,线圈检测完全不受实质影响。**
- 单次 TX 4.3ms < CAP_OK 周期 8.74ms → 不会跨测量窗积压
- 两次 TX 必然间隔一次 cjq_srv → 算法不中断
- 进出车额外延迟 +4.3ms,相对于 26ms 确认窗口仅 +16%
- `loop1_CAP_OK` 是 ISR 置位的标志位,不会因主循环阻塞而丢失
**如果波特率降到 9600,情况完全不同**——单次 TX 45ms 会积压 5 个 CAP_OK,进出车额外延迟 +170%。这就是为什么 Modbus 默认必须用 115200。