Files
wangfq 5f7082c0ba fix(DLD154Pro): 基线跟踪双向对称保护同步V4B V4.20 — 负variation铁块防Origin污染锁死
负偏差(dev>0,CAPVD>Origin)只冻结永不超时更新Origin, 对称窗口[-4×dlt,+4×dlt]
补drift取绝对值(与V4B/vd960Loop一致); 与DLD154V4B V4.20修复同构
2026-09-02 14:52:13 +08:00

1544 lines
56 KiB
C
Raw Permalink 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.
/********************************** (C) COPYRIGHT *******************************
* File Name : peripheral_main.c
* Author : WCH / wangfq
* Version : V2.0 (algorithm ported from DLD154V4B)
* Date : 2026/07/18
* Description : DLD154Pro 单线圈蓝牙车检器 主函数
*
* 算法说明 (移植自 DLD154V4B TaskLoop V2.0, M1H 精简系):
* - 自适应测量窗: LPCNT = MEASUREMENT_BASE / Xn, 测量窗时长与线圈频率无关
* - 一阶 IIR (79/256) + 斜率限幅 5% (拒绝 EMI 瞬态尖峰)
* - 稳定期 128 窗快速收敛 (绕过滤波, 小窗口 100)
* - 基线跟踪 窗口 500 + 冻结保护 (超时 + 稳定性双条件强制更新)
* - 进入确认 3 次; 离开: 平坦性三条件判定 (专利 CN200910309382)
* - 有限存在超时 / 安全复位: 全复位重建基线
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/******************************************************************************/
/* 头文件包含 */
#include "CONFIG.h"
#include "HAL.h"
#include "gattprofile.h"
#include "peripheral.h"
#include "storage.h"
#include <stdlib.h>
#include "cmcng.h"
#include "dbn_ble_srv.h"
#include "CH59x_pwm.h"
#include "CH59x_sys.h" /* WWDG 看门狗 */
#include "rs485_700bs.h"
#include "rs485_modbus.h"
uint8_t g_flag_bt_state = 0; // 0 蓝牙没有连接,1 有蓝牙连接
uint8_t g_function_mode = 0;
uint8_t g_fm_700bs_disable = 0; //0: 700bs protocol; 1 Modbus protocol
uint8_t g_output_radar_mode = 0;
uint8_t g_opt_trigger = 0; // 光耦/雷达 处理后触发信号 (1=有效)
uint32_t g_sys_freq = 0;
uint8_t g_storage_uart_num = 0;
uint32_t g_storage_uart_baud = 19200;//9600;
uint8_t g_max_counter_bt_min = 0;
uint32_t g_max_counter_bt_timeout = 0; //BT_DISABLE_IDLE_TIMEOUT * 60 * 1000; // ms unit
uint8_t g_rs485_id = 0;
/*===========================================================================
* IO 宏定义 -- DLD154Pro 硬件资源
*
* PA8 : RLY1 存在继电器 (单刀双掷, 低电平有效)
* PB22 : LEDA 绿色指示灯 (有车亮/无车灭, 低电平有效)
* PB23 : LEDB 红色指示灯 (呼吸灯, 低电平有效)
* PA12 : FLEVEL 线圈调频 (一级, 0=66nF(低频), 1=33nF(高频))
* PA14 : UART0_Tx RS485发送 (700BS 协议)
* PA15 : UART0_Rx RS485接收 (700BS 协议)
* PA13 : UART0_RE RS485方向控制 (700BS 协议)
* PB10 : IN_1 光耦输入 (逻辑待定)
*===========================================================================*/
#define RLY1_ON (R32_PA_OUT |= BV(8))
#define RLY1_OFF (R32_PA_OUT &= ~BV(8))
#define LEDA_ON (R32_PB_OUT &= ~BV(22))
#define LEDA_OFF (R32_PB_OUT |= BV(22))
#define LEDA_ON_OFF() (GPIOB_ReadPortPin(GPIO_Pin_22) ? GPIOB_ResetBits(GPIO_Pin_22) : GPIOB_SetBits(GPIO_Pin_22))
#define LEDB_ON (R32_PB_OUT &= ~BV(23))
#define LEDB_OFF (R32_PB_OUT |= BV(23))
#define FLEVEL_LOW (R32_PA_OUT &= ~BV(12))
#define FLEVEL_HIGH (R32_PA_OUT |= BV(12))
/* RS485 700BS 协议 (2026-07-23) */
#define RS485_TX_PIN GPIO_Pin_14
#define RS485_RX_PIN GPIO_Pin_15
#define RS485_RE_PIN GPIO_Pin_13
#define RS485_RE_TX (GPIOA_SetBits(RS485_RE_PIN)) // RE=1 发送模式
#define RS485_RE_RX (GPIOA_ResetBits(RS485_RE_PIN)) // RE=0 接收模式
/* 光耦输入预留 (逻辑待定) */
#define OPT_IN1 (GPIOB_ReadPortPin(GPIO_Pin_10))
/*===========================================================================
* LEDB 红色呼吸灯 (PB23, PWM11) — 心跳指示
* PWM freq ≈ 60MHz / (PWM_CLK_DIV * 128) ≈ 5.86kHz @DIV=80
* 无光耦信号: 周期 ≈ 16步×2 + 3tick×2 ≈ 1.9s (DUTY_STEP=8, HOLD=3)
* 光耦有信号: 周期 ≈ 4步×2 + 1tick×2 ≈ 0.5s (DUTY_STEP=32, HOLD=1)
* 复位模式(6)除外,光耦有信号不加速
*===========================================================================*/
#define PWM_CLK_DIV 80
#define PWM_CYCLE 128 // 7-bit 分辨率 (0~127)
#define BREATH_STEP_DELAY 1 // 每 50ms 更新一次
#define BREATH_DUTY_STEP 8 // 每步跳 8 级占空比
#define BREATH_HOLD_TICKS 3 // 高/低电平保持 tick 数
#define BREATH_FADE_IN 0
#define BREATH_HOLD_HIGH 1
#define BREATH_FADE_OUT 2
#define BREATH_HOLD_LOW 3
/* 光耦有信号时加速参数 (周期 ~1s) */
#define BREATH_OPTO_DUTY_STEP 64 // 步长 8x → 渐亮/渐灭各 2 步 (~0.55s 周期, 光耦有信号加速)
#define BREATH_OPTO_HOLD_TICKS 1 // 保持 50ms
/* 看门狗超时: Fsys=60MHz, WDOG_CLK=Fsys/131072≈458Hz, 0xFF≈558ms */
#define WDOG_TIMEOUT 0xFF
static uint8_t g_breath_phase = BREATH_FADE_IN;
static uint8_t g_breath_duty = 0;
static uint8_t g_breath_tick = 0;
const uint8_t MAX_Store_Size = 80;
uint8_t g_loop_power_up_state = 0; // 开机启动时线圈是否连接
uint8_t g_disconnect_active = 0; // 当前线圈是否断开中 (1=断开)
__IO uint32_t TimingDelayInc;
/*===========================================================================
* 算法参数 -- 移植自 DLD154V4B (M4 优化版), 适配 CH591R @60MHz
*
* 测量窗: MEASUREMENT_BASE 个系统时钟 tick, 与线圈频率无关
* 524288(2^19) / 60MHz ~= 8.74ms, 即 vd1_task 有效采样周期 ~8.74ms
* (DLD154V4B 为 131072 @120MHz + 10ms 任务轮询, 时间尺度基本一致)
*===========================================================================*/
#define MEASUREMENT_BASE 524288L // 2^19, 自适应测量窗目标值 (Value ~= 524288)
#define ALFA_CAP1 79 // IIR a=79/256~=0.31 (@8.74ms -> tau~=24ms)
#define MAX_SLOPE_RATE 5 // 斜率限幅: 单次最大变化 5% (拒绝 EMI 尖峰)
#define ENTRY_CONFIRM 3 // 进入确认: 连续 N 次低于阈值才判有车
#define FREEZE_TIMEOUT 1000 // 基线冻结超时: ~8.7s, 持续偏高且稳定后强制更新
#define FREEZE_STABILITY_RATE 2 // 冻结稳定性窗口: 参考值 +-2%
// #define USE_FLATNESS_EXIT 1 // 1=平坦性三条件离开, 0=简单滞回防抖
#define WINDOW_ORIGIN 500 // 基线跟踪窗口 (500 窗 ~= 4.4s)
#define STABLE_SAMPLES 128 // 稳定期样本数 (~1.1s)
#define VARIATION_EVENT_TH 40 // BLE variation 事件阈值 (幅值基准 2^19, 对应旧代码的 5)
#define ENV_ACT_TH 30 // 环境活跃度: CAPVD 相邻差绝对值阈值 (待现场验证)
uint32_t mstick(void){
return TimingDelayInc;
}
uint8_t g_loop_cut_last = 0;
uint32_t g_loop_cut_amount = 0;
/*********************************************************************
* GLOBAL TYPEDEFS
*/
__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];
#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
#else
uint8_t MACAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
#endif
uint8_t g_dev_number[6] = ""; // 设备编号 产品编号
char g_flag_debug = 1;
uint8_t g_freq_sens;
uint8_t loop1_SensLevel;
uint8_t g_freq_level;
uint16_t g_safe_max_cnt = LC_HOLD_TIME;
uint16_t Hold_CNT = 0;
uint8_t Flt_Reg = 0;
uint8_t TM1cnt = 0;
uint16_t g_hold_time = 0;
uint16_t g_wdg_counter = 0;
/*===========================================================================
* 捕获 & 测量
*===========================================================================*/
uint16_t loop1_Xn; // 相邻下降沿周期 (TMR0 直接给出)
uint32_t loop1_dlt_ORG; // 当前灵敏度阈值
uint32_t loop1_Origin; // 基线 (无车参考值)
uint16_t loop1_LPCNT; // 每个测量窗累加的 Xn 个数
uint16_t loop1_CapCnt; // 当前窗口已累加次数
uint32_t loop1_CapSum; // 当前窗口累加和
uint32_t loop1_CAPVD; // IIR 滤波后的测量值
uint32_t loop1_Value; // 一个测量窗的原始 Sigma-Xn
uint32_t loop1_ORG_SUM; // 基线跟踪累加和
uint16_t loop1_ORG_CNT; // 基线跟踪计数
/*===========================================================================
* 计数器
*===========================================================================*/
uint8_t loop1_INCNT;
uint8_t loop1_OUTCNT;
/*===========================================================================
* 标志位
*===========================================================================*/
uint8_t loop1_INI_LOOP;
uint8_t loop1_CAP_OK;
uint8_t loop1_VD_FLAG;
uint8_t loop1_VD_HOLD;
uint8_t loop1_RF_FLAG;
uint8_t loop1_LOOP_OK;
uint8_t loop1_LOOP_OK0;
uint8_t loop1_FLAG_IN;
uint8_t loop1_FLAG_OUT;
uint8_t loop1_FLAG_PLUSE;
uint8_t loop1_FLAG_PLUSE_IN_F = 0;
uint8_t loop1_FLAG_PLUSE_IN = 0;
uint8_t loop1_FLAG_CUT;
uint8_t loop1_FLAG_HOLD_TIMEOUT; // 有限存在超时
/*===========================================================================
* 安全复位
*===========================================================================*/
uint8_t loop1_LC_HOLD = 0;
uint8_t loop1_LC_Reset = 0;
uint32_t LC_Hold_CNT = 0;
/*===========================================================================
* 新算法状态 (DLD154V4B 移植)
*===========================================================================*/
uint8_t g_loop_stable = 0; // 线圈数值已稳定 (0=稳定期中, 1=稳定)
uint16_t loop1_stable_cnt = 0; // 稳定期样本计数
uint8_t loop1_entry_cnt = 0; // 进入确认计数
uint8_t loop1_cnt_release = 0; // 简单离开防抖计数 (USE_FLATNESS_EXIT=0)
uint16_t loop1_freeze_cnt = 0; // 基线冻结持续计数
uint32_t loop1_freeze_ref = 0; // 冻结稳定性参考值
#if USE_FLATNESS_EXIT
uint8_t g_exit_state = 0; // 0=追踪坡面, 1=等待平坦
uint16_t g_max_slope = 0; // 第一上升坡面最大 |f'|
uint16_t g_max_slope_rate = 0; // 第一上升坡面最大 |f''|
uint16_t g_delta2 = 0; // 一阶平坦阈值
uint16_t g_delta3 = 0; // 二阶平坦阈值
int32_t g_prev_capvd = 0; // 上一帧 CAPVD (差分用)
int32_t g_prev_first_deriv = 0; // 上一帧一阶导数
uint8_t g_slope_flat_cnt = 0; // 斜率趋零连续计数
uint8_t g_flat_ok_cnt = 0; // 平坦条件满足连续计数
#endif
/* 环境活跃度 (供 BLE condition 字段上报, 替代旧 flt_mgr.cnt_not_idle) */
uint8_t g_env_activity = 0;
uint32_t g_env_prev_capvd = 0;
/*===========================================================================
* 出厂灵敏度默认表 (写入 g_loop_sens_list, 运行时以 g_loop_sens_list 为准)
* 进入阈值 = Origin * sens_in / 65536; 离开阈值 = Origin * sens_out / 65536
*===========================================================================*/
const uint16_t SensTable[MAX_LOOP_SENS_AMOUNT] = { 108, 54, 28, 14};
const uint16_t SensTable1[MAX_LOOP_SENS_AMOUNT] = {81, 32, 16, 12};
uint16_t g_loop_out_delay = 10; // 离开延时, 50ms 为单位, 由 delay_time 配置
DBN_BLE_State g_dbn_ble_state_acs_enable = {0};
Loop_ACS_Info g_loop_acs_info = {0,};
float g_freq_tmp = 0.0;
/* 用于APP判断文件有效性 */
const uint32_t Address = 0xFFFFFFFF;
__attribute__((aligned(4))) uint32_t Image_Flag __attribute__((section(".ImageFlag"))) = (uint32_t)&Address;
uint8_t loop_cng_default[7] = {2,1,0,0x00,4,0,0};
void set_factory_param(void)
{
uint8_t i;
memcpy(&g_loop_cng_unit.sensitvity, loop_cng_default, 7);
g_loop_sens_list.total = MAX_LOOP_SENS_AMOUNT;
for(i = 0; i < g_loop_sens_list.total; i++)
{
g_loop_sens_list.sens[i].sens_in = SensTable[i];
g_loop_sens_list.sens[i].sens_out = SensTable1[i];
}
}
void factory_dev(void){
uint8_t i = 0, k = 0;
uint8_t *rBuf = (uint8_t *)malloc(MAX_Store_Size);
if(rBuf == NULL){
SYS_ResetExecute();
}
for(i = 0; i < MAX_Store_Size; i++){
rBuf[i] = 0;
}
rBuf[0] = 0x33;
rBuf[1] = 0xBB;
rBuf[2] = 0xC3;
rBuf[3] = 0x3C;
i = 4;
memcpy(&rBuf[i], &g_loop_cng_unit.sensitvity, 7);
i += 7;
rBuf[Addr_RS485_ID_Offset] = 1;
rBuf[Addr_RS485_Baud_Offset] = RS_BAUD_DEFAULT & 0xFF;
rBuf[Addr_RS485_Baud_Offset + 1] = (RS_BAUD_DEFAULT >> 8) & 0xFF;
rBuf[Addr_RS485_Baud_Offset + 2] = (RS_BAUD_DEFAULT >> 16) & 0xFF;
rBuf[ADDR_BT_Close_TIMEOUT_Offset] = 0;
i = Addr_Loop_Sens_List_Offset;
if(g_loop_sens_list.total > MAX_LOOP_SENS_AMOUNT)
{
g_loop_sens_list.total = MAX_LOOP_SENS_AMOUNT;
}
rBuf[i++] = g_loop_sens_list.total;
for(k = 0; k < MAX_LOOP_SENS_AMOUNT; k++)
{
rBuf[i++] = g_loop_sens_list.sens[k].sens_in;
rBuf[i++] = g_loop_sens_list.sens[k].sens_in >> 8;
rBuf[i++] = g_loop_sens_list.sens[k].sens_out;
rBuf[i++] = g_loop_sens_list.sens[k].sens_out >> 8;
}
write_cfg_to_store(0, rBuf, MAX_Store_Size);
free(rBuf);
}
void para_store_init(void)
{
uint8_t *rBuf = (uint8_t *)malloc(MAX_Store_Size);
if(rBuf == NULL){
SYS_ResetExecute();
}
memset(rBuf, 0, MAX_Store_Size);
read_cfg_from_store(0, rBuf, MAX_Store_Size);
if(rBuf[0] == 0x33 && rBuf[1] == 0xBB && rBuf[2] == 0xC3 && rBuf[3] == 0x3C){
memcpy(&g_loop_cng_unit, &rBuf[4], sizeof(g_loop_cng_unit));
memcpy(&g_loop_sens_list, &rBuf[Addr_Loop_Sens_List_Offset], sizeof(g_loop_sens_list));
g_rs485_id = rBuf[Addr_RS485_ID_Offset];
g_storage_uart_baud = rBuf[Addr_RS485_Baud_Offset] | (rBuf[Addr_RS485_Baud_Offset + 1] << 8) | (rBuf[Addr_RS485_Baud_Offset + 2] << 16);
g_max_counter_bt_min = rBuf[ADDR_BT_Close_TIMEOUT_Offset]; // unit: minute
g_max_counter_bt_timeout = g_max_counter_bt_min * 60 * 1000; // unit: ms
g_loop_out_delay = g_loop_cng_unit.delay_time * 2; // 定时器以 50ms 为单位, 延时以100ms为单位
g_hold_time = g_loop_cng_unit.exist_mode * 20 * 5; //50ms/per, period: 5s
g_safe_max_cnt = g_loop_cng_unit.loopSafe_Timeout * 10 * (1000 / 50);
g_freq_level = g_loop_cng_unit.loopFreq_Level - 1;
g_function_mode = g_loop_cng_unit.direction_mode >> 4;
g_fm_700bs_disable = g_function_mode & 0x01;
g_output_radar_mode = g_loop_cng_unit.direction_mode & 0x0F;
g_freq_sens = (g_loop_cng_unit.sensitvity > 0) ? (g_loop_cng_unit.sensitvity - 1) : 0;
#ifdef DEBUG
g_freq_level = 0;
#endif
// DLD154Pro: 一级调频, 0=66nF(低频), 1=33nF(高频)
if (g_freq_level == 0) {
FLEVEL_LOW;
} else {
FLEVEL_HIGH;
}
free(rBuf);
}
else{
free(rBuf);
set_factory_param();
factory_dev();
DelayMs(10);
SYS_ResetExecute();
}
}
static void pwm_led_init(void);
void tm_init(void){
// Cap 捕获
GPIOA_ResetBits(GPIO_Pin_9);
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeIN_Floating);
TMR0_CapInit(FallEdge_To_FallEdge);
TMR0_CAPTimeoutCfg(0xFFFFFFFF);
TMR0_ClearITFlag(TMR0_3_IT_DATA_ACT);
TMR0_ITCfg(ENABLE, TMR0_3_IT_DATA_ACT);
PFIC_EnableIRQ(TMR0_IRQn);
// TMR1
TMR1_TimerInit(FREQ_SYS / 200); // 设置定时时间 5ms
TMR1_ITCfg(ENABLE, TMR0_3_IT_CYC_END); // 开启中断
PFIC_EnableIRQ(TMR1_IRQn);
}
void gpio_uart_init(void)
{
// /*--- RS485 通信 (PA14=TX, PA15=RX, PA13=RE) ---*/
// rs485_init(); /* 初始化 UART0 + GPIO + 中断 */
// modbus_init(); /* 初始化 Modbus 协议状态 */
/*--- 光耦输入 (PB10=IN_1) ---*/
R32_PIN_CONFIG2 &= ~(1UL << 26); // 使能 PB10 数字输入 (默认关闭省电)
GPIOB_ModeCfg(GPIO_Pin_10, GPIO_ModeIN_PU);
/*--- 线圈调频 (PA12=FLEVEL, 一级) ---*/
GPIOA_SetBits(GPIO_Pin_12);
GPIOA_ModeCfg(GPIO_Pin_12, GPIO_ModeOut_PP_5mA);
FLEVEL_LOW; // 默认接入 66nF (低频)
/*--- 继电器 (PA8=RLY1) ---*/
GPIOA_SetBits(GPIO_Pin_8);
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeOut_PP_5mA);
RLY1_OFF;
/*--- LEDA 绿色 (PB22, GPIO, 低电平有效) ---*/
GPIOB_SetBits(GPIO_Pin_22);
GPIOB_ModeCfg(GPIO_Pin_22, GPIO_ModeOut_PP_5mA);
LEDA_OFF;
/*--- LEDB 红色 (PB23, PWM11, 呼吸灯) ---*/
pwm_led_init();
}
/*===========================================================================
* pwm_led_init -- 初始化 LEDB (PB23) 红色呼吸灯 (PWM11)
* PWM 频率 ≈ 60MHz / (80 * 128) ≈ 5.86kHz
* 初始占空比 = 0 (LED 灭)
* 注: PB23 需在 ISP 烧录时关闭外部复位功能 (RB_CFG_RESET_EN=0)
*===========================================================================*/
static void pwm_led_init(void)
{
GPIOB_SetBits(GPIO_Pin_23);
GPIOB_ModeCfg(GPIO_Pin_23, GPIO_ModeOut_PP_5mA);
PWMX_CLKCfg(PWM_CLK_DIV);
PWMX_CycleCfg(PWMX_Cycle_128); // 128 级占空比分辨率
PWMX_ACTOUT(CH_PWM11, 0, Low_Level, ENABLE); // 初始 duty=0, LED 灭
}
/*===========================================================================
* 一阶 IIR 低通滤波器 (对齐 M1H 公式)
* CAPVD_new = a * new_value + (1-a) * CAPVD_old, a = Flt_Reg/256
*===========================================================================*/
uint32_t get_flt_value(uint32_t new_value, uint32_t last_Value) {
uint32_t value_Flt;
uint32_t delta = (new_value > last_Value) ? (new_value - last_Value) : (last_Value - new_value);
uint32_t scaled_delta = (delta * (uint32_t)Flt_Reg) >> 8;
if (new_value > last_Value) {
value_Flt = last_Value + scaled_delta;
} else {
value_Flt = last_Value - scaled_delta;
}
return value_Flt;
}
/*===========================================================================
* 滑动平均基线更新
* 注意: window 必须是 uint16_t (WINDOW_ORIGIN=500 > 255, uint8_t 会静默截断)
*===========================================================================*/
void update_moving_average(uint32_t* p_sum, uint16_t* p_cnt, uint32_t* p_origin, uint32_t new_value, uint16_t window) {
if (!p_sum || !p_cnt || !p_origin || window == 0) {
return;
}
*p_sum += new_value;
(*p_cnt)++;
if (*p_cnt >= window) {
*p_origin = (uint32_t)(*p_sum / window);
*p_cnt = 0;
*p_sum = 0;
}
}
/*===========================================================================
* 初始化所有检测状态 (上电 / 有限存在超时 / 线圈重连 时调用)
* 注意: 不复位 g_loop_power_up_state / g_loop_cut_amount (BLE 上报用)
*===========================================================================*/
void INIT_VD(void)
{
loop1_INI_LOOP = 1;
loop1_LPCNT = 0;
loop1_INCNT = 0;
loop1_OUTCNT = 0;
loop1_CapCnt = 0;
loop1_CapSum = 0;
loop1_Value = 0;
loop1_CAPVD = 0;
loop1_Origin = 0;
loop1_VD_FLAG = 0;
loop1_RF_FLAG = 0;
loop1_LOOP_OK = 1;
loop1_LOOP_OK0 = 0;
loop1_CAP_OK = 0;
loop1_SensLevel = 2;
Flt_Reg = ALFA_CAP1; //79
loop1_ORG_CNT = 0;
loop1_ORG_SUM = 0;
loop1_FLAG_IN = 0;
loop1_FLAG_OUT = 0;
loop1_FLAG_PLUSE = 0;
loop1_FLAG_PLUSE_IN_F = 0;
loop1_FLAG_PLUSE_IN = 0;
loop1_FLAG_CUT = 0;
loop1_FLAG_HOLD_TIMEOUT = 0;
g_disconnect_active = 0;
loop1_VD_HOLD = 0;
Hold_CNT = 0;
loop1_LC_HOLD = 0;
loop1_LC_Reset = 0;
LC_Hold_CNT = 0;
/* 新算法状态 */
g_loop_stable = 0;
loop1_stable_cnt = 0;
loop1_entry_cnt = 0;
loop1_cnt_release = 0;
loop1_freeze_cnt = 0;
loop1_freeze_ref = 0;
#if USE_FLATNESS_EXIT
g_exit_state = 0;
g_max_slope = 0;
g_max_slope_rate = 0;
g_delta2 = 0;
g_delta3 = 0;
g_prev_capvd = 0;
g_prev_first_deriv = 0;
g_slope_flat_cnt = 0;
g_flat_ok_cnt = 0;
#endif
g_env_activity = 0;
g_env_prev_capvd = 0;
g_loop_acs_info.car_state = 0;
}
/*===========================================================================
* 车辆离开 / 释放 公共处理
*===========================================================================*/
static void loop_release_common(void)
{
loop1_VD_FLAG = 0;
loop1_FLAG_OUT = 1;
loop1_VD_HOLD = 0;
loop1_LC_HOLD = 0;
Hold_CNT = 0;
LC_Hold_CNT = 0;
loop1_ORG_CNT = 0;
loop1_ORG_SUM = 0;
g_loop_acs_info.flag_change = 1;
g_loop_acs_info.flag_event = 1;
g_loop_acs_info.car_state = 0;
}
/*===========================================================================
* vd1_task -- 核心检测算法 (移植 DLD154V4B, 每次 CAP_OK 调用, ~8.74ms)
*
* 流程:
* 1. IIR 滤波 + 斜率限幅
* 2. 稳定期: 小窗口快速收敛基线
* 3. 无车: 基线跟踪 (冻结保护) + 进入确认
* 4. 有车: 平坦性三条件离开判定 (带滞回)
*===========================================================================*/
void vd1_task(void){
if (loop1_Origin == 0) return;
/*--- 1. IIR 滤波 + 斜率限幅 ---*/
if (loop1_CAPVD == 0) {
loop1_CAPVD = loop1_Value;
} else {
int32_t raw_delta = (int32_t)loop1_Value - (int32_t)loop1_CAPVD;
int32_t max_step = (int32_t)(loop1_CAPVD * MAX_SLOPE_RATE / 100);
uint32_t clamped_value;
if (max_step < 100) max_step = 100;
if (raw_delta > max_step) raw_delta = max_step;
if (raw_delta < -max_step) raw_delta = -max_step;
clamped_value = (uint32_t)((int32_t)loop1_CAPVD + raw_delta);
loop1_CAPVD = get_flt_value(clamped_value, loop1_CAPVD);
}
/*--- 2. 稳定期: 绕过 IIR/斜率限幅, 小窗口快速收敛 ---*/
if (!g_loop_stable) {
loop1_CAPVD = loop1_Value;
update_moving_average(&loop1_ORG_SUM, &loop1_ORG_CNT, &loop1_Origin, loop1_CAPVD, 100);
loop1_stable_cnt++;
if (loop1_stable_cnt >= STABLE_SAMPLES) {
loop1_stable_cnt = 0;
g_loop_stable = 1;
}
return;
}
/*--- 3. BLE 上报状态刷新 (flag_change 置位期间冻结, 保持事件时刻的值) ---*/
if (g_loop_acs_info.flag_change == 0) {
int32_t _var = (int32_t)loop1_Origin - (int32_t)loop1_CAPVD;
g_loop_acs_info.loop_capvd = loop1_CAPVD;
g_loop_acs_info.variation = _var;
if (g_flag_bt_state && (_var > VARIATION_EVENT_TH || _var < -VARIATION_EVENT_TH)) {
g_loop_acs_info.flag_event = 1;
}
}
/*--- 4. 环境活跃度 (BLE condition 字段, 0~15) ---*/
{
int32_t d = (int32_t)loop1_CAPVD - (int32_t)g_env_prev_capvd;
if (d < 0) d = -d;
if (g_env_prev_capvd != 0 && d > ENV_ACT_TH) {
if (g_env_activity < 200) g_env_activity++;
} else {
if (g_env_activity) g_env_activity--;
}
g_env_prev_capvd = loop1_CAPVD;
}
if (!loop1_VD_FLAG) {
/*================================================================
* 无车状态: 基线跟踪 (冻结保护) + 进入确认
*================================================================*/
loop1_dlt_ORG = ((uint32_t)loop1_Origin * g_loop_sens_list.sens[g_freq_sens].sens_in) >> 16;
{
/* V4B V4.20 同步: 双向对称保护 — 负variation(铁块磁导率)也冻结基线
* 原单边只挡 dev>+4×dlt, 负variation会把Origin污染抬高 → 离开时假进入 → 锁死不释放
* 修复: ① 对称窗口 [-4×dlt, +4×dlt] ② 负偏差只冻结永不超时更新 */
int32_t dev = (int32_t)loop1_CAPVD - (int32_t)loop1_Origin;
int32_t freeze_band = (int32_t)(loop1_dlt_ORG * 4);
if (dev < freeze_band && dev > -freeze_band) {
/* 对称窗口内 → 正常基线跟踪 */
loop1_freeze_cnt = 0;
loop1_freeze_ref = 0;
update_moving_average(&loop1_ORG_SUM, &loop1_ORG_CNT, &loop1_Origin, loop1_CAPVD, WINDOW_ORIGIN);
} else if (dev < 0) {
/* 正variation (疑似车) → 冻结, 保留超时兜底更新 */
if (loop1_freeze_cnt == 0) {
loop1_freeze_ref = loop1_CAPVD;
} else {
int32_t drift = (int32_t)loop1_CAPVD - (int32_t)loop1_freeze_ref;
if (drift < 0) drift = -drift;
if (drift > (int32_t)(loop1_freeze_ref * FREEZE_STABILITY_RATE / 100)) {
loop1_freeze_cnt = 0;
loop1_freeze_ref = loop1_CAPVD;
}
}
loop1_freeze_cnt++;
if (loop1_freeze_cnt >= FREEZE_TIMEOUT) {
loop1_Origin = loop1_CAPVD; /* 确认稳定的新常态 */
loop1_freeze_cnt = 0;
loop1_freeze_ref = 0;
}
loop1_ORG_CNT = 0;
loop1_ORG_SUM = 0;
} else {
/* 负variation (CAPVD高于Origin, 特殊铁块磁导率主导) → 只冻结, 永不更新 Origin */
if (loop1_freeze_cnt == 0) {
loop1_freeze_ref = loop1_CAPVD;
}
loop1_freeze_cnt++;
if (loop1_freeze_cnt > FREEZE_TIMEOUT) loop1_freeze_cnt = FREEZE_TIMEOUT;
loop1_ORG_CNT = 0;
loop1_ORG_SUM = 0;
}
}
/*--- 进入确认: 连续 ENTRY_CONFIRM 次低于阈值才判有车 ---*/
if (loop1_CAPVD < (loop1_Origin - loop1_dlt_ORG)) {
loop1_entry_cnt++;
if (loop1_entry_cnt >= ENTRY_CONFIRM) {
loop1_entry_cnt = 0;
loop1_freeze_cnt = 0;
loop1_freeze_ref = 0;
loop1_VD_FLAG = 1;
loop1_FLAG_IN = 1;
if (g_loop_cng_unit.exist_mode) { /* 有限存在 */
loop1_VD_HOLD = 1;
Hold_CNT = 0;
}
if (g_loop_cng_unit.loopSafe_Timeout) { /* 线圈安全模式: 启动安全复位计时 */
loop1_LC_HOLD = 1;
LC_Hold_CNT = 0;
} else {
loop1_LC_HOLD = 0;
}
if (loop1_LC_Reset) {
loop1_LC_Reset = 0;
}
loop1_ORG_CNT = 0;
loop1_ORG_SUM = 0;
g_loop_acs_info.flag_change = 1;
g_loop_acs_info.flag_event = 1;
g_loop_acs_info.car_state = 1;
#if USE_FLATNESS_EXIT
/* 重置平坦性状态 (专利 CN200910309382) */
g_exit_state = 0;
g_max_slope = 0;
g_max_slope_rate = 0;
g_delta2 = 0;
g_delta3 = 0;
g_slope_flat_cnt = 0;
g_flat_ok_cnt = 0;
g_prev_capvd = (int32_t)loop1_CAPVD;
g_prev_first_deriv = 0;
#endif
}
} else {
if (loop1_entry_cnt > 0) loop1_entry_cnt = 0;
}
}
else {
#if USE_FLATNESS_EXIT
/*================================================================
* 有车状态: 平坦性三条件判定离开 (专利 CN200910309382)
* 幅值阈值按新测量基准 2^19 缩放 (DLD154V4B: 100/5/2 @2^17)
*================================================================*/
#define K1 8
#define K2 8
#define SLOPE_FLAT_THRESH 350
#define MIN_DELTA2 18
#define MIN_DELTA3 7
#define FLAT_CONFIRM_CNT 3
int32_t first_deriv, abs_fd, abs_sd, second_deriv;
first_deriv = (int32_t)loop1_CAPVD - g_prev_capvd;
second_deriv = first_deriv - g_prev_first_deriv;
abs_fd = (first_deriv >= 0) ? first_deriv : -first_deriv;
abs_sd = (second_deriv >= 0) ? second_deriv : -second_deriv;
if (g_exit_state == 0) {
/*--- 阶段0: 追踪第一上升坡面, 自适应计算平坦阈值 ---*/
if (abs_fd > (int32_t)g_max_slope) g_max_slope = (uint16_t)abs_fd;
if (abs_sd > (int32_t)g_max_slope_rate) g_max_slope_rate = (uint16_t)abs_sd;
if (abs_fd < SLOPE_FLAT_THRESH) {
g_slope_flat_cnt++;
if (g_slope_flat_cnt >= 3) {
g_delta2 = g_max_slope / K1;
g_delta3 = g_max_slope_rate / K2;
if (g_delta2 < MIN_DELTA2) g_delta2 = MIN_DELTA2;
if (g_delta3 < MIN_DELTA3) g_delta3 = MIN_DELTA3;
g_exit_state = 1;
g_flat_ok_cnt = 0;
}
} else {
g_slope_flat_cnt = 0;
}
} else {
/*--- 阶段1: 幅值回归 + 一阶平坦 + 二阶平坦 三条件确认离开 ---*/
int32_t dev = (int32_t)loop1_CAPVD - (int32_t)loop1_Origin;
int32_t cond1 = (dev >= 0) ? dev : -dev;
loop1_dlt_ORG = ((uint32_t)loop1_Origin * g_loop_sens_list.sens[g_freq_sens].sens_out) >> 16;
if (cond1 < (int32_t)loop1_dlt_ORG && abs_fd < (int32_t)g_delta2
&& abs_sd < (int32_t)g_delta3) {
g_flat_ok_cnt++;
if (g_flat_ok_cnt >= FLAT_CONFIRM_CNT) {
g_flat_ok_cnt = 0;
g_exit_state = 0;
loop_release_common();
}
} else {
g_flat_ok_cnt = 0;
}
}
g_prev_capvd = (int32_t)loop1_CAPVD;
g_prev_first_deriv = first_deriv;
#else
/*================================================================
* 有车状态: 简单滞回 + 防抖离开
*================================================================*/
loop1_dlt_ORG = ((uint32_t)loop1_Origin * g_loop_sens_list.sens[g_freq_sens].sens_out) >> 16;
if ((loop1_Origin - loop1_dlt_ORG) < loop1_CAPVD) {
loop1_cnt_release++;
if (loop1_cnt_release >= 3) {
loop1_cnt_release = 0;
loop_release_common();
}
} else {
if (loop1_cnt_release > 0) loop1_cnt_release = 0;
}
#endif
}
}
/*===========================================================================
* cjq_srv -- 车检器主循环服务
* - 有限存在超时 / 线圈断开重连: 全复位重建基线
* (线圈仍被占用时, 新基线落在占用值上, 继电器保持释放 -- 对齐 M1H 行为)
* - CAP_OK 到达时执行核心检测算法
*===========================================================================*/
void cjq_srv(void){
if(loop1_LOOP_OK){
if(loop1_FLAG_HOLD_TIMEOUT){
/* 有限存在超时: 全复位, 重新经历稳定期重建基线 */
INIT_VD();
return;
}
if(loop1_FLAG_CUT){
/* 线圈断开后重连: 不丢 VD_FLAG, CAPVD=0 直锁首个样本快速收敛 */
g_disconnect_active = 0;
loop1_FLAG_CUT = 0;
g_loop_cut_last = 0; // 同步复位边沿记忆, 确保下次断开触发计数
loop1_CAPVD = 0; // 首个样本直锁, 跳过 IIR
loop1_ORG_CNT = 0; // 丢弃断开期间过期数据
loop1_ORG_SUM = 0;
if(loop1_Origin == 0) {
/* Origin 意外丢失: 全复位 (不应发生, 做防御) */
INIT_VD();
}
return;
}
if(!loop1_LOOP_OK0){
DelayMs(200); /* 线圈重新起振后等待 200ms 再消费数据 */
loop1_LOOP_OK0 = 1;
}
if(loop1_CAP_OK){
loop1_CAP_OK = 0;
if(!g_loop_power_up_state){
g_loop_power_up_state = 1; // 表示连接了线圈
}
vd1_task();
}
}// end if loop1_LOOP_OK
else{
loop1_FLAG_CUT = 1;
g_disconnect_active = 1;
// 不丢 VD_FLAG (保留有车状态, 重连后恢复)
loop1_FLAG_IN = 0;
loop1_FLAG_OUT = 0;
loop1_FLAG_PLUSE = 0;
loop1_FLAG_PLUSE_IN_F = 0;
loop1_FLAG_PLUSE_IN = 0;
// 线圈断开: 继电器释放
RLY1_OFF;
g_loop_acs_info.relay1_state = 0;
g_loop_acs_info.car_state = 0;
if(g_loop_cut_last != loop1_FLAG_CUT){
g_loop_cut_last = loop1_FLAG_CUT;
if(g_loop_power_up_state){
g_loop_cut_amount++;
}
}
}
}
/*===========================================================================
* opt_input_poll — 光耦输入处理
*
* 产出 g_opt_trigger (1=有效, 0=无效),供继电器输出段融合判决。
* 各模式逻辑:
* MODE 0 (LOOP_OR_RADAR): g_opt_trigger = 光耦信号, 或关系
* MODE 1 (HUMAN_VD_MIX): 状态机 — 屏蔽→地感触发后解禁→离场 3s 防砸窗口
* MODE 2 (ETC): 状态机 — 屏蔽→地感触发后解禁→光耦断开 500ms 防抖
* MODE 3 (LOOP_AND_RADAR): g_opt_trigger = 光耦信号, 且关系
* MODE 4 (LOOP_ONLY): 光耦忽略, g_opt_trigger=0
* MODE 5 (RADAR_ONLY): g_opt_trigger = 光耦信号 (3 样本多数表决防抖)
* MODE 6 (LOOP_X_RESET): 光耦=复位信号,≥400ms 低电平后上升沿芯片复位
*
* 注意: mstick() 单位 5ms/tick
*===========================================================================*/
#define OPT_DEBOUNCE_CNT 6 // 防抖: 6 样本多数表决 (~30ms @5ms)
#define OPT_VM_WINDOW_TICK 600 // 人车混行防砸窗口: 600×5ms=3s
#define OPT_ETC_DEBOUNCE_TICK 100 // ETC 防抖: 100×5ms=500ms
/* 人车混行 / ETC 状态机 */
#define OPT_STATE_IDLE 0 // 雷达屏蔽,等线圈触发
#define OPT_STATE_ARMED 1 // 雷达解禁,地感 || 雷达
#define OPT_STATE_WINDOW 2 // 防砸窗口 (HUMAN_VD_MIX 专用)
#define OPT_STATE_DEBOUNCE 3 // 防抖释放 (ETC 专用)
static void opt_input_poll(void)
{
uint8_t raw = (OPT_IN1 == 0) ? 1 : 0; // 0=低电平有效→1=active
/*--- 光耦信号防抖: 3-sample 多数表决 ---*/
static uint8_t _db_hist = 0; // 位历史: bit0=最新
_db_hist = (uint8_t)((_db_hist << 1) | raw);
{
uint8_t ones = 0;
uint8_t mask = _db_hist & 0x07; // 取低 3 位
if (mask & 0x01) ones++;
if (mask & 0x02) ones++;
if (mask & 0x04) ones++;
raw = (ones >= 2) ? 1 : 0; // ≥2票 → 有效
}
/*================================================================
* 模式 6 — 光耦复位
*================================================================*/
if (g_output_radar_mode == OUTPUT_MODE_LOOP_X_RESET) {
static uint32_t _rst_low_since = 0;
static uint8_t _rst_armed = 0;
g_opt_trigger = 0;
if (OPT_IN1 == 0) { // 干接点接通 → 低电平
if (_rst_low_since == 0) {
_rst_low_since = mstick();
} else if (!_rst_armed && (mstick() - _rst_low_since >= 80)) {
_rst_armed = 1; // 满足 ≥400ms, 等待上升沿
}
} else { // 干接点断开 → 高电平
if (_rst_armed) {
SYS_ResetExecute(); // 上升沿触发芯片复位
}
_rst_low_since = 0;
_rst_armed = 0;
}
return;
}
/*================================================================
* 模式 4 — 纯地感
*================================================================*/
if (g_output_radar_mode == OUTPUT_MODE_LOOP_ONLY) {
g_opt_trigger = 0;
return;
}
/*================================================================
* 模式 0/3/5 — 或 / 且 / 纯雷达
* g_opt_trigger 直出光耦信号, 融合判决在继电器输出段
*================================================================*/
if (g_output_radar_mode == OUTPUT_MODE_RADAR_ONLY ||
g_output_radar_mode == OUTPUT_MODE_LOOP_OR_RADAR ||
g_output_radar_mode == OUTPUT_MODE_LOOP_AND_RADAR) {
g_opt_trigger = raw;
return;
}
/*================================================================
* 模式 1/2 — 人车混行 / ETC (状态机)
*================================================================*/
{
static uint8_t _opt_state = OPT_STATE_IDLE;
static uint8_t _opt_mode_last = 0xFF;
static uint32_t _opt_timer_start = 0;
/* 模式切换 → 状态机复位 */
if (_opt_mode_last != g_output_radar_mode) {
_opt_mode_last = g_output_radar_mode;
_opt_state = OPT_STATE_IDLE;
g_opt_trigger = 0;
return;
}
uint8_t coil_active = (loop1_VD_FLAG | loop1_FLAG_OUT) ? 1 : 0;
switch (_opt_state) {
case OPT_STATE_IDLE:
/* 雷达屏蔽, 等线圈触发 */
g_opt_trigger = 0;
if (coil_active) {
_opt_state = OPT_STATE_ARMED;
}
break;
case OPT_STATE_ARMED:
/* 雷达解禁: 地感 || 雷达 (OR 关系) */
g_opt_trigger = raw;
if (!coil_active && !raw) {
/* 两者均释放 → 进入释放过渡 */
if (g_output_radar_mode == OUTPUT_MODE_HUMAN_VD_MIX) {
_opt_state = OPT_STATE_WINDOW;
_opt_timer_start = mstick();
} else { // ETC
_opt_state = OPT_STATE_DEBOUNCE;
_opt_timer_start = mstick();
}
}
break;
case OPT_STATE_WINDOW: /* HUMAN_VD_MIX 专用: 3s 防砸窗口 */
if (coil_active) {
/* 车辆重新上线圈 → 回到解禁态 */
_opt_state = OPT_STATE_ARMED;
g_opt_trigger = raw;
} else if (raw) {
/* 雷达检测到人 → 立即触发, 窗口复位 */
g_opt_trigger = 1;
_opt_timer_start = mstick();
} else {
g_opt_trigger = 0;
if (mstick() - _opt_timer_start >= OPT_VM_WINDOW_TICK) {
/* 3s 内无雷达触发 → 回到屏蔽态, 落杆 */
_opt_state = OPT_STATE_IDLE;
}
}
break;
case OPT_STATE_DEBOUNCE: /* ETC 专用: 500ms 防抖 */
if (coil_active || raw) {
/* 重新触发 → 取消防抖, 回到解禁态 */
_opt_state = OPT_STATE_ARMED;
g_opt_trigger = raw;
} else {
g_opt_trigger = 0;
if (mstick() - _opt_timer_start >= OPT_ETC_DEBOUNCE_TICK) {
/* 500ms 无触发 → 确认释放 */
_opt_state = OPT_STATE_IDLE;
}
}
break;
default:
_opt_state = OPT_STATE_IDLE;
g_opt_trigger = 0;
break;
}
}
}
void poll_wdg(void)
{
if(g_wdg_counter >= 100) //500ms
{
g_wdg_counter = 0;
WWDG_SetCounter(0);
}
}
/*********************************************************************
* @fn Main_Circulation
*
* @brief 主循环
*
* @return none
*/
__HIGH_CODE
__attribute__((noinline))
void Main_Circulation()
{
while(1)
{
TMOS_SystemProcess();
poll_dbn_ble();
cjq_srv();
opt_input_poll(); // 光耦输入处理 (复位 / 雷达)
if (g_fm_700bs_disable) {
modbus_poll(); // RS485 Modbus RTU 协议
} else {
rs485_poll(); // RS485 700BS 协议: 命令处理 + 心跳上报
}
if(g_flag_bt_state == 0){
// 如果蓝牙断开,主动上报需要禁用
if(g_dbn_ble_state_acs_enable.enable){
g_dbn_ble_state_acs_enable.enable = 0;
}
}
poll_wdg(); // 喂狗
}
}
/*********************************************************************
* @fn main
*
* @brief 主函数
*
* @return none
*/
int main(void)
{
uint8_t i;
#if(defined(DCDC_ENABLE)) && (DCDC_ENABLE == TRUE)
PWR_DCDCCfg(ENABLE);
#endif
SetSysClock(CLK_SOURCE_PLL_60MHz);
#if(defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
#endif
gpio_uart_init();
g_sys_freq = FREQ_SYS;
GetMACAddress(MACAddr);
for(i = 0; i < 6; i++)
{
g_dev_number[i] = MACAddr[i];
}
g_loop_sens_list.total = MAX_LOOP_SENS_AMOUNT; // max
INIT_VD();
para_store_init();
/*--- RS485 通信 (PA14=TX, PA15=RX, PA13=RE) ---*/
rs485_init(); /* 初始化 UART0 + GPIO + 中断 */
modbus_init(); /* 初始化 Modbus 协议状态 */
tm_init();
CH59x_BLEInit();
HAL_Init();
GAPRole_PeripheralInit();
Peripheral_Init();
/* 使能看门狗复位: 超时 ~558ms, 主循环喂狗 */
WWDG_ResetCfg(ENABLE);
WWDG_SetCounter(0);
Main_Circulation();
}
/* @fn TMR0_IRQHandler
*
* @brief TMR0 输入捕获中断 -- 线圈频率测量
* FallEdge_To_FallEdge 模式, CAPGetData 直接给出相邻下降沿周期 Xn
* 累加 LPCNT 次 -> 一个测量窗 Value (~= MEASUREMENT_BASE)
*
* @return none
*/
__INTERRUPT
__HIGH_CODE
void TMR0_IRQHandler(void) // TMR0 捕获中断
{
if(TMR0_GetITFlag(TMR0_3_IT_DATA_ACT)){
loop1_Xn = (uint16_t)TMR0_CAPGetData();
if(loop1_Xn == 0){
R8_TMR0_INT_FLAG |= 0xff;
return;
}
if(!loop1_RF_FLAG){
loop1_RF_FLAG = 1;
}
else{
loop1_CapCnt++;
if(loop1_INI_LOOP){
/*--- 初始化阶段 ---*/
if(loop1_LPCNT == 0){
if(loop1_CapCnt > 200){ /* 上电/换频后等待振荡稳定 */
uint32_t lpcnt = (uint32_t)MEASUREMENT_BASE / loop1_Xn;
if(lpcnt == 0 || lpcnt > 65535){
lpcnt = 100; /* 异常 Xn 保护 */
}
loop1_LPCNT = (uint16_t)lpcnt;
g_freq_tmp = (float)g_sys_freq/((float)loop1_Xn);
loop1_CAPVD = 0;
loop1_CapSum = 0;
loop1_CapCnt = 0;
}
}
else{
/* 第一个测量窗: 直接作为基线 Origin */
loop1_CapSum += loop1_Xn;
if(loop1_CapCnt >= loop1_LPCNT){
loop1_CAPVD = loop1_CapSum;
loop1_Origin = loop1_CAPVD;
if(g_loop_acs_info.flag_change == 0){
g_loop_acs_info.loop_capvd = loop1_CAPVD;
}
loop1_INI_LOOP = 0;
loop1_CapSum = 0;
loop1_Value = 0;
loop1_CapCnt = 0;
}
}
}// end if loop1_INI_LOOP
else {
/*--- 正常运行: 累加到测量窗 ---*/
loop1_CapSum += loop1_Xn;
if(loop1_CapCnt >= loop1_LPCNT){
loop1_Value = loop1_CapSum;
loop1_CAP_OK = 1;
loop1_CapSum = 0;
loop1_CapCnt = 0;
}
}
}
R8_TMR0_INT_FLAG |= 0xff;
}
}
/*********************************************************************
* @fn TMR1_IRQHandler
*
* @brief TMR1 定时中断 5ms/per -- 时序状态机 / 继电器输出 / LED
*
* @return none
*/
__INTERRUPT
__HIGH_CODE
void TMR1_IRQHandler(void)
{
static uint16_t _counter1_init = 0;
if(TMR1_GetITFlag(TMR0_3_IT_CYC_END))
{
if(g_dbn_ble_state_acs_enable.enable && g_flag_bt_state){
g_loop_acs_info.report_counter++;
}
TimingDelayInc++;
g_wdg_counter++;
/*--- LED: 断开中 200ms 快闪; 稳定期 200ms 慢闪 ---*/
if(g_disconnect_active || !g_loop_power_up_state)
{
/* 线圈断开中 / 上电从未连接 → 200ms 快闪 (故障指示) */
_counter1_init++;
if(_counter1_init >= 40) // 40: 200ms
{
_counter1_init = 0;
LEDA_ON_OFF();
}
}
else if(!g_loop_stable)
{
/* 稳定期 → 200ms 慢闪 (自检中) */
_counter1_init++;
if(_counter1_init >= 40) // 40: 200ms
{
_counter1_init = 0;
LEDA_ON_OFF();
}
}
TM1cnt++;
if(TM1cnt >= 10) //about=50ms
{
TM1cnt = 0;
if(loop1_FLAG_IN) // 线圈1 从无车到有车
{
loop1_FLAG_OUT = 0;
loop1_OUTCNT = 0;
loop1_FLAG_IN = 0;
if(g_loop_cng_unit.output_mode == 1) // 进入脉冲
{
loop1_FLAG_PLUSE_IN_F = 1;
}
loop1_INCNT = 0;
LEDA_ON;
}
if(loop1_FLAG_PLUSE_IN_F)
{
loop1_INCNT++;
if(loop1_INCNT > g_loop_out_delay)
{
loop1_INCNT = 0;
loop1_FLAG_PLUSE_IN_F = 0;
loop1_FLAG_PLUSE_IN = 1;
}
}
if(loop1_FLAG_PLUSE_IN)
{
loop1_INCNT++;
if(loop1_INCNT > IN_DELAY) // 500ms
{
loop1_INCNT = 0;
loop1_FLAG_PLUSE_IN = 0;
}
}
if(loop1_FLAG_OUT) // 从有车到无车的标志
{
loop1_OUTCNT++;
if(loop1_OUTCNT > g_loop_out_delay)
{
loop1_FLAG_OUT = 0;
loop1_FLAG_PLUSE = 1;
loop1_OUTCNT = 0;
LEDA_OFF;
}
}
if(loop1_FLAG_PLUSE) // Give 500ms
{
loop1_OUTCNT++;
if(loop1_OUTCNT > PLUSE_DELAY)
{
loop1_FLAG_PLUSE = 0;
loop1_OUTCNT = 0;
}
}
/*--- 光耦参与模式: LED 同步继电器实际状态 ---*/
/* (非 LOOP_ONLY/LOOP_X_RESET 时开启) ---*/
/* 断开/稳定期闪烁已在 5ms 段优先处理 ---*/
if (g_output_radar_mode != OUTPUT_MODE_LOOP_ONLY
&& g_output_radar_mode != OUTPUT_MODE_LOOP_X_RESET
&& !g_disconnect_active
&& g_loop_power_up_state
&& g_loop_stable) {
if (g_loop_acs_info.relay1_state) LEDA_ON;
else LEDA_OFF;
}
if(loop1_VD_HOLD)
{
Hold_CNT++;
if(Hold_CNT > g_hold_time) // 超过有限存在时间
{
loop1_VD_HOLD = 0;
Hold_CNT = 0;
if(loop1_VD_FLAG)
{
/* 有限存在超时: 释放继电器, 主循环全复位重建基线 */
loop1_FLAG_HOLD_TIMEOUT = 1;
RLY1_OFF;
g_loop_acs_info.relay1_state = 0;
}
}
}
if(loop1_LC_HOLD)
{
LC_Hold_CNT++;
if(LC_Hold_CNT > g_safe_max_cnt)
{
/* 安全复位: 重新初始化测量, 重建基线 (对齐 M1H) */
loop1_LC_Reset = 1;
loop1_INI_LOOP = 1;
loop1_LOOP_OK0 = 0;
g_loop_stable = 0;
loop1_stable_cnt = 0;
LC_Hold_CNT = 0;
loop1_ORG_CNT = 0;
loop1_ORG_SUM = 0;
#if USE_FLATNESS_EXIT
g_exit_state = 0;
g_max_slope = 0;
g_max_slope_rate = 0;
g_slope_flat_cnt = 0;
g_flat_ok_cnt = 0;
#endif
}
}
/*--- LEDB 红色呼吸灯 (PWM11, 50ms tick, 光耦有信号时加速 ~1s) ---*/
{
uint8_t _step, _hold;
/* 非复位模式下光耦有信号 → 红灯快闪 (现场判断光耦是否正常) */
if (g_opt_trigger && g_output_radar_mode != OUTPUT_MODE_LOOP_X_RESET) {
_step = BREATH_OPTO_DUTY_STEP;
_hold = BREATH_OPTO_HOLD_TICKS;
} else {
_step = BREATH_DUTY_STEP;
_hold = BREATH_HOLD_TICKS;
}
g_breath_tick++;
switch (g_breath_phase) {
case BREATH_FADE_IN:
if (g_breath_tick >= BREATH_STEP_DELAY) {
g_breath_tick = 0;
if (g_breath_duty + _step >= PWM_CYCLE) {
g_breath_duty = PWM_CYCLE - 1;
g_breath_phase = BREATH_HOLD_HIGH;
g_breath_tick = 0;
} else {
g_breath_duty += _step;
}
PWM11_ActDataWidth(g_breath_duty);
}
break;
case BREATH_HOLD_HIGH:
if (g_breath_tick >= _hold) {
g_breath_phase = BREATH_FADE_OUT;
g_breath_tick = 0;
}
break;
case BREATH_FADE_OUT:
if (g_breath_tick >= BREATH_STEP_DELAY) {
g_breath_tick = 0;
if (g_breath_duty <= _step) {
g_breath_duty = 0;
g_breath_phase = BREATH_HOLD_LOW;
g_breath_tick = 0;
} else {
g_breath_duty -= _step;
}
PWM11_ActDataWidth(g_breath_duty);
}
break;
case BREATH_HOLD_LOW:
if (g_breath_tick >= _hold) {
g_breath_phase = BREATH_FADE_IN;
g_breath_tick = 0;
}
break;
}
}
}
/*--- 线圈载波检测 & 继电器输出刷新 (每 5ms) ---*/
if(loop1_RF_FLAG)
{
loop1_LOOP_OK = 1;
loop1_RF_FLAG = 0;
if(loop1_LC_Reset == 0)
{
switch(g_loop_cng_unit.output_mode)
{ // 输出方式
case 0: // 存在输出 (线圈+光耦融合判决)
{
uint8_t coil_sig = (loop1_VD_FLAG | loop1_FLAG_OUT) ? 1 : 0;
uint8_t relay_on = 0;
switch (g_output_radar_mode) {
case OUTPUT_MODE_LOOP_ONLY:
case OUTPUT_MODE_LOOP_X_RESET:
relay_on = coil_sig;
break;
case OUTPUT_MODE_RADAR_ONLY:
relay_on = g_opt_trigger;
break;
case OUTPUT_MODE_LOOP_OR_RADAR:
relay_on = coil_sig || g_opt_trigger;
break;
case OUTPUT_MODE_LOOP_AND_RADAR:
relay_on = coil_sig && g_opt_trigger;
break;
case OUTPUT_MODE_HUMAN_VD_MIX:
case OUTPUT_MODE_ETC:
relay_on = coil_sig || g_opt_trigger;
break;
default:
relay_on = coil_sig;
break;
}
if(relay_on)// 输出存在信号
{
RLY1_ON;
g_loop_acs_info.relay1_state = 1;
}
else
{
RLY1_OFF;
g_loop_acs_info.relay1_state = 0;
}
} break;
case 1: // 进入脉冲
{
if(loop1_FLAG_PLUSE_IN)
{
RLY1_ON;
g_loop_acs_info.relay1_state = 1;
}
else
{
RLY1_OFF;
g_loop_acs_info.relay1_state = 0;
}
} break;
case 2: // 离开脉冲
{
if(loop1_FLAG_PLUSE) // 输出离开脉冲
{
RLY1_ON;
g_loop_acs_info.relay1_state = 1;
}
else
{
RLY1_OFF;
g_loop_acs_info.relay1_state = 0;
}
} break;
default: {
// DLD154Pro 单继电器, 默认存在模式
if(loop1_VD_FLAG)
{
RLY1_ON;
g_loop_acs_info.relay1_state = 1;
}
else
{
RLY1_OFF;
g_loop_acs_info.relay1_state = 0;
}
} break;
}
}// end if loop1_LC_Reset == 0
} // end if loop1_RF_FLAG
else
{
loop1_LOOP_OK0 = loop1_LOOP_OK;
loop1_LOOP_OK = 0;
}
TMR1_ClearITFlag(TMR0_3_IT_CYC_END); // 清除中断标志
}
}
/******************************** endfile @ main ******************************/