Files
DLD154V4B/utilities/at32f421_freertos_demo/inc/TaskLoop.h
wangfq fec67d6f20 feat: 冻结超时增加稳定性检查 — CAPVD波动超±2%则重置计数
问题: 上次提交仅计数冻结持续时长,若CAPVD在冻结期间大幅波动
(如车辆缓慢驶入过程中CAPVD持续爬升),30s后也会被误认为"环境变化"。

方案:
- 新增 loop1_freeze_ref: 记录进入冻结时的CAPVD值
- 每tick检查 |CAPVD - freeze_ref| > freeze_ref * 2%
- 波动超限 → 重置计数并以当前值重新开始计时
- 只有CAPVD连续30s稳定在±2%窗口内 → 才更新Origin

这确保了"连续稳定的新值"而非"连续偏高但波动的值"才会触发基线更新。
2026-06-29 10:30:01 +08:00

188 lines
10 KiB
C
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.
/**
**************************************************************************
* @file TaskLoop.h
* @version v2.0
* @date 2025-09-08 (original), 2026-06-23 (simplified)
* @brief 地感功能实现 — 精简版,对齐 M1H/TLD-110 参考实现
**************************************************************************
* Copyright notice & Disclaimer
* * Create 2025-09-08 by wangfq
* * Simplify 2026-06-23: 去除二阶滤波、StageRangeConfig 等未使用模块
**************************************************************************
*/
#ifndef __TASKLOOP_H__
#define __TASKLOOP_H__
#include <stdint.h>
#include <stddef.h>
/*===========================================================================
* 时序参数(每 tick ≈50ms由 TMR15 5ms×10 产生),对齐 M1H 参考实现
*===========================================================================*/
#define HOLD_TIME (5 * 1200) // 有限存在保持(约 5 分钟)
#define LC_HOLD_TIME (4 * 1200) // 安全复位时间(约 4 分钟)
#define IN_DELAY 10 // 进入防抖 500ms
#define OUT_DELAY 10 // 离开防抖 500ms仅 SW_4=ON 时生效)
#define PULSE_DELAY 10 // 脉冲宽度 500ms
/*===========================================================================
* 滤波参数 — M4 优化版
*
* 与 M1H (8051, 50ms tick) 的关键差异:
* - tick 提升到 10ms滤波系数同步调整保持等效时间常数
* - 新增斜率限幅 (MAX_SLOPE_RATE) 过滤瞬态尖峰
* - 进入确认 (ENTRY_CONFIRM) 替代单次阈值判定
*===========================================================================*/
#define ALFA_CAP1 18 // IIR α = 18/256 ≈ 0.07 (@10ms → τ≈135ms, 等效 50ms 的 79/256)
#define ALFA_FAST 128 // 快速 IIR α = 128/256 = 0.5 (@10ms → τ≈28ms, 用于检测)
#define MAX_SLOPE_RATE 5 // 斜率限幅: 单次最大变化 5% (物理限制, 拒绝 EMI 尖峰)
#define ENTRY_CONFIRM 3 // 进入确认: 连续 N 次低于阈值才判定有车
#define FREEZE_TIMEOUT 3000 // 基线冻结超时: ~30s @ 10ms/tick, 持续偏高后强制更新基线
#define FREEZE_STABILITY_RATE 2 // 冻结稳定性窗口: 参考值的 ±2% (CAPVD 需在此范围内才累计超时)
/*===========================================================================
* 离开检测模式
* 1 = 平坦性三条件判定 (CN200910309382), 0 = 简单 cnt_release 防抖
*===========================================================================*/
#define USE_FLATNESS_EXIT 1
/*===========================================================================
* 频率测量参数
* MEASUREMENT_BASE: 自适应测量窗口目标值 (≈131072)
* LPCNT = MEASUREMENT_BASE / Xn, 使 Value ≈ MEASUREMENT_BASE
* 121072 = 2^17, 兼顾精度和 Origin 范围
*===========================================================================*/
#define MEASUREMENT_BASE 131072 // 2^17
/*===========================================================================
* 灵敏度表 — 对齐 M1H
* 进入阈值 = Origin × SensTable[SENS] / 65536
* 离开阈值 = Origin × SensTable_1[SENS] / 65536 (滞回 ~50%
*===========================================================================*/
extern const uint16_t SensTable[4];
extern const uint16_t SensTable_1[4];
/*===========================================================================
* 全局状态变量 — 捕获 & 测量
*===========================================================================*/
extern uint32_t g_sys_freq; // 系统时钟频率
extern uint8_t g_input_div; // TIM3 输入分频倍数
extern uint16_t loop1_Xn; // 当前相邻边沿周期差
extern uint16_t loop1_CapThis; // 本次捕获值
extern uint16_t loop1_CapLast; // 上次捕获值
extern uint16_t loop1_LPCNT; // 每 Value 需累加 LPCNT 次 Xn
extern uint16_t loop1_CapCnt; // 当前窗口已累加次数
extern uint32_t loop1_CapSum; // 当前窗口累加和
extern uint32_t loop1_Value; // 一个测量窗口的原始 ΣXn
extern uint32_t loop1_CAPVD; // IIR 滤波后的频率值
extern uint32_t loop1_Origin; // 基线(无车时的参考频率)
extern uint32_t loop1_ORG_SUM; // 基线跟踪累加和
extern uint16_t loop1_ORG_CNT; // 基线跟踪计数(窗口=100
extern uint16_t loop1_dlt_ORG; // 当前灵敏度阈值
extern uint8_t Flt_Reg; // IIR 滤波系数
/*===========================================================================
* 全局状态变量 — 标志位
*===========================================================================*/
extern uint8_t loop1_INI_LOOP; // 初始化阶段
extern uint8_t loop1_CAP_OK; // 新测量数据就绪
extern uint8_t loop1_VD_FLAG; // 有车标志
extern uint8_t loop1_VD_HOLD; // 有限存在计时启用
extern uint8_t loop1_RF_FLAG; // 本 tick 收到线圈振荡边沿
extern uint8_t loop1_LOOP_OK; // 线圈连接正常
extern uint8_t loop1_LOOP_OK0; // 线圈连接正常(上周期)
extern uint8_t loop1_FLAG_IN; // 进入延时中
extern uint8_t loop1_FLAG_OUT; // 离开延时中
extern uint8_t loop1_FLAG_PLUSE; // 脉冲输出中
extern uint8_t loop1_SensLevel; // 当前灵敏度等级 (0~3)
extern uint8_t g_loop_stable; // 线圈数值已稳定 (0=稳定中, 1=稳定)
/* 离开防抖计数器(连续 CAPVD 恢复到阈值以上才释放) */
extern uint8_t loop1_cnt_release; // 离开防抖计数
/* M4 优化: 快速 IIR + 进入确认 */
extern uint32_t loop1_CAPVD_fast; // 快速 IIR 值 (α=0.5, τ≈28ms, 用于检测)
extern uint8_t loop1_entry_cnt; // 进入确认计数
extern uint16_t loop1_freeze_cnt; // 基线冻结持续计数(超时后强制更新 Origin
extern uint32_t loop1_freeze_ref; // 冻结参考值CAPVD 偏离此值超限则重置计数)
#if USE_FLATNESS_EXIT
extern uint8_t g_exit_state; // 离开检测: 0=追踪斜率, 1=等待平坦
extern uint16_t g_max_slope; // 第一上升坡面最大 |f'|
extern uint16_t g_max_slope_rate; // 第一上升坡面最大 |f''|
extern uint16_t g_delta2; // Δ2: 一阶平坦阈值
extern uint16_t g_delta3; // Δ3: 二阶平坦阈值
extern int32_t g_prev_capvd; // 上一帧 CAPVD (差分用)
extern int32_t g_prev_first_deriv; // 上一帧一阶导数
extern uint8_t g_slope_flat_cnt; // 斜率趋零连续计数
extern uint8_t g_flat_ok_cnt; // 平坦条件满足连续计数
#endif
/*===========================================================================
* 全局状态变量 — 计数器
*===========================================================================*/
extern uint16_t Hold_CNT; // 有限存在计数器
extern uint8_t loop1_INCNT; // 进入延时计数
extern uint8_t loop1_OUTCNT; // 离开延时/脉冲宽度计数
extern uint8_t TM1cnt; // 50ms tick 分频计数
/*===========================================================================
* 拨码开关状态
*===========================================================================*/
extern uint8_t SET_PLUS; // 0=存在输出, 1=脉冲输出
extern uint8_t SET_DLY; // 离开延时: 0=无, 1=500ms
extern uint8_t SET_SAFE; // 1=安全复位拨下
/*===========================================================================
* 拨码开关去抖变量
*===========================================================================*/
extern uint8_t sw0, sw1, swok, swcnt;
extern uint8_t SENS, SENS_LAST;
/*===========================================================================
* 安全复位相关
*===========================================================================*/
extern uint8_t loop1_LC_HOLD; // 安全复位计时中
extern uint8_t loop1_LC_Reset; // 触发安全复位
extern uint32_t LC_Hold_CNT; // 安全复位计数器
extern uint16_t g_safe_max_cnt; // 安全复位超时
/*===========================================================================
* 故障指示相关 — 黄灯 LEDC (PA10)
*
* 行为:
* - 当前断开中 或 上电后从未接线圈:快闪 (200ms)
* - 线圈已恢复连接, 断开过 N 次N 短闪 (N≤3)
* - 线圈正常连接, 无断开记录:灭
*
* 注: 绿灯 LEDA (PA9) 由 poll_green_led() 控制;
* 红灯 (PB1) 始终 PWM 呼吸, 不需软件干预.
*===========================================================================*/
extern uint8_t g_loop_power_up_state; // 上电后线圈是否曾连接 (0=否, 1=是)
extern uint8_t g_disconnect_count; // 当前上电周期内线圈断开次数 (0~3)
extern uint8_t g_disconnect_active; // 当前处于断开状态 (0=连接/从未连, 1=断开中)
extern uint8_t g_fault_phase; // 黄灯闪烁阶段
extern uint16_t g_fault_tick; // 黄灯闪烁计时器 (每5ms+1)
/*===========================================================================
* 调试计数器
*===========================================================================*/
extern uint32_t g_xn_counter; // 边沿总数(用于调试输出)
/*===========================================================================
* 函数声明
*===========================================================================*/
void loop_task_function(void *pvParameters);
void poll_sw_state(void);
uint32_t get_flt_value(uint32_t new_value, uint32_t last_Value);
uint8_t update_moving_average(uint32_t* p_sum, uint16_t* p_cnt,
uint32_t* p_origin, uint32_t new_value,
uint8_t window);
void poll_yellow_led(void);
void poll_green_led(void);
void LEDA_ON_OFF(void);
void vd1_task(void);
#endif /* __TASKLOOP_H__ */