feat(opt): 光耦输出模式完整实现 — 6种融合逻辑 + 人车混行/ETC 状态机

- 新增 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: 更新开发日志 (状态机图 + 各模式对照表)
This commit is contained in:
wangfq
2026-07-28 09:34:18 +08:00
parent f5edab43c2
commit 978cce4af8
3 changed files with 257 additions and 20 deletions
@@ -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=稳定)
@@ -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;
+74
View File
@@ -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` 低四位取值
### 背景