380 lines
11 KiB
Markdown
380 lines
11 KiB
Markdown
# 参考项目代码分析
|
||
|
||
> 分析对象: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 完整分析 |
|