# 最坏情况:活动上报 + 继电器翻转 对线圈检测的影响 > 场景:变化量持续活跃 (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。