# 参考项目代码分析 > 分析对象:M1H(STC12C5202 / C)和 TLD-110(P87LPC762 / ASM) > 目的:为 DLD154V4B(AT32F421)提供算法参考 --- # 一、项目概览 | 项目 | MCU | 语言 | 通道 | 年份 | 代码量 | |------|-----|------|------|------|--------| | M1H | STC12C5202 (8051) | C | 1 路 | 2008 | 379 行 | | TLD-110 | P87LPC762 (8051) | ASM | 1~2 路 | 2003~2006 | 1563 行 | **共同点:** - 都基于 8051 架构 - 都使用线圈 LC 谐振频率偏移检测车辆 - 都通过 DIP 开关设置灵敏度 - 都输出继电器信号 --- # 二、M1H 分析 ## 2.1 整体数据流 ``` 线圈振荡 → PCA捕获(CCAP0) → 周期差值(Xn) │ ┌───────────────┴────────────────┐ ▼ (初始化) ▼ (正常运行) 累加 Xn 测一个完整周期 累加 Xn 满 LPCNT 次 LPCNT = 32768 / Xn Value = ΣXn Origin = ΣXn (首窗口) │ │ ▼ │ IIR 低通滤波 │ CAPVD = α·Value + (1-α)·CAPVD │ α = 79/256 │ │ └─────────┬───────────────────────┘ ▼ ┌─── 有车? ───┐ ▼ 无车 ▼ 有车 慢速基线跟踪 ┌──进入检测──┐ ORG_SUM += CAPVD │ │ 每100次平均→Origin ▼ 进入 ▼ 离开 CAPVD < CAPVD > Origin-阈值 Origin-恢复阈值 ``` ## 2.2 频率测量 (CAP0 ISR) ``` 捕获中断触发 ├─ 读 CCAP0H:L → CapThis (16bit 捕获值) ├─ 首次中断: CapLast = CapThis, 置 RF_FLAG └─ 后续中断: ├─ Xn = CapThis - CapLast (相邻边沿周期差) ├─ CapLast = CapThis └─ 累加 Xn → CapSum, 计数 CapCnt ``` **测量窗口自适应:** - 初始化阶段:等 CapCnt > 10 后,`LPCNT = 32768 / Xn` - LPCNT 含义:每 LPCNT 次捕获产生一个 Value(约 1 秒的积分窗口) - Xn 大(频率低) → LPCNT 小 → 测量快 - Xn 小(频率高) → LPCNT 大 → 测量更精确 ## 2.3 IIR 滤波 (VD1_TASK) ```c if (Value > CAPVD) CAPVD = CAPVD + ((Value - CAPVD) * 79) >> 8; else CAPVD = CAPVD - ((CAPVD - Value) * 79) >> 8; ``` 等效公式:**CAPVD_new = 0.3086 × Value + 0.6914 × CAPVD_old** - 响应速度:约 3~4 次更新达到 63% - 对单个野值有良好抑制 ## 2.4 检测算法 ### 灵敏度表 | DIP (SA1,SA0) | SENS | 进入阈值(比例) | 离开阈值(比例) | |---------------|------|---------------|---------------| | 00 | 3 (最高灵敏) | 10/65536 ≈ 0.015% | 9/65536 ≈ 0.014% | | 01 | 2 | 36/65536 ≈ 0.055% | 18/65536 ≈ 0.027% | | 10 | 1 | 108/65536 ≈ 0.16% | 72/65536 ≈ 0.11% | | 11 | 0 (最低灵敏) | 216/65536 ≈ 0.33% | 108/65536 ≈ 0.16% | > 注:DIP 拨到 ON = 1,SENS = 3 - (sw & 0x03) ### 进入判据 ``` dlt_ORG = (Origin × SensTable[SENS]) >> 16 IF CAPVD < Origin - dlt_ORG: 有车! ``` ### 离开判据(滞回) ``` dlt_ORG = (Origin × SensTable1[SENS]) >> 16 // 约为进入阈值的 50% IF CAPVD > Origin - dlt_ORG: 无车! ``` ### 基线跟踪(仅无车时) ```c ORG_SUM += CAPVD; if (++ORG_CNT == 100) { Origin = ORG_SUM / 100; // 每 100 次平均更新 ORG_CNT = 0; ORG_SUM = 0; } ``` ## 2.5 时序状态机 (Timer1 ISR, 50ms tick) ``` IN_DELAY=10 OUT_DELAY=38 [空闲] ──有车──→ [进入延时] ──超时──→ [有车确认] ↑ │ │ 车辆离开 │ ↓ └──脉冲结束──── [脉冲输出] ←──超时── [离开延时] PLUSE_DELAY=19 ``` | 参数 | 值 | 时间 | |------|-----|------| | IN_DELAY | 10 | 500ms (进入防抖) | | OUT_DELAY | 38 | 1.9s (离开防抖) | | PLUSE_DELAY | 19 | 950ms (脉冲宽度) | ## 2.6 拨码逻辑 ``` SA_1(PA0), SA_2(PA1) → 灵敏度 (4级) SW_3(PA2) → 0=存在输出, 1=脉冲输出 SW_4(PA3) → 0=无延时, 1=延时 SW_5(PA4) → 安全复位 ``` 拨码去抖:连续 5 次读取一致才生效。 ## 2.7 输出逻辑 ``` SOLA (继电器1) = VD_FLAG | FLAG_OUT (有车或有离开延时) SOLB (继电器2) = VD_FLAG | FLAG_OUT (SET_PLUS模式) FLAG_PULSE (非脉冲模式) ``` --- # 三、TLD-110 分析 ## 3.1 整体数据流 ``` 线圈振荡边沿 → EX0中断触发 │ ▼ Timer0定时 + Timer1计数 (门控频率测量法) │ ▼ 4次扫描取中值 (SUM - MAX - MIN) / 2 → SQ │ ┌───────────┴───────────┐ ▼ 初始化 ▼ 运行 频率范围校验 Δ = Q - SQ 32样本平均→Q基线 │ INI_T0校准 ├─ Δ>0 (频率↓): 可能来车 CAL_TH(阈值计算) │ ├─ Δ > TR: SET A_VD │ └─ Δ ≤ TR: 累加到APY │ 16次后更新Q基线 └─ Δ≤0 (频率↑): ├─ A_VD=1 且 Δ < TF: 离开 └─ A_VD=0: 正常 ``` ## 3.2 频率测量 (MAIN_VD → GET_VD) **门控频率测量法:** ``` 1. Timer0 装载 INI_T0,向下计数(门控时间 ≈ 50ms) 2. Timer1 清零,向上计数(对线圈脉冲计数) 3. 使能 EX0 外部中断 4. 线圈第一个上升沿 → EX0 ISR: 启动 TR0 + TR1 5. Timer0 溢出 → TF0 ISR: 停止 TR0 + TR1 6. 读 Timer1 的 TH1:TL1 → 脉冲计数 ``` **中值滤波(4 次采样):** - 记录 4 次测量的 SUM、MAX、MIN - 结果 = (SUM - MAX - MIN) / 2 → 相当于平均中间两个值 - 能有效剔除单个毛刺 ## 3.3 初始化流程 ``` 1. TEST_VD: 粗测频率 → 软件延时门控 2. 频率范围校验: - 下限: SQ > 0x0154 (频率不过低) - 上限: SQ < 0x0DF0 (频率不过高) - SQ = 0 → STATUS=1 (线圈断开) 3. 计算 INI_T0: INI_T0 = 0xFFFF - (0xC350 / SQ) → 使门控时间内计数值约为 3125 4. 32 个样本累加 → 右移 5 位 (/32) → 校准基线 Q - 校验: Q ≠ 0 (否则重新初始化) ``` ## 3.4 检测算法 ### 灵敏度表 | TAB_SENS | HEX | DEC | 说明 | |----------|-----|-----|------| | [0] | 0x46 | 70 | 最低灵敏度 | | [1] | 0x37 | 55 | | | [2] | 0x28 | 40 | | | [3] | 0x14 | 20 | 最高灵敏度 | ### 阈值计算 (CAL_TH_A) ``` 进入阈值 TR = Q × SensTable[SENS] / 100000 离开阈值 TF = Q × SensTable[SENS+1] / 100000 // 更严格 ``` 以 Q=100000 为例: | SENS | TR(进入) | TF(离开) | 说明 | |------|----------|----------|------| | 3 (高灵敏) | 20 → 0.02% | 下一档=70 → 0.07% | 离开更容易 | | 2 | 40 → 0.04% | 55 → 0.055% | | | 1 | 55 → 0.055% | 70 → 0.07% | | | 0 (低灵敏) | 70 → 0.07% | — | 最不灵敏 | ### 动态基线更新 (ADJ_A_QT) ``` 当 Δ≤TR (频率变化不跨阈值): 累加 SQ 到 APY (16次) 16次后: 如果无车、无输出、无延时: Q = APY_sum / 32 → 更新基线 否则: 不更新 APY清零 ``` > TLD-110 的基线更新比 M1H 更谨慎——有车时绝不更新基线。 ## 3.5 方向判别 (MODEL=200) ``` ATOB: A先有车 → B后有车 → 方向 A→B BTOA: B先有车 → A后有车 → 方向 B→A 触发条件: A_VD=1, B_VD=1 → 判断先后 - 如果先有 ATOB flag: 方向 A→B - 如果先有 BTOA flag: 方向 B→A ``` ## 3.6 输出模式 | MODE | 说明 | A_SOL | B_SOL | |------|------|-------|-------| | 0 | 存在输出 | OUT_A (离开延时后) | OUT_B | | 1 | 进入脉冲 | IN_A | IN_B | | 2 | 离开脉冲 | !IN_A & A_VD | !IN_B & B_VD | | 3 | 存在+LED | A_VD \| OUT_A | B_VD \| OUT_B | | 4 | 方向 A→B | ATOB | BTOA | | 5 | 方向+延时 | ATOB & IN_B | BTOA & IN_A | ## 3.7 故障指示 (FLASH_LED) 通过 LED 闪烁模式指示线圈状态: | STATUS | 故障 | LED 闪烁 | |--------|------|----------| | 0 | 正常 | 灭 | | 1 | 线圈断开(SQ=0) | 均匀闪烁 | | 2 | 频率过低 | 1-4-6-7 ON 短码 | | 3 | 频率过高 | 1-4-6-7-8-9 ON 长码 | --- # 四、两项目关键差异对比 | 特性 | M1H | TLD-110 | |------|-----|---------| | 频率测量 | PCA 周期捕获 | 门控脉冲计数 | | 滤波方式 | IIR 指数平滑 (α=0.31) | 4取中值 | | 基线跟踪 | 100次滑动平均(有车也跟踪) | 16次累积更新(有车不更新) | | 滞回 | 进入/离开用不同阈值表 | 进入/离开用相邻灵敏度档 | | 进入判断 | CAPVD < Origin - 阈值 | ΔQ > TR (delta超阈值) | | 防抖 | IN_DELAY=500ms, OUT_DELAY=1.9s | DELAY_VALUE=10或40 | | 方向判别 | 不支持 | 支持 (ATOB/BTOA) | | 故障检测 | 仅 LOOP_OK | 断开/过低/过高 3种 | --- # 五、DLD154V4B 建议采用的方案 综合两个参考项目的优点: ## 5.1 频率测量 使用 AT32F421 的 **TIM3_CH2 输入捕获**(硬件捕获),结合 DMA 或定时器溢出中断: ``` 方案:TIM3 自由运行计数 + CH2 捕获模式 - 每次捕获中断读取 CCR2 → 得到相邻边沿时间差 - 同 M1H:计算 Xn,累加 N 次产生 Value ``` ## 5.2 滤波 **级联滤波:** 1. 第一级:中值滤波(仿 TLD-110,4 取中值) 2. 第二级:IIR 指数平滑(仿 M1H,α 可配置) ## 5.3 检测 ``` 进入: CAPVD < Origin - Origin × SensTable[SENS] / 65536 离开: CAPVD > Origin - Origin × SensTable1[SENS] / 65536 ``` ## 5.4 基线跟踪 仿 TLD-110:**有车时冻结基线**,无车时慢速跟踪。 ``` if (!VD_FLAG) { ORG_SUM += CAPVD; if (++ORG_CNT >= 64) { Origin = ORG_SUM >> 6; // /64 ORG_CNT = 0; ORG_SUM = 0; } } ``` ## 5.5 时序 沿用 M1H 的 Timer 状态机模式(用 AT32F421 的 SysTick 或 TIM1): | 参数 | 默认值 | 说明 | |------|--------|------| | IN_DELAY | 10 tick | 进入防抖 | | OUT_DELAY | 38 tick | 离开防抖 | | PULSE_WIDTH | 19 tick | 脉冲输出宽度 | | HOLD_TIME | 不限 | 安全模式保持时间 | ## 5.6 灵敏度表 沿用 M1H 的 4 级: ```c const uint16_t SensTable[4] = {216, 108, 36, 10}; // 进入 const uint16_t SensTable1[4] = {108, 72, 18, 9}; // 离开(滞回) ``` --- # 修订记录 | 版本 | 时间 | 说明 | |------|------|------| | V1.00 | 2026-06-22 | 初版,M1H + TLD-110 完整分析 |