lamp_protect.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /*
  2. * Lamp Protection Module - v3.2 (Optimized for fast short detection)
  3. *
  4. * 改进:
  5. * - 高电流持续时间阈值降低至1200ms
  6. * - 增加快速短路条件(峰值≥3500且下降≥2500且当前≤1500)
  7. * - 稳定期内保持起始电流不变,避免高电流覆盖
  8. */
  9. /*********************↓ include ↓************************/
  10. #define DBG_TAG "LAMP_PROT"
  11. #define DBG_LVL DBG_INFO
  12. #include <rtdbg.h>
  13. #include <rtthread.h>
  14. #include <rtdevice.h>
  15. #include <board.h>
  16. #include <string.h>
  17. #include "ecode.h"
  18. #include "ym310_protecl.h"
  19. /*********************↑ include ↑************************/
  20. /*********************↓ define ↓************************/
  21. #define DETECT_MS 500 /* 检测周期,与ADC一致 */
  22. #define STABLE_MS 500 /* 开启后稳定等待时间(1个周期) */
  23. #define OPEN_TRIGGER_MS 10000 /* 开路触发时间(10秒) */
  24. #define RECOVER_STABLE_MS 30000 /* 恢复所需稳定时间(30秒) */
  25. /* 短路特征阈值 */
  26. #define RISE_THRESH 1000 /* 上升≥1000(情景A) */
  27. #define FALL_THRESH_A 2000 /* 情景A下降阈值 */
  28. #define HIGH_CURRENT 3300 /* 高电流阈值(情景B) */
  29. #define HIGH_DUR_MS 1000 /* 高电流持续时间(1秒) */
  30. #define FALL_THRESH_B 2500 /* 情景B下降阈值(略降提高灵敏度) */
  31. /* 快速短路条件(独立于持续时间) */
  32. #define FAST_PEAK_THRESH 3500 /* 快速短路峰值阈值 */
  33. #define FAST_FALL_THRESH 2500 /* 快速短路下降阈值 */
  34. #define FAST_CURRENT_MAX 1500 /* 快速短路时当前电流最大值 */
  35. #define OPEN_MAX 100 /* 开路电流最大值 */
  36. #define NORMAL_MIN 1000 /* 正常电流最小值 */
  37. #define LAMP_FAULT_NONE 0
  38. #define LAMP_FAULT_OPEN 0x7A
  39. #define LAMP_FAULT_SHORT 0x9D
  40. #define LAMP_PIN GET_PIN(B, 5)
  41. #define LAMP_ON PIN_HIGH
  42. #define LAMP_OFF PIN_LOW
  43. /*********************↑ define ↑************************/
  44. /*********************↓ 外部变量/函数声明 ↓***********************/
  45. extern SYS_STATUS sys_sta;
  46. extern DEV_INFO dev_info;
  47. extern void save_dev_info(void);
  48. extern void report_now(void);
  49. extern void gpio_lamp_ctrl(uint8_t state);
  50. extern void gpio_hv_ctrl(uint8_t state);
  51. /*********************↑ 外部变量/函数声明 ↑***********************/
  52. /*********************↓ 静态变量 ↓***********************/
  53. static rt_thread_t s_thread = RT_NULL;
  54. /* 开路检测 */
  55. static uint32_t s_open_start_ms = 0;
  56. /* 短路检测 */
  57. static uint32_t s_start_current = 0; /* 稳定期开始时的起始电流(固定值) */
  58. static uint32_t s_peak_current = 0; /* 检测到的峰值(稳定期内也记录) */
  59. static uint32_t s_high_start_ms = 0; /* 高电流开始时间(稳定期内也记录) */
  60. static uint8_t s_short_triggered = 0; /* 本次开启周期是否已触发短路保护 */
  61. /* 恢复检测 */
  62. static uint32_t s_recover_start_ms = 0; /* 稳定正常开始时间 */
  63. static uint8_t s_last_fault = 0; /* 记录当前保护类型 */
  64. /* 灯管开启后的稳定延迟 */
  65. static uint32_t s_stable_until_ms = 0; /* 稳定期结束的时间点 */
  66. /*********************↑ 静态变量 ↑************************/
  67. /*********************↓ 内部辅助函数 ↓************************/
  68. static void reset_all_state(void)
  69. {
  70. s_open_start_ms = 0;
  71. s_start_current = 0;
  72. s_peak_current = 0;
  73. s_high_start_ms = 0;
  74. s_short_triggered = 0;
  75. s_recover_start_ms = 0;
  76. s_stable_until_ms = 0;
  77. }
  78. /* 触发短路保护(关灯、关机、上报) */
  79. static void trigger_short(uint32_t current)
  80. {
  81. if (s_short_triggered)
  82. return;
  83. s_short_triggered = 1;
  84. sys_sta.lamp_fault = LAMP_FAULT_SHORT;
  85. s_last_fault = LAMP_FAULT_SHORT;
  86. LOG_W("[SHORT] Triggered! peak=%d, curr=%d", s_peak_current, current);
  87. gpio_lamp_ctrl(0);
  88. gpio_hv_ctrl(0);
  89. dev_info.power_state = 0;
  90. save_dev_info();
  91. Recode_e_code(e_protect, current, "灯管短路保护触发");
  92. report_now();
  93. }
  94. /* 触发开路保护(只上报,不关灯) */
  95. static void trigger_open(uint32_t current)
  96. {
  97. if (sys_sta.lamp_fault == LAMP_FAULT_OPEN)
  98. return;
  99. sys_sta.lamp_fault = LAMP_FAULT_OPEN;
  100. s_last_fault = LAMP_FAULT_OPEN;
  101. LOG_W("[OPEN] Triggered! current=%d", current);
  102. Recode_e_code(e_protect, current, "灯管开路故障");
  103. report_now();
  104. }
  105. /* 清除保护(恢复) */
  106. static void clear_protection(void)
  107. {
  108. if (sys_sta.lamp_fault == LAMP_FAULT_OPEN)
  109. {
  110. sys_sta.lamp_fault = LAMP_FAULT_NONE;
  111. LOG_I("[OPEN] Cleared");
  112. Recode_e_code(e_protect, 0, "灯管开路故障恢复");
  113. report_now();
  114. }
  115. else if (sys_sta.lamp_fault == LAMP_FAULT_SHORT)
  116. {
  117. sys_sta.lamp_fault = LAMP_FAULT_NONE;
  118. LOG_I("[SHORT] Cleared");
  119. Recode_e_code(e_protect, 0, "灯管短路保护解除");
  120. report_now();
  121. }
  122. s_recover_start_ms = 0;
  123. s_last_fault = LAMP_FAULT_NONE;
  124. }
  125. /*********************↑ 内部辅助函数 ↑***********************/
  126. /*********************↓ 主线程(极简流程) ↓***********************/
  127. static void lamp_protect_entry(void *param)
  128. {
  129. uint32_t now, current;
  130. uint8_t lamp_on;
  131. uint32_t rise, fall;
  132. rt_thread_mdelay(6*1000);
  133. char off_lamp_proc = 0;
  134. ef_get_env_blob("off_lamp_proc", &off_lamp_proc, sizeof(off_lamp_proc), NULL);
  135. if(off_lamp_proc == VALID)
  136. {
  137. LOG_W("JUMP lamp_protect_entry");
  138. }
  139. while (1)
  140. {
  141. while (rt_pin_read(LAMP_PIN) != LAMP_ON)
  142. {
  143. rt_thread_mdelay(DETECT_MS);
  144. }
  145. reset_all_state();
  146. s_stable_until_ms = rt_tick_get_millisecond() + STABLE_MS;
  147. s_start_current = sys_sta.lamp_current;
  148. s_peak_current = s_start_current;
  149. LOG_I(" Lamp ON, stable until %lu, start_current=%d",
  150. s_stable_until_ms, s_start_current);
  151. while (rt_pin_read(LAMP_PIN) == LAMP_ON)
  152. {
  153. now = rt_tick_get_millisecond();
  154. current = sys_sta.lamp_current;
  155. if (now < s_stable_until_ms)
  156. {
  157. if (current > s_peak_current)
  158. s_peak_current = current;
  159. if (current >= HIGH_CURRENT)
  160. {
  161. if (s_high_start_ms == 0)
  162. s_high_start_ms = now;
  163. }
  164. else
  165. {
  166. s_high_start_ms = 0;
  167. }
  168. rt_thread_mdelay(DETECT_MS);
  169. continue;
  170. }
  171. if (sys_sta.lamp_fault != LAMP_FAULT_OPEN)
  172. {
  173. if (current <= OPEN_MAX)
  174. {
  175. if (s_open_start_ms == 0)
  176. s_open_start_ms = now;
  177. if (now - s_open_start_ms >= OPEN_TRIGGER_MS)
  178. {
  179. trigger_open(current);
  180. s_open_start_ms = 0;
  181. }
  182. }
  183. else
  184. {
  185. s_open_start_ms = 0;
  186. }
  187. }
  188. if (sys_sta.lamp_fault != LAMP_FAULT_SHORT && !s_short_triggered)
  189. {
  190. if (current > s_peak_current)
  191. s_peak_current = current;
  192. rise = (s_peak_current > s_start_current) ? (s_peak_current - s_start_current) : 0;
  193. fall = (s_peak_current > current) ? (s_peak_current - current) : 0;
  194. if (current >= HIGH_CURRENT)
  195. {
  196. if (s_high_start_ms == 0)
  197. s_high_start_ms = now;
  198. }
  199. else
  200. {
  201. s_high_start_ms = 0;
  202. }
  203. uint8_t short_cond = 0;
  204. if (s_peak_current >= FAST_PEAK_THRESH && fall >= FAST_FALL_THRESH && current <= FAST_CURRENT_MAX)
  205. {
  206. short_cond = 1;
  207. LOG_D("[SHORT] Fast short: peak=%d, curr=%d, fall=%d", s_peak_current, current, fall);
  208. }
  209. else if (rise >= RISE_THRESH && fall >= FALL_THRESH_A)
  210. {
  211. short_cond = 1;
  212. LOG_D("[SHORT] Cond A: rise=%d, fall=%d", rise, fall);
  213. }
  214. else if (s_high_start_ms && (now - s_high_start_ms >= HIGH_DUR_MS) && fall >= FALL_THRESH_B)
  215. {
  216. short_cond = 1;
  217. LOG_D("[SHORT] Cond B: highDur=%d, fall=%d", now - s_high_start_ms, fall);
  218. }
  219. if (short_cond)
  220. {
  221. trigger_short(current);
  222. break;
  223. }
  224. }
  225. if (sys_sta.lamp_fault != LAMP_FAULT_NONE)
  226. {
  227. if (current >= NORMAL_MIN)
  228. {
  229. if (s_recover_start_ms == 0)
  230. {
  231. s_recover_start_ms = now;
  232. LOG_D("[RECOV] Start counting, current=%d", current);
  233. }
  234. if (now - s_recover_start_ms >= RECOVER_STABLE_MS)
  235. {
  236. clear_protection();
  237. s_recover_start_ms = 0;
  238. }
  239. }
  240. else
  241. {
  242. s_recover_start_ms = 0;
  243. }
  244. }
  245. else
  246. {
  247. s_recover_start_ms = 0;
  248. }
  249. static uint32_t last_log = 0;
  250. if (now - last_log >= 10000)
  251. {
  252. last_log = now;
  253. LOG_D(" Cur=%d, Fault=%s, Peak=%d, Rise=%d, Fall=%d, HighDur=%d",
  254. current,
  255. (sys_sta.lamp_fault == LAMP_FAULT_OPEN) ? "OPEN" : (sys_sta.lamp_fault == LAMP_FAULT_SHORT) ? "SHORT"
  256. : "NONE",
  257. s_peak_current, rise, fall,
  258. s_high_start_ms ? (now - s_high_start_ms) : 0);
  259. }
  260. rt_thread_mdelay(DETECT_MS);
  261. } /* end while(lamp_on) */
  262. LOG_I(" Lamp OFF, reset all");
  263. reset_all_state();
  264. }
  265. }
  266. static void lamp_protect_start(void)
  267. {
  268. if (s_thread)
  269. return;
  270. s_thread = rt_thread_create("lamp_prot", lamp_protect_entry, NULL,
  271. 1024, 15, 10);
  272. if (s_thread)
  273. {
  274. rt_thread_startup(s_thread);
  275. LOG_I(" Thread created");
  276. }
  277. else
  278. {
  279. LOG_E(" Failed to create thread");
  280. }
  281. }
  282. static int auto_init(void)
  283. {
  284. lamp_protect_start();
  285. return 0;
  286. }
  287. INIT_APP_EXPORT(auto_init);
  288. /*********************↓ MSH命令(独立命名) ↓***********************/
  289. static void cmd_lamp_status(int argc, char **argv)
  290. {
  291. (void)argc;
  292. (void)argv;
  293. uint32_t now = rt_tick_get_millisecond();
  294. rt_kprintf("\n========== LAMP PROTECTION STATUS ==========\n");
  295. rt_kprintf("Lamp switch: %s\n", rt_pin_read(LAMP_PIN) ? "ON" : "OFF");
  296. rt_kprintf("Current: %d\n", sys_sta.lamp_current);
  297. rt_kprintf("Fault: %s\n",
  298. sys_sta.lamp_fault == LAMP_FAULT_OPEN ? "OPEN" : sys_sta.lamp_fault == LAMP_FAULT_SHORT ? "SHORT"
  299. : "NONE");
  300. rt_kprintf("Short triggered this session: %s\n", s_short_triggered ? "YES" : "NO");
  301. rt_kprintf("Peak current: %d\n", s_peak_current);
  302. if (s_high_start_ms)
  303. {
  304. rt_kprintf("High current duration: %d/%d ms\n", now - s_high_start_ms, HIGH_DUR_MS);
  305. }
  306. rt_kprintf("Recover stable: %s\n", s_recover_start_ms ? "COUNTING" : "IDLE");
  307. if (s_recover_start_ms)
  308. {
  309. rt_kprintf(" elapsed: %d/%d ms\n", now - s_recover_start_ms, RECOVER_STABLE_MS);
  310. }
  311. rt_kprintf("============================================\n");
  312. }
  313. MSH_CMD_EXPORT(cmd_lamp_status, Show lamp protection status);
  314. static void cmd_lamp_clear(int argc, char **argv)
  315. {
  316. if (argc < 2)
  317. {
  318. rt_kprintf("Usage: lamp_clear [open|short|all]\n");
  319. return;
  320. }
  321. if (strcmp(argv[1], "open") == 0 || strcmp(argv[1], "all") == 0)
  322. {
  323. if (sys_sta.lamp_fault == LAMP_FAULT_OPEN)
  324. {
  325. sys_sta.lamp_fault = LAMP_FAULT_NONE;
  326. LOG_I("[CMD] Open protection cleared");
  327. }
  328. }
  329. if (strcmp(argv[1], "short") == 0 || strcmp(argv[1], "all") == 0)
  330. {
  331. if (sys_sta.lamp_fault == LAMP_FAULT_SHORT)
  332. {
  333. sys_sta.lamp_fault = LAMP_FAULT_NONE;
  334. s_short_triggered = 0;
  335. LOG_I("[CMD] Short protection cleared");
  336. }
  337. }
  338. s_recover_start_ms = 0;
  339. s_last_fault = LAMP_FAULT_NONE;
  340. rt_kprintf("Lamp protection cleared.\n");
  341. cmd_lamp_status(0, NULL);
  342. }
  343. MSH_CMD_EXPORT(cmd_lamp_clear, Clear lamp protection : lamp_clear[open | short | all]);
  344. /*********************↑ MSH命令 ↑***********************/