/* * Lamp Protection Module - v3.2 (Optimized for fast short detection) * * 改进: * - 高电流持续时间阈值降低至1200ms * - 增加快速短路条件(峰值≥3500且下降≥2500且当前≤1500) * - 稳定期内保持起始电流不变,避免高电流覆盖 */ /*********************↓ include ↓************************/ #define DBG_TAG "LAMP_PROT" #define DBG_LVL DBG_INFO #include #include #include #include #include #include "ecode.h" #include "ym310_protecl.h" /*********************↑ include ↑************************/ /*********************↓ define ↓************************/ #define DETECT_MS 500 /* 检测周期,与ADC一致 */ #define STABLE_MS 500 /* 开启后稳定等待时间(1个周期) */ #define OPEN_TRIGGER_MS 10000 /* 开路触发时间(10秒) */ #define RECOVER_STABLE_MS 30000 /* 恢复所需稳定时间(30秒) */ /* 短路特征阈值 */ #define RISE_THRESH 1000 /* 上升≥1000(情景A) */ #define FALL_THRESH_A 2000 /* 情景A下降阈值 */ #define HIGH_CURRENT 3300 /* 高电流阈值(情景B) */ #define HIGH_DUR_MS 1000 /* 高电流持续时间(1秒) */ #define FALL_THRESH_B 2500 /* 情景B下降阈值(略降提高灵敏度) */ /* 快速短路条件(独立于持续时间) */ #define FAST_PEAK_THRESH 3500 /* 快速短路峰值阈值 */ #define FAST_FALL_THRESH 2500 /* 快速短路下降阈值 */ #define FAST_CURRENT_MAX 1500 /* 快速短路时当前电流最大值 */ #define OPEN_MAX 100 /* 开路电流最大值 */ #define NORMAL_MIN 1000 /* 正常电流最小值 */ #define LAMP_FAULT_NONE 0 #define LAMP_FAULT_OPEN 0x7A #define LAMP_FAULT_SHORT 0x9D #define LAMP_PIN GET_PIN(B, 5) #define LAMP_ON PIN_HIGH #define LAMP_OFF PIN_LOW /*********************↑ define ↑************************/ /*********************↓ 外部变量/函数声明 ↓***********************/ extern SYS_STATUS sys_sta; extern DEV_INFO dev_info; extern void save_dev_info(void); extern void report_now(void); extern void gpio_lamp_ctrl(uint8_t state); extern void gpio_hv_ctrl(uint8_t state); /*********************↑ 外部变量/函数声明 ↑***********************/ /*********************↓ 静态变量 ↓***********************/ static rt_thread_t s_thread = RT_NULL; /* 开路检测 */ static uint32_t s_open_start_ms = 0; /* 短路检测 */ static uint32_t s_start_current = 0; /* 稳定期开始时的起始电流(固定值) */ static uint32_t s_peak_current = 0; /* 检测到的峰值(稳定期内也记录) */ static uint32_t s_high_start_ms = 0; /* 高电流开始时间(稳定期内也记录) */ static uint8_t s_short_triggered = 0; /* 本次开启周期是否已触发短路保护 */ /* 恢复检测 */ static uint32_t s_recover_start_ms = 0; /* 稳定正常开始时间 */ static uint8_t s_last_fault = 0; /* 记录当前保护类型 */ /* 灯管开启后的稳定延迟 */ static uint32_t s_stable_until_ms = 0; /* 稳定期结束的时间点 */ /*********************↑ 静态变量 ↑************************/ /*********************↓ 内部辅助函数 ↓************************/ static void reset_all_state(void) { s_open_start_ms = 0; s_start_current = 0; s_peak_current = 0; s_high_start_ms = 0; s_short_triggered = 0; s_recover_start_ms = 0; s_stable_until_ms = 0; } /* 触发短路保护(关灯、关机、上报) */ static void trigger_short(uint32_t current) { if (s_short_triggered) return; s_short_triggered = 1; sys_sta.lamp_fault = LAMP_FAULT_SHORT; s_last_fault = LAMP_FAULT_SHORT; LOG_W("[SHORT] Triggered! peak=%d, curr=%d", s_peak_current, current); gpio_lamp_ctrl(0); gpio_hv_ctrl(0); dev_info.power_state = 0; save_dev_info(); Recode_e_code(e_protect, current, "灯管短路保护触发"); report_now(); } /* 触发开路保护(只上报,不关灯) */ static void trigger_open(uint32_t current) { if (sys_sta.lamp_fault == LAMP_FAULT_OPEN) return; sys_sta.lamp_fault = LAMP_FAULT_OPEN; s_last_fault = LAMP_FAULT_OPEN; LOG_W("[OPEN] Triggered! current=%d", current); Recode_e_code(e_protect, current, "灯管开路故障"); report_now(); } /* 清除保护(恢复) */ static void clear_protection(void) { if (sys_sta.lamp_fault == LAMP_FAULT_OPEN) { sys_sta.lamp_fault = LAMP_FAULT_NONE; LOG_I("[OPEN] Cleared"); Recode_e_code(e_protect, 0, "灯管开路故障恢复"); report_now(); } else if (sys_sta.lamp_fault == LAMP_FAULT_SHORT) { sys_sta.lamp_fault = LAMP_FAULT_NONE; LOG_I("[SHORT] Cleared"); Recode_e_code(e_protect, 0, "灯管短路保护解除"); report_now(); } s_recover_start_ms = 0; s_last_fault = LAMP_FAULT_NONE; } /*********************↑ 内部辅助函数 ↑***********************/ /*********************↓ 主线程(极简流程) ↓***********************/ static void lamp_protect_entry(void *param) { uint32_t now, current; uint8_t lamp_on; uint32_t rise, fall; rt_thread_mdelay(6*1000); char off_lamp_proc = 0; ef_get_env_blob("off_lamp_proc", &off_lamp_proc, sizeof(off_lamp_proc), NULL); if(off_lamp_proc == VALID) { LOG_W("JUMP lamp_protect_entry"); } while (1) { while (rt_pin_read(LAMP_PIN) != LAMP_ON) { rt_thread_mdelay(DETECT_MS); } reset_all_state(); s_stable_until_ms = rt_tick_get_millisecond() + STABLE_MS; s_start_current = sys_sta.lamp_current; s_peak_current = s_start_current; LOG_I(" Lamp ON, stable until %lu, start_current=%d", s_stable_until_ms, s_start_current); while (rt_pin_read(LAMP_PIN) == LAMP_ON) { now = rt_tick_get_millisecond(); current = sys_sta.lamp_current; if (now < s_stable_until_ms) { if (current > s_peak_current) s_peak_current = current; if (current >= HIGH_CURRENT) { if (s_high_start_ms == 0) s_high_start_ms = now; } else { s_high_start_ms = 0; } rt_thread_mdelay(DETECT_MS); continue; } if (sys_sta.lamp_fault != LAMP_FAULT_OPEN) { if (current <= OPEN_MAX) { if (s_open_start_ms == 0) s_open_start_ms = now; if (now - s_open_start_ms >= OPEN_TRIGGER_MS) { trigger_open(current); s_open_start_ms = 0; } } else { s_open_start_ms = 0; } } if (sys_sta.lamp_fault != LAMP_FAULT_SHORT && !s_short_triggered) { if (current > s_peak_current) s_peak_current = current; rise = (s_peak_current > s_start_current) ? (s_peak_current - s_start_current) : 0; fall = (s_peak_current > current) ? (s_peak_current - current) : 0; if (current >= HIGH_CURRENT) { if (s_high_start_ms == 0) s_high_start_ms = now; } else { s_high_start_ms = 0; } uint8_t short_cond = 0; if (s_peak_current >= FAST_PEAK_THRESH && fall >= FAST_FALL_THRESH && current <= FAST_CURRENT_MAX) { short_cond = 1; LOG_D("[SHORT] Fast short: peak=%d, curr=%d, fall=%d", s_peak_current, current, fall); } else if (rise >= RISE_THRESH && fall >= FALL_THRESH_A) { short_cond = 1; LOG_D("[SHORT] Cond A: rise=%d, fall=%d", rise, fall); } else if (s_high_start_ms && (now - s_high_start_ms >= HIGH_DUR_MS) && fall >= FALL_THRESH_B) { short_cond = 1; LOG_D("[SHORT] Cond B: highDur=%d, fall=%d", now - s_high_start_ms, fall); } if (short_cond) { trigger_short(current); break; } } if (sys_sta.lamp_fault != LAMP_FAULT_NONE) { if (current >= NORMAL_MIN) { if (s_recover_start_ms == 0) { s_recover_start_ms = now; LOG_D("[RECOV] Start counting, current=%d", current); } if (now - s_recover_start_ms >= RECOVER_STABLE_MS) { clear_protection(); s_recover_start_ms = 0; } } else { s_recover_start_ms = 0; } } else { s_recover_start_ms = 0; } static uint32_t last_log = 0; if (now - last_log >= 10000) { last_log = now; LOG_D(" Cur=%d, Fault=%s, Peak=%d, Rise=%d, Fall=%d, HighDur=%d", current, (sys_sta.lamp_fault == LAMP_FAULT_OPEN) ? "OPEN" : (sys_sta.lamp_fault == LAMP_FAULT_SHORT) ? "SHORT" : "NONE", s_peak_current, rise, fall, s_high_start_ms ? (now - s_high_start_ms) : 0); } rt_thread_mdelay(DETECT_MS); } /* end while(lamp_on) */ LOG_I(" Lamp OFF, reset all"); reset_all_state(); } } static void lamp_protect_start(void) { if (s_thread) return; s_thread = rt_thread_create("lamp_prot", lamp_protect_entry, NULL, 1024, 15, 10); if (s_thread) { rt_thread_startup(s_thread); LOG_I(" Thread created"); } else { LOG_E(" Failed to create thread"); } } static int auto_init(void) { lamp_protect_start(); return 0; } INIT_APP_EXPORT(auto_init); /*********************↓ MSH命令(独立命名) ↓***********************/ static void cmd_lamp_status(int argc, char **argv) { (void)argc; (void)argv; uint32_t now = rt_tick_get_millisecond(); rt_kprintf("\n========== LAMP PROTECTION STATUS ==========\n"); rt_kprintf("Lamp switch: %s\n", rt_pin_read(LAMP_PIN) ? "ON" : "OFF"); rt_kprintf("Current: %d\n", sys_sta.lamp_current); rt_kprintf("Fault: %s\n", sys_sta.lamp_fault == LAMP_FAULT_OPEN ? "OPEN" : sys_sta.lamp_fault == LAMP_FAULT_SHORT ? "SHORT" : "NONE"); rt_kprintf("Short triggered this session: %s\n", s_short_triggered ? "YES" : "NO"); rt_kprintf("Peak current: %d\n", s_peak_current); if (s_high_start_ms) { rt_kprintf("High current duration: %d/%d ms\n", now - s_high_start_ms, HIGH_DUR_MS); } rt_kprintf("Recover stable: %s\n", s_recover_start_ms ? "COUNTING" : "IDLE"); if (s_recover_start_ms) { rt_kprintf(" elapsed: %d/%d ms\n", now - s_recover_start_ms, RECOVER_STABLE_MS); } rt_kprintf("============================================\n"); } MSH_CMD_EXPORT(cmd_lamp_status, Show lamp protection status); static void cmd_lamp_clear(int argc, char **argv) { if (argc < 2) { rt_kprintf("Usage: lamp_clear [open|short|all]\n"); return; } if (strcmp(argv[1], "open") == 0 || strcmp(argv[1], "all") == 0) { if (sys_sta.lamp_fault == LAMP_FAULT_OPEN) { sys_sta.lamp_fault = LAMP_FAULT_NONE; LOG_I("[CMD] Open protection cleared"); } } if (strcmp(argv[1], "short") == 0 || strcmp(argv[1], "all") == 0) { if (sys_sta.lamp_fault == LAMP_FAULT_SHORT) { sys_sta.lamp_fault = LAMP_FAULT_NONE; s_short_triggered = 0; LOG_I("[CMD] Short protection cleared"); } } s_recover_start_ms = 0; s_last_fault = LAMP_FAULT_NONE; rt_kprintf("Lamp protection cleared.\n"); cmd_lamp_status(0, NULL); } MSH_CMD_EXPORT(cmd_lamp_clear, Clear lamp protection : lamp_clear[open | short | all]); /*********************↑ MSH命令 ↑***********************/