Files
DLD154V4B/docs/technical-spec.md
T

735 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DLD154V4B 技术规格书
> 单路线圈车辆检测器 | 固件版本: V2.6 | 文档版本: V2.1
> 本文档面向工程开发、系统集成及故障深度分析
---
## 1. 系统架构
### 1.1 硬件架构
```
┌──────────────────────────────────┐
线圈 ────────────┤ PA7 (TIM3_CH2) AT32F421F8P7 │
│ 输入捕获 Cortex-M4 ├──── PB1 (TMR14 PWM) ──── 红灯
│ 120MHz / 64KB │
DIP ×5 ─────────┤ PA0~PA4 (GPIO) ├──── PA9 (GPIO) ──────── 绿灯
│ │
Tx ─────────────┤ USART (TTL) ├──── PA10 (GPIO) ─────── 黄灯
│ │
│ PA5 (GPIO) ──┼──── RLY2 继电器
│ PA6 (GPIO) ──┼──── RLY1 继电器
│ │
│ SWD (PA13/PA14) ────────────────┼──── 调试接口
└──────────────────────────────────┘
```
### 1.2 软件架构
```
FreeRTOS Kernel (CMSIS-RTOS v2)
├── loop_task (主检测任务)
│ ├── vd1_task() — 每 ~10ms 执行 (M4 优化)
│ │ ├── IIR 滤波 (ALFA_CAP1=79/256, τ≈32ms)
│ │ ├── 斜率限幅 (MAX_SLOPE_RATE=5%)
│ │ ├── 基线跟踪 (500 窗口滑动平均, 5s)
│ │ ├── 进入确认 (ENTRY_CONFIRM=3 次)
│ │ ├── 离开检测 (cnt_release 防抖,平坦性 #if 可选)
│ │ ├── 时序状态机 (IN/OUT/PULSE/HOLD)
│ │ └── 冻结超时恢复 (10s + ±2% 稳定性检查)
│ ├── poll_sw_state() — 拨码去抖
│ ├── poll_green_led() — 绿灯驱动
│ └── poll_yellow_led() — 黄灯故障编码
├── TMR3_ISR() — 线圈频率捕获
├── TMR15_ISR() — 5ms 系统 tick (LED 驱动 + 看门狗活性计数)
├── TMR14_PWM() — 红灯呼吸
└── IWDT — 硬件看门狗 (超时≈1.64s, main 使能, 主循环 poll_wdg 喂狗)
```
---
## 2. 电气参数
| 参数 | 最小值 | 典型值 | 最大值 | 单位 | 备注 |
|------|--------|--------|--------|------|------|
| 供电电压 (VDD) | 10 | 12 / 24 | 30 | V | 宽压输入 |
| 功耗 | — | 0.5 | 2 | W | 含继电器吸合 |
| 工作温度 | -40 | — | +85 | °C | 工业级 |
| 存储温度 | -55 | — | +125 | °C | — |
| 线圈电感范围 | 50 | 200 | 1000 | μH | 超出范围可工作但精度下降 |
| 线圈频率范围 | 30 | 100 | 200 | kHz | — |
| 线圈 Q 值 | 5 | — | — | — | 过低导致振荡不稳定 |
| 继电器触点电压 | — | — | 250 | VAC | — |
| 继电器触点电流 | — | — | 3 | A | — |
| GPIO 输出电压 | 0 | 3.3 | 3.6 | V | CMOS 电平 |
| GPIO 输出电流 | — | — | 25 | mA | 单引脚最大 |
| ESD 防护 | ±2 | — | — | kV | HBM |
---
## 3. IO 引脚分配
### 3.1 完整引脚表
| 引脚 | 标识 | 功能 | 方向 | 外设 | 初始状态 | 备注 |
|------|------|------|------|------|---------|------|
| PA0 | SA_1 | 灵敏度 bit0 | IN | GPIO, 上拉 | — | DIP 开关 |
| PA1 | SA_2 | 灵敏度 bit1 | IN | GPIO, 上拉 | — | DIP 开关 |
| PA2 | SW_3 | 存在/脉冲选择 | IN | GPIO, 上拉 | — | 0=存在, 1=脉冲 |
| PA3 | SW_4 | 离开延时 | IN | GPIO, 上拉 | — | 0=无, 1=500ms |
| PA4 | SW_5 | 安全复位 | IN | GPIO, 上拉 | — | 1=复位 |
| PA5 | RLY2 | 继电器 2 | OUT | GPIO PP | 0 (开路) | 辅助输出 |
| PA6 | RLY1 | 继电器 1 | OUT | GPIO PP | 0 (开路) | 主输出 |
| **PA7** | **LP** | 线圈频率捕获 | IN | **TIM3_CH2** | — | **核心输入** |
| PA9 | LEDA | 绿灯 | OUT | GPIO PP | 0 (灭) | 有车/自检 |
| PA10 | LEDC | 黄灯 | OUT | GPIO PP | 0 (灭) | 故障诊断 |
| PB1 | LEDA_RED | 红灯 | ALT | TMR14_CH1 PWM | — | 呼吸灯 |
| PA13 | SWDIO | 调试数据 | I/O | SWD | — | 仅调试 |
| PA14 | SWCLK | 调试时钟 | IN | SWD | — | 仅调试 |
### 3.2 拨码开关逻辑
```c
// DIP 开关读取与解码
SENS = 3 - (sw & 0x03);
// SA_2:SA_1 = 11 → SENS = 0 (低灵敏)
// SA_2:SA_1 = 10 → SENS = 1
// SA_2:SA_1 = 01 → SENS = 2
// SA_2:SA_1 = 00 → SENS = 3 (最高灵敏)
SET_PLUS = (sw >> 2) & 0x01; // PA2 = SW_3
SET_DLY = (sw >> 3) & 0x01; // PA3 = SW_4
SET_SAFE = (sw >> 4) & 0x01; // PA4 = SW_5
```
**拨码去抖**:连续 5 次读取一致才生效(对齐 M1H 参考实现)。
---
## 4. 检测算法
### 4.1 频率测量
#### 4.1.1 硬件链路
DLD154V4B **不使用** CD4060 外部分频芯片。线圈直接驱动 PA7 (TIM3_CH2),利用 AT32F421 内置 TIM3 输入分频器 DIV_2 (÷2)。
| 对比项 | M1H/TLD-110 | DLD154V4B |
|--------|-------------|-----------|
| 外部分频 | CD4060 Pin5 (÷32) | **无(直连)** |
| MCU 内部分频 | 无 | TIM3 DIV_2 (÷2) |
| 总分频比 | ÷32 | **÷2** |
| 中断率 @100kHz | ~3.1k/s | **50k/s** |
| CPU 占用 @120MHz | — | < 3% |
#### 4.1.2 捕获流程
```
线圈边沿 → PA7 (TIM3_CH2)
TIM3 自由运行 (16-bit, 120MHz/DIV_2 = 60MHz 时钟)
└─ 每个边沿 → CH2 捕获 → 读 CCR2
TMR3 ISR:
CCR2_now → 存为 CapThis
Xn = CapThis - CapLast (相邻边沿周期差)
处理 16-bit 溢出: if (Xn & 0x8000) Xn += 0x10000
CapLast = CapThis
LPCNT = MEASUREMENT_BASE / Xn (自适应窗口)
CapSum += Xn
CapCnt++
CapCnt >= LPCNT ?
YES → Value = CapSum (≈ MEASUREMENT_BASE)
CapCnt = CapSum = 0
loop1_CAP_OK = 1 (通知 vd1_task)
```
#### 4.1.3 关键常量
```c
#define MEASUREMENT_BASE 131072 // 2^17
#define g_input_div 2 // TIM3 DIV_2
```
| 线圈频率 | Xn @DIV_2 | LPCNT | 测量窗口 | Value 范围 |
|---------|-----------|-------|---------|-----------|
| 50 kHz | 1200 | 109 | 2.2 ms | ~130800 |
| 100 kHz | 600 | 218 | 2.2 ms | ~130800 |
| 150 kHz | 400 | 328 | 2.2 ms | ~131200 |
| 200 kHz | 300 | 437 | 2.2 ms | ~131100 |
> **设计要点**:LPCNT 自适应使不同频率下 Value 归一化到 ~131072,百分比阈值(灵敏度)直接适用,无需频率补偿。
#### 4.1.4 精度陷阱(已修复)
旧代码存在 `<<6``>>6` 互相抵消的精度浪费:
```
旧: LPCNT = (32768 << 6) / Xn = 437 → 窗口 17.5ms
Value >>= 6 → 等效 7 样本精度
新: LPCNT = 131072 / Xn = 27~54 → 窗口 ~1ms
不做右移 → 全样本精度
```
**改进效果**:响应速度提升 16 倍,精度保留全部采样信息。
### 4.2 IIR 滤波(M4 优化:ALFA_CAP1=79 @10ms
V2.6 起采用单路 IIRALFA_CAP1=79 @10ms (τ≈32ms),比旧 50ms tick 的 τ≈162ms 快 5 倍:
```c
#define ALFA_CAP1 79 // IIR α = 79/256 ≈ 0.31 (@10ms → τ≈32ms)
// get_flt_value(): 通用一阶 IIR
CAPVD = (|Value - CAPVD| * ALFA_CAP1) >> 8 // 每 tick 移动 ~31%
```
| 参数 | 值 | 说明 |
|------|-----|------|
| α | 79/256 ≈ 0.31 | 指数平滑系数 |
| τ | ~32ms @10ms tick | 3 次更新达 63% |
| 噪声抑制 | 良好 | 单次野值影响 < 31% |
**进入确认**CAPVD 连续 ENTRY_CONFIRM=3 次低于阈值才判定有车。
```c
if (CAPVD < Origin - dlt_ORG) {
if (++entry_cnt >= 3)
VD_FLAG = 1; // 确认有车
} else {
entry_cnt = 0; // 恢复则重置
}
```
| 对比 | 8051/M1H 旧设计 | V2.6 |
|------|----------------|------|
| tick | 50ms | **10ms** |
| IIR α | 79/256 (@50ms, τ=162ms) | **79/256 (@10ms, τ=32ms)** |
| 确认方式 | 单次阈值 | **连续 3 次** |
| 瞬态抑制 | 无 | **斜率限幅 + 确认** |
| 进入响应 | ~550ms | **~530ms** |
### 4.3 检测判据
#### 4.3.1 灵敏度表
```c
const uint16_t SensTable[4] = {300, 60, 36, 20}; // 进入阈值 (V2.11: 0/1 档对齐 PD132T)
const uint16_t SensTable_1[4] = { 14, 14, 14, 14}; // 离开恒 14 (V2.11: 对齐 PD132T ASB=OFF 出厂默认)
```
| SENS | SensTable | 进入阈值 (×Origin/65536) | SensTable_1 | 离开阈值 (×Origin/65536) |
|------|-----------|-------------------------|-------------|-------------------------|
| 0 (低) | 300 | 0.46% | 14 | 0.021% |
| 1 | 60 | 0.09% | 14 | 0.021% |
| 2 | 36 | 0.055% | 14 | 0.021% |
| 3 (高) | 20 | 0.031% | 14 | 0.021% |
> ⚠ V2.82026-08-27):SENS=3 最高档进入阈值 10→200.015%→0.031% Δf/f,ΔL/L 0.031%→0.061%),离开 9→14(滞回 90%→70%)——现场广告杆落杆时最高档易误触发(落杆机械/电磁扰动越过 0.015% 阈值),提高阈值并加大滞回。
> ⚠ V2.112026-08-28):**PD132T 客户现场替换对齐**——① 进入 0/1 档 216/108 → **300/60**0.33%/0.16% → **0.46%/0.09%** Δf/f,对齐 PD132T SensTable {300,60,32,21} 的 0/1 档);② 离开表 {108,72,18,14} → **恒 14**0.021% Δf/f,对齐 PD132T 出厂默认 ASB=OFF 的恒 14 释放;若现场 PD132T ASB 拨码为 ON 则 PD132T 离开分档 {60,32,21,14},需改回分档)。2/3 档进入保持 V4B 优化值(与 PD132T 几乎一致)。
#### 4.3.2 进入检测(M4 优化:确认机制)
```c
// CAPVD 连续 ENTRY_CONFIRM 次低于阈值才判定有车
if (CAPVD < Origin - dlt_ORG) {
entry_cnt++;
if (entry_cnt >= ENTRY_CONFIRM) { // 3 次连续确认
VD_FLAG = 1; FLAG_IN = 1;
entry_cnt = 0;
}
} else {
if (entry_cnt > 0) entry_cnt = 0; // 恢复则重置
}
```
| 对比 | 8051/M1H 旧设计 | V2.6 M4 优化 |
|------|----------------|-------------|
| 判定依据 | CAPVD (α=79, τ=162ms) | **CAPVD (α=79, τ=32ms)** |
| 确认方式 | 单次阈值 | **连续 3 次确认** |
| 瞬态抑制 | 无 | **斜率限幅 + 确认双重保护** |
| 进入响应 | ~550ms | **~530ms** |
#### 4.3.3 离开检测(滞回)
##### 模式 1:简单防抖 (USE_FLATNESS_EXIT=0) — 默认(V2.9 起)
```c
dlt_ORG = (Origin * SensTable_1[SENS]) >> 16; // V2.11 起恒 14(对齐 PD132T 默认)
if ((Origin - dlt_ORG) < CAPVD) { // CAPVD 回升至距基线不足 dlt → 离开
if (++cnt_release >= 3) { // 连续 3 次确认
VD_FLAG = 0; FLAG_OUT = 1;
}
} else {
cnt_release = 0; // 回落立即重置
}
```
> **恒 14 设计依据(V2.11**:离开阈值恒 140.021% Δf/f)是对齐 PD132T **出厂默认(ASB=OFF** 行为——PD132T 出厂即"离开阈值固定、不随灵敏度档位变化"(`SET_ASB=OFF` 时强制 `SensTable1[3]`=14)。物理意义:进入需分档适配车型(大车/摩托车),离开判定本质是"频率恢复到接近基线"的二元事实,固定小阈值保证**任何档位下车走即释放、释放手感一致**。若现场 PD132T 的 ASB 拨码为 ON(离开分档 {60,32,21,14}),需将 `SensTable_1` 改回分档表对齐。
##### 模式 2:平坦性判定 (USE_FLATNESS_EXIT=1) — ⚠ 默认禁用(#if 0,代码保留)
基于专利 **CN200910309382**(中山大学),解决大车通行时频率多峰导致的多次误触发。
> ⚠ **2026-08-28 现场结论:平坦性算法实测不理想,默认关闭(USE_FLATNESS_EXIT=0**,离开判定切回简单 cnt_release 防抖(模式 1)。平坦性代码完整保留在 `#if USE_FLATNESS_EXIT` 内,可在 TaskLoop.h 一行开启,现场对比验证用。
**算法架构:**
```
车辆到达 → 单一阈值法 (沿用 SensTable)
▼ Phase 1: g_exit_state = 0 (追踪第一上升坡面)
│ 追踪最大 |f'| 和 |f''|
│ 当 |f'| 连续 3 次 < SLOPE_FLAT_THRESH:
│ Δ2 = max_slope / K1 (一阶平坦阈值)
│ Δ3 = max_slope_rate / K2 (二阶平坦阈值)
│ g_exit_state = 1
▼ Phase 2: g_exit_state = 1 (平坦性判定)
三条件同时满足:
① |f - f_b| < dlt_ORG (频率回归基频)
② |f'| < Δ2 (一阶导数近零)
③ |f''| < Δ3 (二阶导数近零)
连续 FLAT_CONFIRM_CNT(3) 次全部满足 → 车辆离开
```
**参数表:**
| 常量 | 值 | 含义 |
|------|-----|------|
| K1, K2 | 8 | 动态阈值除数(专利推荐值) |
| SLOPE_FLAT_THRESH | 100 | 斜率趋零判断阈值 |
| MIN_DELTA2 | 5 | Δ2 下限(防除数过小) |
| MIN_DELTA3 | 2 | Δ3 下限 |
| FLAT_CONFIRM_CNT | 3 | 平坦确认次数 |
**整数化适配:** 专利原实现用 floatHz 频率值),DLD154V4B 用 uint32 定点(Origin ≈ 131K)。导数计算用 int32 整数差分,阈值 /K1、/K2 做整数除法,精度足够。
### 4.4 基线跟踪(M4 优化:斜率限幅 + 冻结超时)
#### 4.4.1 斜率限幅
EMI/闪电等瞬态干扰会造成 CAPVD 瞬间跳变。物理车辆不可能让线圈频率瞬间改变 >5%:
```c
#define MAX_SLOPE_RATE 5 // 单次最大变化 5%
int32_t raw_delta = Value - CAPVD;
int32_t max_step = CAPVD * MAX_SLOPE_RATE / 100;
if (max_step < 100) max_step = 100; // 最小限幅,防止低 Origin 时锁死
if (raw_delta > max_step) raw_delta = max_step;
if (raw_delta < -max_step) raw_delta = -max_step;
uint32_t clamped_value = CAPVD + raw_delta;
CAPVD = get_flt_value(clamped_value, CAPVD); // 慢速 IIR
```
尖峰被截断,真实车辆信号(缓慢的频率漂移)不受影响。
#### 4.4.2 基线跟踪规则
```c
// 仅无车 + 无离开延时中 → 跟踪基线
if (!VD_FLAG) {
int32_t dev = CAPVD - Origin;
if (dev < dlt_ORG * 4) {
// CAPVD 未显著偏离 → 正常跟踪
loop1_freeze_cnt = 0;
update_moving_average(&ORG_SUM, &ORG_CNT, &Origin, CAPVD, 100);
} else {
// CAPVD 异常偏高 → 冻结 + 超时恢复逻辑
}
}
```
| 设计决策 | 原因 |
|---------|------|
| 有车时冻结基线 | 防止把车辆的影响"学"进基线(仿 TLD-110 |
| 100 窗口滑动平均 | 缓慢跟踪温漂,但不响应车辆 |
| 4× 冻结阈值 | 防止异常 CAPVD 上升污染基线(V1.5 |
| 5% 斜率限幅 | 过滤 EMI/闪电尖峰,保护 IIRV2.0 |
| 冻结超时 + 稳定性检查 | 防止永久冻结死锁(V2.3~2.5 |
#### 4.4.3 基线更新速率(两阶段)
| 阶段 | 窗口 | 周期 | 用途 |
|------|------|------|------|
| 稳定期 (`!g_loop_stable`) | 100 | **1s** | 绕过 IIR/限幅,快速收敛,开机即用 |
| 正常运行 | 500 (WINDOW_ORIGIN) | **5s** | 强噪声抑制,稳定跟踪 |
```
稳定期: CAPVD = Value (raw) → 100 样本 → Origin 快速建立
正常: CAPVD = IIR(Value, α=79) → 500 样本 → Origin 稳定跟踪
```
### 4.5 Origin 污染保护与冻结超时恢复(V1.5 → V2.5)
#### 4.5.1 问题演进
| 版本 | 问题 | 方案 | 遗留问题 |
|------|------|------|---------|
| V1.5 | 车辆驶入时 Xn 先增,Origin 被污染后无法释放 | 4×阈值冻结 | 环境变化时永久冻结,需复位 |
| V2.3 | 永久冻结导致死锁 | 冻结超时(30s 后强制更新) | 波动值也可能超时触发 |
| V2.4 | 波动值被误判为"新常态" | 稳定性检查(±2% 窗口) | — |
| V2.5 | 30s 等待太长 | 缩短到 10s | — |
#### 4.5.2 当前完整逻辑
```c
if (dev < dlt_ORG * 4) {
/* 正常范围 → 跟踪,清零冻结状态 */
loop1_freeze_cnt = 0;
update_moving_average(...);
} else {
/* 异常偏高 → 冻结 + 超时 + 稳定性验证 */
if (loop1_freeze_cnt == 0)
loop1_freeze_ref = CAPVD; // 记录冻结起始值
else if (|CAPVD - freeze_ref| > freeze_ref * FREEZE_STABILITY_RATE / 100)
reset(freeze_cnt, freeze_ref); // 波动 > ±2% → 重新计时
loop1_freeze_cnt++;
if (loop1_freeze_cnt >= FREEZE_TIMEOUT) { // 10s @ 10ms/tick
Origin = CAPVD; // 连续稳定 → 接受为新基线
}
}
```
#### 4.5.3 关键常量
| 常量 | 值 | 说明 |
|------|-----|------|
| 冻结触发阈值 | dlt_ORG × 4 | CAPVD 偏离 Origin 的倍数 |
| FREEZE_TIMEOUT | 1000 | ~10s @ 10ms/tick |
| FREEZE_STABILITY_RATE | 2 | 稳定性窗口:参考值的 ±2% |
| 基线窗口 | 100 | 滑动平均样本数(更新周期 ~1s) |
---
## 5. 时序状态机
### 5.1 状态转移
```
IN_DELAY=10 OUT_DELAY=10
[空闲] ──有车──→ [进入延时] ──超时──→ [有车确认]
↑ │
│ 车辆离开 (+ SW_4离开延时)
│ ↓
└──脉冲结束───── [脉冲输出] ←──超时── [离开延时]
PULSE_DELAY=10
```
### 5.2 时序参数
| 参数 | Tick (10ms) | 时间 | 说明 |
|------|------------|------|------|
| IN_DELAY | 50 | **500 ms** | 进入确认防抖(3 次 IIR 确认 + 500ms IN_DELAY |
| OUT_DELAY | 50 | **500 ms** | 离开防抖(仅 SW_4=ON 时生效,OFF 时为 0 |
| PULSE_DELAY | 50 | **500 ms** | 脉冲输出宽度 |
| HOLD_TIME | 5×1200 | **~5 min** | 有限存在超时 |
| LC_HOLD_TIME | 4×1200 | **~4 min** | 安全复位超时 |
| STABLE_SAMPLES | 128 tick | **~128 ms** | 上电稳定期 |
| FREEZE_TIMEOUT | 1000 | **~10 s** | 基线冻结超时(连续稳定后更新 Origin) |
> **M4 优化**V2.0 将 tick 从 50ms (TMR15 5ms×10) 提升到 10ms (vTaskDelay 10ms)。IIR 系数同步调整(α 从 79/256→18/256),保持等效时间常数。进入确认 3×10ms + 500ms IN_DELAY = ~530ms,比旧设计 (50ms + 500ms = 550ms) 略快。基线更新从 5s 加速到 1s。
### 5.3 系统 Tick 来源
TMR15 每 5ms 产生一次中断,`TM1cnt` 计数到 10 后触发 vd1_task50ms 周期)。TMR15 ISR 同时驱动 LED。
---
## 6. 指示灯状态机
### 6.1 三 LED 驱动架构
```
TMR15 ISR (每 5ms)
├── 红灯 PB1 — TMR14 PWM 呼吸(硬件自主,不需软件干预)
├── 绿灯 PA9 — poll_green_led() 每 tick 更新
└── 黄灯 PA10 — poll_yellow_led() 每 tick 更新
```
> **设计原则**:三 LED 由 TMR15 ISR 统一驱动,单点控制。vd1_task 只设标志位,ISR 据此刷新硬件。
### 6.2 绿灯行为表
```c
void poll_green_led(void) {
if (loop1_INI_LOOP || !g_loop_stable) {
// 自检 / 稳定期:慢闪 200ms
blink_200ms();
} else if (g_disconnect_active) {
// 当前断开中:强制灭
LEDA_OFF;
} else if (VD_FLAG || FLAG_IN || FLAG_OUT) {
// 有车 / 进入 / 离开延时中:亮
LEDA_ON;
} else {
// 无车:灭
LEDA_OFF;
}
}
```
### 6.3 黄灯行为表
| 条件 | 行为 | 参数 | 诊断含义 |
|------|------|------|---------|
| `g_disconnect_active == 1` | **快闪** | 200ms 亮 / 200ms 灭 | 线圈当前断开中 |
| `!g_loop_power_up_state` | **快闪** | 200ms 亮 / 200ms 灭 | 上电后从未连接线圈 |
| `g_disconnect_count == 1` | **1 短闪** | 80ms 亮 / 200ms 灭 → 1.2s 灭(循环) | 断开 1 次,已恢复 |
| `g_disconnect_count == 2` | **2 短闪** | 同上 | 断开 2 次 |
| `g_disconnect_count >= 3` | **3 短闪** | 同上 | 断开 3+ 次 |
| 正常 | **灭** | — | 一切正常 |
```c
void poll_yellow_led(void) {
if (g_disconnect_active || !g_loop_power_up_state)
fast_blink_200ms(); // 断开中快闪
else if (g_disconnect_count > 0)
n_short_flash(g_disconnect_count); // N 短闪编码
else
led_off(); // 正常
}
```
> **注意**:"上电后不接线,之后再接线圈"不计入断开次数(`g_loop_power_up_state` 控制)。只有已连接过的线圈断开才计入 `g_disconnect_count`。
---
## 7. 上电稳定期
### 7.1 背景
Origin 首次确立后,线圈振荡未真正稳定。立即启用检测容易误判为有车(绿灯常亮)。
### 7.2 实现
```c
#define STABLE_SAMPLES 128 // ~128ms
if (!g_loop_stable) {
// 仅跟踪基线,不检测车辆
update_moving_average(&ORG_SUM, &ORG_CNT, &Origin, CAPVD, 100);
if (++_stable_cnt >= STABLE_SAMPLES)
g_loop_stable = 1; // 稳定确认,正式启用检测
return; // 跳过进入/离开判断
}
```
稳定期间绿灯继续慢闪(`poll_green_led` 条件包含 `!g_loop_stable`)。
安全复位时 `loop1_LC_Reset` 重置 `g_loop_stable = 0`
---
## 8. 线圈重连逻辑
### 8.1 设计目标
断开时不丢 VD_FLAG(车辆仍在线圈上方),重连后快速收敛 IIR。
### 8.2 状态机
```
断开检测: loop1_RF_FLAG == 0 (没有收到边沿)
├─ loop1_LOOP_OK = 0
├─ g_disconnect_active = 1
├─ g_disconnect_count++ (≤3)
├─ 保留 loop1_VD_FLAG ← 关键:不丢有车状态
├─ 关断继电器输出
└─ 绿灯强制灭
重连检测: loop1_RF_FLAG == 1 (重新收到边沿)
├─ loop1_LOOP_OK = 1
├─ g_disconnect_active = 0
├─ loop1_CAPVD = 0 ← 触发快速收敛
└─ vd1_task: CAPVD == 0 → CAPVD = Value (直锁首个样本)
```
### 8.3 断开-重连场景矩阵
| 断开前 | 断开期间 | 重连后 | VD_FLAG | 绿灯 | 继电器 |
|--------|---------|--------|---------|------|--------|
| 有车 | 车仍在 | 车仍在 | 1 → 保持 | 恢复亮 | 恢复输出 |
| 有车 | 车离开 | 无车 | 1 → cnt_release→3 → 0 | 灭 | 释放 |
| 无车 | 车进入 | 有车 | 0 → CAPVD>Origin+dlt → 1 | 亮 | 吸合 |
---
## 9. 调试接口 (TTL Tx)
### 9.1 物理层
| 参数 | 值 |
|------|-----|
| 接口 | TTL 电平 UART Tx |
| 电平 | 3.3V CMOS |
| 波特率 | 9600(默认) |
| 数据位 | 8 |
| 停止位 | 1 |
| 校验 | 无 |
| 用途 | 调试信息输出(频率、状态、标志位) |
### 9.2 数据格式
> 调试输出内容待后续版本补充。当前版本可通过 TTL 串口输出检测状态和原始频率值,用于开发调试和现场调参。
---
## 10. 故障检测
### 10.1 检测项
| 检测项 | 判定条件 | 触发动作 |
|--------|---------|---------|
| 线圈断开 | `loop1_RF_FLAG == 0` 持续 | 黄灯快闪 / 继电器释放 |
| 线圈短路 | Xn 持续为 0 或极小 | 黄灯快闪 / 继电器释放 |
| 频率过低 | Value 持续 < MIN_FREQ | 黄灯编码闪烁 |
| 频率过高 | Value 持续 > MAX_FREQ | 黄灯编码闪烁 |
### 10.2 黄灯编码设计
断开次数编码提供了比 TLD-110 的均匀闪烁更丰富的诊断信息:
- **快闪=当前故障** → 现场立即处理
- **N短闪=历史故障** → 判断是偶发还是持续问题
---
## 11. 代码架构
### 11.1 目录结构
```
DLD154V4B/
├── utilities/at32f421_freertos_demo/
│ ├── src/
│ │ └── TaskLoop.c # 主检测逻辑 (~945 行 V2.5)
│ ├── inc/
│ │ └── TaskLoop.h # 全局变量和函数声明
│ └── ... # FreeRTOS + HAL 框架
├── docs/
│ ├── product-manual.md # 产品手册
│ ├── technical-spec.md # 本文档
│ ├── devlog.md # 开发日志
│ └── reference_analysis.md # M1H/TLD-110 参考分析
└── README.md
```
### 11.2 代码精简历程
| 版本 | 代码量 | 说明 |
|------|--------|------|
| 原始 | ~1177 行 | 包含二阶滤波、FltHistoryManager 等死代码 |
| V1.1 | ~706 行 | 精简重构,-40% |
| V1.5 | ~868 行 | 增加平坦性判定、污染保护 |
| V2.5 | ~945 行 | 增加双路 IIR、斜率限幅、进入确认、冻结超时+稳定性 |
**删除的死代码:**
- 二阶差分滤波(计算但从未参与判决)
- FltHistoryManager20+ 未用字段)
- StageRangeConfig(区间约束未引用)
- 动态窗口切换(LOOP_WINDOW_SIZE_LOW → FAST
- 中间层时序状态(PLUSE_IN_F / PLUSE_IN
---
## 12. 性能基准
### 12.1 检测性能
| 指标 | 值 | 说明 |
|------|-----|------|
| 进入检测延迟 | < 3 ms (测量) + 3×10ms (确认) + 500 ms (防抖) = **~530 ms** | M4 优化,比旧 550ms 略快 |
| 离开检测延迟 | < 3 ms (测量) + 3×10ms (防抖确认) + 500 ms (可选延时) | 滞回 + 3 次确认 |
| 误检率(单阈值) | — | 基准参考 |
| 误检率(防抖) | 滞回 + 3 次确认 | 瞬态干扰免疫(平坦性 #if 可选) |
| 频率分辨率 | < 0.01% | 取决于线圈 Q 值 |
| 温漂补偿 | 自动(100 窗口基线跟踪,更新周期 ~1s) | 仅无车时;冻结超时 10s |
| 瞬态抑制 | 5% 斜率限幅 + 3 次进入确认 | EMI/闪电免疫 |
### 12.2 CPU 占用
| 任务 | 频率 | CPU 占用 @120MHz | 说明 |
|------|------|-----------------|------|
| TMR3 ISR (捕获) | 50k/s @100kHz | ~2.1% | 每边沿约 50 周期 |
| TMR15 ISR (tick) | 200/s | < 1% | LED + 计数 |
| vd1_task | 100/s | < 1% | 滤波 + 检测(M4 10ms tick |
| FreeRTOS 开销 | — | < 1% | 任务调度 |
| **总计** | — | **< 5%** | 余量充足 |
### 12.3 RAM 占用
| 模块 | 大小 | 说明 |
|------|------|------|
| 全局检测变量 | ~100 B | 状态、计数、滤波值 |
| FreeRTOS 堆栈 | ~4 KB | 任务栈 + 系统堆 |
| 剩余 | ~11 KB | 可用于扩展功能 |
---
## 13. 编译选项
```c
// TaskLoop.h
#define USE_FLATNESS_EXIT 0 // 1 = 平坦性离开判定 (CN200910309382)
// 0 = 简单 cnt_release 防抖 (V2.9 默认)
// M4 优化参数
#define MAX_SLOPE_RATE 5 // 斜率限幅: 单次最大变化 5%
#define ENTRY_CONFIRM 3 // 进入确认: 连续 N 次低于阈值
#define FREEZE_TIMEOUT 1000 // 冻结超时: ~10s @ 10ms/tick
#define FREEZE_STABILITY_RATE 2 // 稳定性窗口: 参考值的 ±2%
// 看门狗参数 (IWDT, V2.10 新增)
#define WDT_COUNTER_LIMIT 100 // 喂狗周期 500ms (TMR15 5ms × 100)
#define WDT_DIV 2 // IWDT 分频枚举值: 2 = WDT_CLK_DIV_16 (实际分频 16, 勿传 16!)
#define WDT_RLD 4095 // 12bit 重装载 → 超时 ≈ 1.64s
```
### 13.1 看门狗机制(IWDTV2.10 新增)
AT32F421 独立看门狗(IWDT),双保险喂狗模式(对齐 DLD154Pro V3.03 方案):
| 环节 | 实现 |
|------|------|
| 使能 | `main()``wdt_init()`:分频 16(枚举 `WDT_CLK_DIV_16`)+ 重装载 4095 + 立即喂一次 |
| 超时 | ≈ 1.64sLSI≈40kHz`16×4096/40k` |
| 活性计数 | TMR15 ISR 每 5ms `g_wdg_counter++` |
| 喂狗 | 主循环每轮 `poll_wdg()`:计数达 100500ms)才 `wdt_counter_reload()` |
**双保险语义**
- TMR15 ISR 死 → 计数不涨 → 永不喂狗 → 1.64s 后复位
- 主循环死(阻塞/死循环不走喂狗点)→ poll_wdg 不执行 → 1.64s 后复位
- FreeRTOS 调度失败 / 任务创建失败 → 无人喂狗 → 复位(期望行为,避免"假活")
> ⚠ 喂狗周期 500ms 必须远小于超时 1.64s;修改 WDT_DIV/WDT_RLD 时保持 `喂狗周期 < 超时/2`。
---
## 14. 关键专利
| 专利号 | 名称 | 权利人 | 应用 |
|--------|------|--------|------|
| CN200910309382 | 一种防误检环形线圈车辆检测器 | 中山大学 张辉/黄永强/陈古典 | 平坦性三条件离开判定 |
DLD154V4B V1.4 起实现该专利的整数化版本,用于大车通行时的离开判定,有效抑制频率曲线多峰导致的多次误触发。**V2.9(2026-08-28)起默认关闭(现场实测不理想),代码保留在 `#if USE_FLATNESS_EXIT` 内可一行开启。**
---
## 15. 修订记录
| 版本 | 日期 | 说明 |
|------|------|------|
| V1.0 | 2026-06-24 | 技术规格书初版(V1.5 固件) |
| V2.0 | 2026-06-29 | 更新至 V2.5 固件:双路 IIR、斜率限幅、进入确认、冻结超时+稳定性 |
| V2.1 | 2026-06-29 | 更新至 V2.6:单路 IIR ALFA_CAP1=79, WINDOW_ORIGIN=500, 两阶段基线 |