Files
DLD154V4B/utilities/at32f421_freertos_demo/inc/TaskLoop.h
T
wangfq b4aa7402a5 feat(V4B): V4.36.39 — COIL_UNDER_MIN_AS_OPEN 默认 0→1 (用户拍板)
L<20µH(f>171k) 短路级出厂即等同线圈断开完全态:
判车暂停 + 继电器保持释放 + 绿灯不亮 + 黄灯快闪(断开同款)
恢复: coil_monitor_recover 无条件监测 f 回窗≤171k 连续5s 实时置档
=0 可编译期关(仅快闪提示仍判车)
spec V2.57 / manual V2.16 / devlog V2.75
语法0 error, 4测试全绿
2026-09-09 10:45:09 +08:00

257 lines
18 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 提升到 10msALFA_CAP1=79 @10ms (τ≈32ms, 等效原 79@50ms 的 5× 响应速度)
* - 斜率限幅 (MAX_SLOPE_RATE) 过滤瞬态尖峰
* - 进入确认 (ENTRY_CONFIRM) 替代单次阈值判定
*===========================================================================*/
#define ALFA_CAP1 79 // IIR α = 79/256 ≈ 0.31 (@10ms → τ≈32ms)
#define RELEASE_ALFA 21 // 释放慢滤波 α = 21/256 ≈ 0.082 (@10ms → 精确τ≈117ms, V4.04: 对齐 PD132T α79@43.7ms 精确τ≈118ms; 原18→精确τ137ms偏慢)
#define REL_ALFA 30 // V4.36.19/26: 低Q 释放平滑 α=30/256≈0.117 (@10ms → τ≈85ms, 46→30): 复刻打印降采样平均效应, 只用于低Q 释放判定抗抖 (V4.36.26 加大剂量 50→85ms)
#define REL_BAND_LO_MULT 180 // V4.36.19/28: 低Q 释放带回加宽 % (dlt_rel×1.8: 23→41@SENS3): 防边界试探锁死
#define REL_BAND_TIMEOUT_TICKS 250 // V4.36.30: 低Q 环带超时兜底 2.5s(@10ms): 板已离开触发深度(CAPVD>进入线)
// 持续 2.5s → 强制释放 (空间回滞带内停住不再永久卡死; 用时间回滞替代空间回滞)
#define VACUUM_EMA_ALFA 128 // V4.36.31: 真空 EMA 平滑因子 (τ≈1.28s@10ms): B3 判定参考解耦
// 无车 dev 窗内跟踪实时真空; 噪声 σ_ema≈σ/16 (σ1-2 → 0.1 counts)
#define VAC_REF_DELTA_DLT 1 // V4.36.33: vac_ref 重锚阈值 (×dlt): 仅 OriginEMA > 1×dlt(真锚错)
// 才用 EMA 锚低 — 防金属板悬感应边缘(dev20~40<4dlt)快速拉低 EMA
// → 触发线漂移(触发高度下降); 小偏差仍用 Origin
// 150(→35)不够: 23µH 现场实测板停临界回摆 Origin-36, 需释放线<Origin-37 才释放;
// 180(→41)线=Origin-41, 余 4 counts; 触发-释放回滞 49-41=8 counts (实测σ≈1-2, 安全)
#define USE_SLOW_RELEASE 0 // 方案A总开关: 1=释放走慢滤波(对齐PD132T) 0=原快滤波释放
#define USE_PLANB_TABLE 1 // 方案B (V4.06): 快滤波释放 + 灵敏度表现场调校
// 1=进入加深/释放调浅双表(见 TaskLoop.c, SENS=3: 25/12 现场实测接近PD132T)
// 0=原始PD132T对齐表 {300,60,32,21}/{60,32,21,14}
// 历史: V4.05 曾用 ReleaseTable_B 加深释放表(实验失败, 方向反)
// V4.06 改为 SENS=3 进入21→25+释放14→12, 等比推全档
#define MAX_SLOPE_RATE 5 // 斜率限幅: 单次最大变化 5% (物理限制, 拒绝 EMI 尖峰)
/* V4.36.15: 重连判稳门控 (无车断开重连: 值稳定才放行, 不稳黄灯续闪) */
#define STABILIZE_STEP_TICKS 20 // 判稳步进: 20 样本≈200ms
#define STABILIZE_STEPS_OK 3 // 连续 3 步(600ms)漂移≤dlt/2 → 无漂移
#define STABILIZE_MAX_MS 5000 // 判稳兜底: 超时强制放行(避免永久无输出)
/* V4.36.8: 进入/释放确认样本数 — 按线圈 Q 档 (Q∝1/f 代理, 低Q抖动大需更多样本防误判) */
#define ENTRY_CONFIRM 3 // 进入确认基准(高Q): 连续 N 次低于阈值才判定有车
#define ENTRY_CONFIRM_HI 3 // 高Q(f<=80k) 进入确认样本
#define ENTRY_CONFIRM_MID 4 // 中Q(80~100k)
#define ENTRY_CONFIRM_LO 5 // 低Q(f>100k): 抖动大, 多样本防假进入
#define REL_ORIGIN_FREEZE_TICKS 100 // V4.36.26/32: 释放后 Origin 全冻结 1000ms — 残余缓离窗口不入均值窗
#define ORIGIN_LOWLEARN_TICKS 200 // V4.36.32: 冻结后降权低速补偿期 2000ms: 残余低值样本权重降 ×1/MULT
// 仿 PD132T 慢采样等效(10ms 快采样让 5s 窗装得快, 残余易拉低 Origin; 慢学更稳)
#define ORIGIN_LOWLEARN_MULT 5 // V4.36.32: 降权期均值窗放大 500→2500 样本(25s 窗), 学习速率 1/5
#define READY_HOLD_HI_TICKS 1000 // V4.36.36: 判稳后就绪巩固期 (5ms tick): 高Q 5s/中Q 7s/低Q 10s
// 低Q 上电自检刚完(绿灯灭)即压板易绿灯常亮 — 巩固期绿灯继续慢闪,
// 期间 Origin/EMA/滤波继续收敛, 绿灯灭才允许操作 (5s/7s/≥10s 用户拍板)
#define READY_HOLD_MID_TICKS 1400 // 中Q 7s
#define READY_HOLD_LO_TICKS 2000 // 低Q 10s
#define REL_CONFIRM_HI 3 // 高Q 释放确认样本
#define REL_CONFIRM_MID 4 // 中Q
#define REL_CONFIRM_LO 5 // 低Q: 释放边界抖动, 多样本防输出抖落
#define FREEZE_TIMEOUT 1000 // 基线冻结超时: ~10s @ 10ms/tick, 持续偏高且稳定后强制更新基线
#define FREEZE_STABILITY_RATE 2 // 冻结稳定性窗口: 参考值的 ±2% (CAPVD 需在此范围内才累计超时)
#define ENV_WARN_WAIT 200 // 环境预判 (V4.31): dev>+4dlt 高位连续 ~2s → 黄灯预判锁存(回摆保持)
#define ENV_RECOVER_WAIT 200 // 恢复确认 (V4.31): 新基线替换后 环境空闲连续 ~2s 才解除预判, 黄灯灭
#define COIL_F_OK_MIN_KHZ 18 // 线圈频率合理窗 (V4.36.18): 默认低频档口径, <18kHz → L偏大 (≈双 250µH+ 大线圈放行)
#define COIL_L_MIN_UH 24 // V4.36.23/25: 出窗偏小指示阈值 µH (对应 COIL_L_MIN_F_KHZ=156): L<此值 → 黄灯疾闪 100ms(独立节奏), 判定恒照常
#define COIL_L_SHORT_UH 20 // V4.36.37: 真短路级阈值 µH (方案A 分级): L<20µH(f>171k) → 断开级快闪(200ms, 与真断开同款), COIL_UNDER_MIN_AS_OPEN 作用于此级
#define COIL_L_SHORT_F_KHZ 171 // V4.36.37: f@20µH=171.6k 取 171: f>此值 → L<20µH 短路级
#define COIL_UNDER_MIN_AS_OPEN 1 // V4.36.24/37/39: L<20µH(f>171k, 短路级) 是否视为线圈断开完全状态(方案A 作用域从 156k 移到 171k):
// 1=默认(用户 2026-09-08 拍板): 黄灯快闪+继电器保持释放+绿灯不亮(同真正断开, 判定停)+专职恢复监测;
// 0=仅黄灯快闪(断开级指示), 绿灯/继电器/判定照常
// 156~171k(L 20~24µH) 恒判车照常+一长两短, 不随此宏
#define COIL_FAULT_HOLD_TICKS 500 // V4.36.21: 电感量越界/恢复防抖 500tick=5s (原100=1s; 下限判定重要, 加长防误检瞬态冲高)
#define COIL_F_OK_MAX_KHZ 125 // 线圈频率合理窗上限 (V4.36.25 恢复): >125kHz(43nF≈38µH) → L偏小不合理 → 黄灯一长一短 (V4.36.9 口径不变)
#define COIL_L_MIN_F_KHZ 156 // V4.36.25: 低于下限频率 (43nF: L=2.533e7/(f²×43), f@24µH=156.7k): f>此值 → L<COIL_L_MIN_UH → 黄灯快闪(断开级)
#define COIL_CAL_C_NF 43 // 标定等效谐振电容 nF (V4.34): 三极管库存板 低频档(66nF名义, R19在/R27空)实测 C_eff≈43 (41.3~45.5; 0Ω板68仅实验口径, 产品不用)
// 旧43 = 5.1K电阻旧板带病特性(三极管开关未饱和导通, 第二颗33nF未全量并入), 作废
#define COIL_CAL_C_NF_33 34 // 高频档(33nF名义)标定值: 实测 C_eff≈34.4 (33.8~35.0, 3组) — 用33nF档时改 COIL_CAL_C_NF 为34
#define COIL_DEF_C_NF 66 // 名义默认档电容 (保留: 注释/文档口径; 计算用 COIL_CAL_C_NF)
/*===========================================================================
* 离开检测模式
* 1 = 平坦性三条件判定 (CN200910309382), 0 = 简单 cnt_release 防抖
*===========================================================================*/
#define USE_FLATNESS_EXIT 0
/*===========================================================================
* 看门狗 (IWDT) - V2.10 新增
* 双保险模式: TMR15 ISR 5ms 递增 g_wdg_counter, 主循环 poll_wdg() 每 500ms 喂狗
* 超时 = WDT_DIV x (WDT_RLD+1) / LSI(约40kHz) 约 1.64s
*===========================================================================*/
#define WDT_COUNTER_LIMIT 100 // 喂狗周期 500ms (TMR15 5ms x 100)
#define WDT_DIV 2 // IWDT 分频枚举值: 2 = WDT_CLK_DIV_16 (实际分频 16; 勿传 16!)
#define WDT_RLD 4095 // 12bit 重装载 -> 超时约 1.64s
#define WINDOW_ORIGIN 500 // 基线跟踪窗口 (500 × 10ms = 5s)
/*===========================================================================
* 频率测量参数
* 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_CAPVD_slow; // 释放判定慢滤波值 (方案A: 独立 IIR, 精确τ≈117ms, 对齐 PD132T 释放手感)
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 优化) */
extern uint8_t loop1_entry_cnt; // 进入确认计数
extern uint16_t loop1_freeze_cnt; // 基线冻结持续计数
extern uint32_t loop1_freeze_ref; // 冻结参考值
#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 volatile uint16_t g_wdg_counter; // 看门狗活性计数 (TMR15 5ms 递增)
/*===========================================================================
* 拨码开关状态
*===========================================================================*/
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,
uint16_t window);
void poll_yellow_led(void);
void poll_green_led(void);
void LEDA_ON_OFF(void);
void vd1_task(void);
void wdt_init(void);
void poll_wdg(void);
#endif /* __TASKLOOP_H__ */