关键发现: - 两个 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 标志位, 不会因主循环阻塞丢失
5.2 KiB
5.2 KiB
最坏情况:活动上报 + 继电器翻转 对线圈检测的影响
场景:变化量持续活跃 (150ms 上报) + 车辆进出触发继电器翻转 (即时上报) 波特率:115200 (Modbus 默认)
1. 为什么两个 TX 不会背靠背?
modbus_report_schedule() 的结构:
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。