- devlog: 新增 V2.6 架构简化章节 + 两阶段基线策略 - release-notes: V2.5→V2.6, 更新 M4 优化表(双路→单路 IIR) - product-manual: V2.5→V2.6 + 版本历史 - technical-spec: §4.2 重写为单路 IIR ALFA_CAP1=79 @10ms, §4.3.2 去除 CAPVD_fast 引用, §4.4.3 两阶段基线表, §15 新增 V2.1 修订记录
703 lines
24 KiB
Markdown
703 lines
24 KiB
Markdown
# 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)
|
||
│ │ ├── 时序状态机 (IN/OUT/PULSE/HOLD)
|
||
│ │ └── 冻结超时恢复 (10s + ±2% 稳定性检查)
|
||
│ ├── poll_sw_state() — 拨码去抖
|
||
│ ├── poll_green_led() — 绿灯驱动
|
||
│ └── poll_yellow_led() — 黄灯故障编码
|
||
├── TMR3_ISR() — 线圈频率捕获
|
||
├── TMR15_ISR() — 5ms 系统 tick (LED 驱动)
|
||
└── TMR14_PWM() — 红灯呼吸
|
||
```
|
||
|
||
---
|
||
|
||
## 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 起采用单路 IIR,ALFA_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] = {216, 108, 36, 10}; // 进入阈值
|
||
const uint16_t SensTable_1[4] = {108, 72, 18, 9}; // 离开阈值(滞回 ~50%)
|
||
```
|
||
|
||
| SENS | SensTable | 进入阈值 (×Origin/65536) | SensTable_1 | 离开阈值 (×Origin/65536) |
|
||
|------|-----------|-------------------------|-------------|-------------------------|
|
||
| 0 (低) | 216 | 0.33% | 108 | 0.16% |
|
||
| 1 | 108 | 0.16% | 72 | 0.11% |
|
||
| 2 | 36 | 0.055% | 18 | 0.027% |
|
||
| 3 (高) | 10 | 0.015% | 9 | 0.014% |
|
||
|
||
#### 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)
|
||
|
||
```c
|
||
dlt_ORG = (Origin * SensTable_1[SENS]) >> 16; // 更小的离开阈值
|
||
if (CAPVD < Origin + dlt_ORG) {
|
||
if (++cnt_release >= 3) { // 连续 3 次确认
|
||
VD_FLAG = 0; FLAG_OUT = 1;
|
||
}
|
||
} else {
|
||
cnt_release = 0; // 回落立即重置
|
||
}
|
||
```
|
||
|
||
##### 模式 2:平坦性判定 (USE_FLATNESS_EXIT=1) — 默认
|
||
|
||
基于专利 **CN200910309382**(中山大学),解决大车通行时频率多峰导致的多次误触发。
|
||
|
||
**算法架构:**
|
||
|
||
```
|
||
车辆到达 → 单一阈值法 (沿用 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 | 平坦确认次数 |
|
||
|
||
**整数化适配:** 专利原实现用 float(Hz 频率值),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/闪电尖峰,保护 IIR(V2.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_task(50ms 周期)。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、斜率限幅、进入确认、冻结超时+稳定性 |
|
||
|
||
**删除的死代码:**
|
||
- 二阶差分滤波(计算但从未参与判决)
|
||
- FltHistoryManager(20+ 未用字段)
|
||
- 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 (测量) + 平坦性确认 + 500 ms (防抖) | 含双重确认 |
|
||
| 误检率(单阈值) | — | 基准参考 |
|
||
| 误检率(平坦性) | 显著降低 | 大车多峰场景 |
|
||
| 频率分辨率 | < 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 1 // 1 = 平坦性离开判定 (CN200910309382)
|
||
// 0 = 简单 cnt_release 防抖
|
||
|
||
// 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%
|
||
```
|
||
|
||
---
|
||
|
||
## 14. 关键专利
|
||
|
||
| 专利号 | 名称 | 权利人 | 应用 |
|
||
|--------|------|--------|------|
|
||
| CN200910309382 | 一种防误检环形线圈车辆检测器 | 中山大学 张辉/黄永强/陈古典 | 平坦性三条件离开判定 |
|
||
|
||
DLD154V4B V1.4 起实现该专利的整数化版本,用于大车通行时的离开判定,有效抑制频率曲线多峰导致的多次误触发。
|
||
|
||
---
|
||
|
||
## 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, 两阶段基线 |
|