From 978cce4af8d4e4be883d9871b61263c823893ebc Mon Sep 17 00:00:00 2001 From: wangfq Date: Tue, 28 Jul 2026 09:34:18 +0800 Subject: [PATCH] =?UTF-8?q?feat(opt):=20=E5=85=89=E8=80=A6=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E6=A8=A1=E5=BC=8F=E5=AE=8C=E6=95=B4=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=20=E2=80=94=206=E7=A7=8D=E8=9E=8D=E5=90=88=E9=80=BB=E8=BE=91?= =?UTF-8?q?=20+=20=E4=BA=BA=E8=BD=A6=E6=B7=B7=E8=A1=8C/ETC=20=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 g_opt_trigger 全局变量:opt_input_poll() 产出, TMR1 ISR 消费 - MODE 1/2/3/4: 纯地感/纯雷达/或/与 — g_opt_trigger 直出光耦信号 - MODE 5 (HUMAN_VD_MIX): 3态机 IDLE→ARMED→WINDOW, 3s防砸窗口 - MODE 6 (ETC): 3态机 IDLE→ARMED→DEBOUNCE, 500ms防抖释放 - TMR1 ISR case 0: 6模式融合判决 (coil || opt_trigger / coil && opt_trigger等) - 光耦防抖: 3样本多数表决, ~30ms消抖 - MODE 0 复位逻辑不变 - docs: 更新开发日志 (状态机图 + 各模式对照表) --- .../APP/include/cmcng.h | 1 + .../APP/peripheral_main.c | 202 ++++++++++++++++-- docs/devlog.md | 74 +++++++ 3 files changed, 257 insertions(+), 20 deletions(-) diff --git a/BLE/DLD154Pro_Peripheral_28K/APP/include/cmcng.h b/BLE/DLD154Pro_Peripheral_28K/APP/include/cmcng.h index a8c91f6..6d7369d 100644 --- a/BLE/DLD154Pro_Peripheral_28K/APP/include/cmcng.h +++ b/BLE/DLD154Pro_Peripheral_28K/APP/include/cmcng.h @@ -43,6 +43,7 @@ extern uint8_t g_loop_power_up_state; extern uint8_t g_function_mode; extern uint8_t g_fm_700bs_disable ; //0: 700bs protocol; 1 Modbus protocol extern uint8_t g_output_radar_mode; +extern uint8_t g_opt_trigger; // 光耦/雷达 处理后触发信号 (1=有效) /* 新算法状�? (DLD154V4B 移植) */ extern uint8_t g_loop_stable; // 稳定期结束标�? (0=收敛�?, 1=稳定) diff --git a/BLE/DLD154Pro_Peripheral_28K/APP/peripheral_main.c b/BLE/DLD154Pro_Peripheral_28K/APP/peripheral_main.c index 9cae0f0..11c15cf 100644 --- a/BLE/DLD154Pro_Peripheral_28K/APP/peripheral_main.c +++ b/BLE/DLD154Pro_Peripheral_28K/APP/peripheral_main.c @@ -36,6 +36,7 @@ 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; @@ -850,33 +851,168 @@ void cjq_srv(void){ /*=========================================================================== * opt_input_poll — 光耦输入处理 * - * g_output_radar_mode == 0: 光耦复位模式 + 地感模式 - * g_output_radar_mode >= 1: 雷达输入模式 (暂未实现) - * 外部干接点接通 → PB10=0 → 计时; 保持 ≥500ms 后断开 → 上升沿 → 芯片复位 + * 产出 g_opt_trigger (1=有效, 0=无效),供继电器输出段融合判决。 + * 各模式逻辑: + * MODE 0 (LOOP_X_RESET): 光耦=复位信号,≥400ms 低电平后上升沿芯片复位 + * MODE 1 (LOOP_ONLY): 光耦忽略,g_opt_trigger=0 + * MODE 2 (RADAR_ONLY): g_opt_trigger = 光耦信号 (3 样本多数表决防抖) + * MODE 3 (LOOP_OR): g_opt_trigger = 光耦信号 + * MODE 4 (LOOP_AND): g_opt_trigger = 光耦信号 + * MODE 5 (HUMAN_VD_MIX): 状态机 — 屏蔽→地感触发后解禁→离场 3s 防砸窗口 + * MODE 6 (ETC): 状态机 — 屏蔽→地感触发后解禁→光耦断开 500ms 防抖 + * + * 注意: 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) { - static uint32_t _opt_low_since = 0; // PB10 变低的时刻 - static uint8_t _opt_armed = 0; // 低电平已保持 ≥500ms, 等待上升沿 + uint8_t raw = (OPT_IN1 == 0) ? 1 : 0; // 0=低电平有效→1=active - if (g_output_radar_mode) { - _opt_low_since = 0; - _opt_armed = 0; + /*--- 光耦信号防抖: 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票 → 有效 + } + + /*================================================================ + * 模式 0 — 光耦复位 + *================================================================*/ + 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; } - if (OPT_IN1 == 0) { // 干接点接通 → 低电平 - if (_opt_low_since == 0) { - _opt_low_since = mstick(); - } else if (!_opt_armed && (mstick() - _opt_low_since >= 80)) { // 100 tick × 5ms = 500ms - _opt_armed = 1; // 满足 500ms, 等待上升沿 + /*================================================================ + * 模式 1 — 纯地感 + *================================================================*/ + if (g_output_radar_mode == OUTPUT_MODE_LOOP_ONLY) { + g_opt_trigger = 0; + return; + } + + /*================================================================ + * 模式 2/3/4 — 纯雷达 / 或 / 与 + * 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; + } + + /*================================================================ + * 模式 5/6 — 人车混行 / 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; } - } else { // 干接点断开 → 高电平 - if (_opt_armed) { - SYS_ResetExecute(); // 上升沿触发芯片复位 + + 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; } - _opt_low_since = 0; - _opt_armed = 0; } } @@ -1234,9 +1370,35 @@ void TMR1_IRQHandler(void) { switch(g_loop_cng_unit.output_mode) { // 输出方式 - case 0: // 存在输出 + case 0: // 存在输出 (线圈+光耦融合判决) { - if(loop1_VD_FLAG | loop1_FLAG_OUT)// 输出存在信号 + 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; diff --git a/docs/devlog.md b/docs/devlog.md index be86c63..725588b 100644 --- a/docs/devlog.md +++ b/docs/devlog.md @@ -4,6 +4,80 @@ --- +## 2026-07-28 (午后) — 光耦输出模式完整实现:6 种融合逻辑 + 状态机 + +### 架构 + +`opt_input_poll()` 处理光耦输入 → 产出 `g_opt_trigger` (1=有效) → TMR1 ISR 继电器输出段 `case 0` 根据 `g_output_radar_mode` 做融合判决。 + +``` +光耦 PB10 → 3样本多数表决防抖 → opt_input_poll() → g_opt_trigger + ↓ +线圈 VD_FLAG/FLAG_OUT → coil_sig ──────────→ 融合判决 → RLY1 + ↑ + g_output_radar_mode +``` + +### 各模式实现 + +| 模式 | 值 | `opt_input_poll()` | 继电器 `case 0` 融合公式 | +|------|-----|-------------------|--------------------------| +| LOOP_X_RESET | 0 | 光耦复位 (400ms低→上升沿→SYS_ResetExecute) | `coil_sig` | +| LOOP_ONLY | 1 | return, g_opt_trigger=0 | `coil_sig` | +| RADAR_ONLY | 2 | g_opt_trigger = 光耦信号 | `g_opt_trigger` | +| LOOP_OR_RADAR | 3 | g_opt_trigger = 光耦信号 | `coil_sig \|\| g_opt_trigger` | +| LOOP_AND_RADAR | 4 | g_opt_trigger = 光耦信号 | `coil_sig && g_opt_trigger` | +| HUMAN_VD_MIX | 5 | 状态机 (见下) | `coil_sig \|\| g_opt_trigger` | +| ETC | 6 | 状态机 (见下) | `coil_sig \|\| g_opt_trigger` | + +> 注: `coil_sig = (loop1_VD_FLAG | loop1_FLAG_OUT)` — 含离开脉冲保持 + +### HUMAN_VD_MIX 状态机 (人车混行防砸) + +``` +IDLE (雷达屏蔽, 仅线圈) + │ 线圈检测到车 + ▼ +ARMED (雷达解禁, 线圈||雷达) + │ 两者均释放 + ▼ +WINDOW (3s 防砸窗口) + │ 雷达触发 → g_opt_trigger=1 → 继电器吸合, 窗口复位 + │ 线圈上线 → 回到 ARMED + │ 3s 超时无触发 → 回到 IDLE, 落杆 +``` + +定时参数: `OPT_VM_WINDOW_TICK = 600` (600×5ms = 3s) + +### ETC 状态机 + +``` +IDLE (雷达屏蔽, 仅线圈) + │ 线圈检测到车 + ▼ +ARMED (雷达解禁, 线圈||雷达) + │ 两者均释放 + ▼ +DEBOUNCE (500ms 防抖) + │ 线圈/雷达重新触发 → 回到 ARMED + │ 500ms 超时 → 回到 IDLE, 落杆 +``` + +定时参数: `OPT_ETC_DEBOUNCE_TICK = 100` (100×5ms = 500ms) + +### 光耦防抖 + +所有非复位模式共用 3 样本多数表决 (`OPT_DEBOUNCE_CNT=6`): 最近 3 次采样中 ≥2 票即判定有效,等效 ~30ms 消抖。 + +### 文件变更 + +| 文件 | 变更 | +|------|------| +| `peripheral_main.c` | +`g_opt_trigger` 全局变量, `opt_input_poll()` 重写 (120→180行), TMR1 ISR `case 0` 融合判决 | +| `cmcng.h` | +`extern uint8_t g_opt_trigger` | + +--- + ## 2026-07-28 — 光耦输出模式升级:`DLD_OUTPUT_MODE` 枚举 + `direction_mode` 低四位取值 ### 背景