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 标志位, 不会因主循环阻塞丢失
This commit is contained in:
wangfq
2026-07-30 17:52:01 +08:00
parent 2142674c3e
commit 0be7af8aa3
+142
View File
@@ -0,0 +1,142 @@
# 最坏情况:活动上报 + 继电器翻转 对线圈检测的影响
> 场景:变化量持续活跃 (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。