From 52c59395a8db0373480bcbbd646eb91bb5a39e39 Mon Sep 17 00:00:00 2001 From: wrh Date: Mon, 10 Aug 2026 16:28:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=AF=E6=AD=A3=E5=B8=B8=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E7=89=88=E6=9C=AC=EF=BC=8C=E4=BB=A3=E4=BB=B7=E6=98=AF5V?= =?UTF-8?q?=E6=AF=94=E8=BE=83=E6=85=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit chore: 完成充电控制软件多项功能迭代与优化 1. 修改chrg.uvprojx,开启调试前更新Flash 2. 新增协议回码等待状态,注释掉协议优先于CC的测试流程 3. 启用南向寄存器写命令调试日志 4. 重构Sink工作状态机,拆分关机流程为多阶段等待 5. 新增主继电器0V持续掉电保护功能 6. 优化南向单次量测队列管理,修复多通道低电流确认异常 7. 调整电压稳定确认逻辑,为5V目标增加更长确认窗口 8. 移除软恢复相关状态与逻辑,简化状态流转 --- apps/chrg/applications/thread/chrg_comm.c | 36 +- apps/chrg/applications/thread/chrg_north.c | 49 ++- apps/chrg/applications/thread/chrg_north.h | 2 +- apps/chrg/applications/thread/chrg_roll_nor.c | 52 ++- apps/chrg/applications/thread/chrg_roll_nor.h | 4 + apps/chrg/applications/thread/chrg_roll_sou.c | 22 +- apps/chrg/applications/utils/chrg_sink.c | 316 +++++++++++------- apps/chrg/applications/utils/chrg_sink.h | 13 +- apps/chrg/chrg.uvprojx | 2 +- apps/chrg/codex_low_voltage_relay_verify.log | 9 + apps/chrg/codex_protocol_ack_verify.log | 18 + apps/chrg/codex_soft_resume_remove.log | 21 ++ .../codex_stop_current_confirm_verify.log | 21 ++ apps/chrg/codex_stop_direct_verify.log | 21 ++ apps/chrg/codex_stop_repeat_guard_verify.log | 9 + apps/chrg/codex_verify.log | 6 +- 16 files changed, 403 insertions(+), 198 deletions(-) create mode 100644 apps/chrg/codex_low_voltage_relay_verify.log create mode 100644 apps/chrg/codex_protocol_ack_verify.log create mode 100644 apps/chrg/codex_soft_resume_remove.log create mode 100644 apps/chrg/codex_stop_current_confirm_verify.log create mode 100644 apps/chrg/codex_stop_direct_verify.log create mode 100644 apps/chrg/codex_stop_repeat_guard_verify.log diff --git a/apps/chrg/applications/thread/chrg_comm.c b/apps/chrg/applications/thread/chrg_comm.c index c1e7eaa..c9fff7d 100644 --- a/apps/chrg/applications/thread/chrg_comm.c +++ b/apps/chrg/applications/thread/chrg_comm.c @@ -2348,6 +2348,7 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch, rt_uint8_t old_cv_mode = pReal->CV_mode; rt_uint16_t old_loadv = pReal->sink.loadv; rt_uint16_t old_loadc = pReal->sink.loadc; + rt_uint8_t old_on_work = pReal->sink.On_work; rt_uint8_t old_work_mode = pReal->sink.work_mode; rt_uint16_t sink_work = pShadow->sink.Now_State; chrg_param_diff_t diff_info; @@ -2383,11 +2384,13 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch, } pReal->sink.test.test_mode_old = curr_test; } else { + /* Protocol-before-CC test flow is disabled in this version. */ pReal->sub = IDX_SET_SINK_CC_BEFORE_PD; pReal->sink.work_mode = SINK_WORK_INIT; } } else if (pReal->sink.On_work == 0) { pReal->sink.On_work = 1; + /* Protocol-before-CC test flow is disabled in this version. */ pReal->sub = IDX_SET_SINK_CC_BEFORE_PD; pReal->sink.work_mode = SINK_WORK_INIT; } else if (full_handshake_change) { @@ -2398,6 +2401,7 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch, * 仅协议变化时不重复设置未变化的CC。 */ if (diff_info.cc_changed && protocol_data_changed) { + /* Protocol-before-CC test flow is disabled in this version. */ pReal->sub = IDX_SET_SINK_CC_BEFORE_PD; } else if (diff_info.cc_changed) { pReal->sub = IDX_SET_SINK_CCLINE; @@ -2414,8 +2418,6 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch, pReal->sub = IDX_SET_SINK_PD_ONLY; if (old_work_mode == SINK_WORK_LOAD_STANDBY) { pReal->sink.work_mode = SINK_WORK_WAIT; - } else if (old_work_mode == SINK_WORK_LOAD_SOFT_STANDBY) { - pReal->sink.work_mode = SINK_WORK_SOFT_RESUME_WAIT; } else { /* 运行状态修改协议参数时保持继电器,只停止电子负载。 */ pReal->sink.work_mode = SINK_WORK_PROTOCOL_UNLOAD; @@ -2432,7 +2434,20 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch, } } else { pReal->sink.On_work = 0; - pReal->sink.work_mode = SINK_WORK_STOP; + /* 组合控制或上位机重发可能在关机尚未完成时再次提交OFF。 + * 此时必须保留当前停止阶段,不能重新进入STOP并清零低电流确认次数, + * 否则实际电流即使一直为0,也永远累计不到连续5帧。 */ + if ((old_work_mode == SINK_WORK_STOP_WAIT) || + (old_work_mode == SINK_WORK_STOP_RELAY) || + (old_work_mode == SINK_WORK_STOP_RELAY_WAIT)) { + pReal->sink.work_mode = old_work_mode; + } else if ((old_on_work == 0U) && + (old_work_mode == SINK_WORK_WAIT)) { + /* 已完成停止时重复OFF保持WAIT,不重复操作继电器。 */ + pReal->sink.work_mode = SINK_WORK_WAIT; + } else { + pReal->sink.work_mode = SINK_WORK_STOP; + } } return (chrg_sink_work((eIDX_SOU_CH)ch, pReal) == 0) ? @@ -2463,8 +2478,7 @@ static rt_bool_t chrg_comm_handle_sink_load_current( } should_start = chrg_sink_load_should_start(pReal); - if ((old_work_mode == SINK_WORK_RUNING) || - (old_work_mode == SINK_WORK_SOFT_RUNNING)) { + if (old_work_mode == SINK_WORK_RUNING) { if (!should_start) { pReal->sink.work_mode = SINK_WORK_LOAD_STOP; return RT_TRUE; @@ -2484,18 +2498,6 @@ static rt_bool_t chrg_comm_handle_sink_load_current( return RT_TRUE; } - if (old_work_mode == SINK_WORK_LOAD_SOFT_STANDBY) { - if (should_start) { - /* - * 软待机恢复同样必须先读取北向实际电压。 - * 电压稳定后由解析流程进入SOFT_RESUME,再下发目标电流和WORK_START。 - */ - pReal->sub = IDX_GET_SINK_VC; - pReal->sink.work_mode = SINK_WORK_SOFT_RESUME_WAIT; - } - return RT_TRUE; - } - /* 协议握手期间禁止把低于门限的小电流提前写入南向功率板。 */ return should_start ? RT_FALSE : RT_TRUE; } diff --git a/apps/chrg/applications/thread/chrg_north.c b/apps/chrg/applications/thread/chrg_north.c index 3ecbaeb..fffcacf 100644 --- a/apps/chrg/applications/thread/chrg_north.c +++ b/apps/chrg/applications/thread/chrg_north.c @@ -29,8 +29,10 @@ #define SOURCE_QC_MIN_VOLT_MV 5000U // QC2.0/QC3.0允许使用的最低目标电压 #define SOURCE_QC_SWITCH_ERROR 0x04U // Source协议或CC切换失败错误位 #define SINK_CURRENT_START_GRACE_MS 200U // Sink启动后暂不判断无电流的保护时间 -#define SINK_VOLT_STABLE_ERROR_MV 2000U // Sink实际电压与协议目标电压的最大允许误差 -#define SINK_VOLT_STABLE_CONFIRM_COUNT 3U // Sink连续有效稳定电压帧数达到此值后进入RUNING +#define SINK_VOLT_STABLE_ERROR_MV 2000U // Sink实际电压与协议目标电压的最大允许误差 +#define SINK_VOLT_5V_TARGET_MV 5000U // VSafe5V目标电压,需延长稳定确认时间 +#define SINK_VOLT_CONFIRM_NORMAL_COUNT 5U // 非5V目标连续有效电压确认帧数 +#define SINK_VOLT_CONFIRM_5V_COUNT 15U // 5V目标连续有效电压确认帧数,避免把握手阶段VSafe5V误判为协议稳定 /***************************************************************** 函数名称: chrg_source_apply_protocol_voltage_rule @@ -82,6 +84,22 @@ static rt_bool_t chrg_sink_voltage_is_stable(rt_uint16_t actual_volt_mv, RT_TRUE : RT_FALSE; } +/***************************************************************** +函数名称: chrg_sink_voltage_confirm_count +函数描述: 根据Sink协议目标电压选择进入RUNING前所需的连续稳定帧数 +输入参数: target_volt_mv:当前协议申请的目标电压,单位mV +输出参数: - +返回说明: 5V目标返回延长确认帧数,其它目标返回普通确认帧数 +其它说明: 快充协议切换时总线会先经过VSafe5V;当目标本身也是5V时, + 单凭电压值无法区分过渡阶段和协议稳定阶段,因此增加确认时间, + 防止电子负载提前启动后导致协议板复位 +*****************************************************************/ +static rt_uint8_t chrg_sink_voltage_confirm_count(rt_uint16_t target_volt_mv) +{ + return (target_volt_mv == SINK_VOLT_5V_TARGET_MV) ? + SINK_VOLT_CONFIRM_5V_COUNT : SINK_VOLT_CONFIRM_NORMAL_COUNT; +} + /***************************************************************** 函数名称: chrg_source_voltage_control 函数描述: 根据目标电压与实际电压统一控制Source电压下发和重试 @@ -225,6 +243,7 @@ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, struct chrg_switch_t *pSW, struct chrg_north_t *pNOR) { rt_uint16_t volt_mv = ((frame_data[4] << 8) | frame_data[5]) * 10; + rt_uint8_t stable_confirm_count; static rt_uint8_t volt_low[TOTAL_SOU_CHS] = {0}; static rt_uint8_t no_curr[TOTAL_SOU_CHS] = {0}; static rt_uint8_t volt_set_ok[TOTAL_SOU_CHS] = {0}; @@ -234,6 +253,8 @@ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { return; } + stable_confirm_count = chrg_sink_voltage_confirm_count( + pSW->sink.pro_loadv); pSW->VZ = ((frame_data[14] << 8) | frame_data[15]); pSW->VF = ((frame_data[16] << 8) | frame_data[17]); @@ -246,10 +267,10 @@ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, if (volt_mv <= WORK_MIN_VOLT) { // 电压过低,禁止进入工作状态机 volt_stable_count[idx] = 0; if (volt_set_ok[idx] == 1) { - if (++volt_low[idx] >= 20) { + if (++volt_low[idx] >= 50) { volt_set_ok[idx] = 0; no_curr[idx] = 0; - pSW->sink.work_mode = SINK_WORK_LOW; + //pSW->sink.work_mode = SINK_WORK_LOW; } } } @@ -273,25 +294,19 @@ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, else if (chrg_sink_voltage_is_stable(volt_mv, pSW->sink.pro_loadv)) { if ((pSW->sink.work_mode != SINK_WORK_RUNING) && - (pSW->sink.work_mode != SINK_WORK_SOFT_RUNNING) && - (pSW->sink.work_mode != SINK_WORK_LOAD_STANDBY) && - (pSW->sink.work_mode != SINK_WORK_LOAD_SOFT_STANDBY)) { - if (volt_stable_count[idx] < SINK_VOLT_STABLE_CONFIRM_COUNT) { + (pSW->sink.work_mode != SINK_WORK_LOAD_STANDBY)) { + if (volt_stable_count[idx] < stable_confirm_count) { volt_stable_count[idx]++; } - if (volt_stable_count[idx] >= SINK_VOLT_STABLE_CONFIRM_COUNT) { - /* 回码已经过CRC、ID、命令和配置版本校验;首帧达到目标 - * 电压附近后立即进入RUNING,不再增加额外稳定等待。 */ + if (volt_stable_count[idx] >= stable_confirm_count) { + /* 回码已经过CRC、ID、命令和配置版本校验,并连续达到当前 + * 目标对应的确认帧数;5V采用更长窗口过滤VSafe5V过渡阶段。 */ volt_stable_count[idx] = 0; - pSW->sink.work_mode = - ((pSW->sink.work_mode == SINK_WORK_SOFT_RESUME_WAIT) || - (pSW->sink.work_mode == SINK_WORK_LOAD_RESUME)) ? - SINK_WORK_SOFT_RESUME : SINK_WORK_RUNING; + pSW->sink.work_mode = SINK_WORK_RUNING; running_start_tick[idx] = rt_tick_get(); no_curr[idx] = 0; } - } else if ((pSW->sink.work_mode == SINK_WORK_LOAD_STANDBY) || - (pSW->sink.work_mode == SINK_WORK_LOAD_SOFT_STANDBY)) { + } else if (pSW->sink.work_mode == SINK_WORK_LOAD_STANDBY) { /* 协议保持在线但电子负载主动停止,不执行无电流重试。 */ volt_stable_count[idx] = 0; no_curr[idx] = 0; diff --git a/apps/chrg/applications/thread/chrg_north.h b/apps/chrg/applications/thread/chrg_north.h index fb6fc7e..b3c9a78 100644 --- a/apps/chrg/applications/thread/chrg_north.h +++ b/apps/chrg/applications/thread/chrg_north.h @@ -26,7 +26,7 @@ #define NORTH_SOURCE_DEBUG 0x00 // Source协议解析及组帧 #define NORTH_SINK_DEBUG 0x00 // Sink协议解析及组帧 #define SOUTH_FRAME_DEBUG 0x00 // 南向UART原始收发帧 -#define SOUTH_COMMAND_DEBUG 0x00 // 南向寄存器写命令 +#define SOUTH_COMMAND_DEBUG 0x01 // 南向寄存器写命令 #define COMM_FRAME_DEBUG 0x00 // COM UART原始收发帧 #define COMM_DEBUG 0x00 // COM寄存器读写过程 #define COMM_TRIM_DEBUG 0x00 // COM校准参数解析 diff --git a/apps/chrg/applications/thread/chrg_roll_nor.c b/apps/chrg/applications/thread/chrg_roll_nor.c index a70d980..020c691 100644 --- a/apps/chrg/applications/thread/chrg_roll_nor.c +++ b/apps/chrg/applications/thread/chrg_roll_nor.c @@ -82,7 +82,6 @@ static rt_bool_t chrg_roll_nor_sink_query_is_slow( } return (pSW->sink.work_mode == SINK_WORK_WAIT) || (pSW->sink.work_mode == SINK_WORK_INIT_AUX_WAIT) || - (pSW->sink.work_mode == SINK_WORK_SOFT_RESUME_WAIT) || (pSW->sink.work_mode == SINK_WORK_LOW_MONITOR); } @@ -283,6 +282,13 @@ static rt_bool_t chrg_roll_nor_sink_wait_process(rt_uint8_t ch, } bit = SOURCE_CHANNEL_BIT(ch); + /* 关机必须先完成南向低电流确认和继电器批次,期间禁止北向发送。 */ + if ((pSW->sink.work_mode == SINK_WORK_STOP_WAIT) || + (pSW->sink.work_mode == SINK_WORK_STOP_RELAY) || + (pSW->sink.work_mode == SINK_WORK_STOP_RELAY_WAIT)) { + return RT_TRUE; + } + if ((pSW->id != ID_SINK) || !pSW->sink.On_work) { g_sink_cc_wait_mask &= (rt_uint8_t)~bit; g_sink_cc_wait_start[ch] = 0U; @@ -297,18 +303,16 @@ static rt_bool_t chrg_roll_nor_sink_wait_process(rt_uint8_t ch, return RT_TRUE; } - /* - * 完整握手批次最后发送FU_REL_ON。批次完成并建立量测基线后, - * 允许北向协议/CC与南向低电流确认并行;当sub进入GET_SINK_VC - * 而状态仍为HANDSHAKE_WAIT时,说明低电流确认尚未完成,禁止发送0x20。 - */ + /* 协议或CC切换必须先完成低电流确认;该过程保持南向继电器状态不变。 */ if (pSW->sink.work_mode == SINK_WORK_HANDSHAKE_WAIT) { - if (!chrg_sink_handshake_north_ready((eIDX_SOU_CH)ch)) { - return RT_TRUE; - } - if (pSW->sub == IDX_GET_SINK_VC) { - return RT_TRUE; - } + return RT_TRUE; + } + + /* D0回码确认后先经过一个非发送状态,禁止把协议回码当成量测回码。 */ + if (pSW->sub == IDX_WAIT_SINK_PD_ACK) { + pSW->sub = IDX_GET_SINK_VC; + chrg_roll_nor_sink_query_wait_start(ch); + return RT_TRUE; } if ((pSW->sub != IDX_WAIT_SINK_CC) && @@ -605,6 +609,9 @@ static rt_uint8_t chrg_roll_nor_expected_cmd(const struct chrg_switch_t *pSW) return SINK_CMD_GET_PD; case IDX_SET_SINK_PD: case IDX_SET_SINK_PD_ONLY: +#if 0 + case IDX_SET_SINK_PD_BEFORE_CC: +#endif return pSW->sink.protocol; case IDX_SET_SINK_CCLINE: case IDX_SET_SINK_CC_BEFORE_PD: @@ -822,12 +829,18 @@ static int chrg_roll_nor_set(rt_uint8_t ch, struct chrg_switch_t *pSW, case IDX_SET_SINK_CCLVL: //CC电平 return sink_set_cc_lvl(pSW->sink.cc_lvl); case IDX_SET_SINK_PD: - /* CC已经在协议前完成设置,协议回码后直接查询电压。 */ - *next_sub = IDX_GET_SINK_VC; + /* 只有协议回码确认后,下一轮才允许进入电压查询。 */ + *next_sub = IDX_WAIT_SINK_PD_ACK; return chrg_roll_nor_sink_pro_set(pSW); case IDX_SET_SINK_PD_ONLY: - *next_sub = IDX_GET_SINK_VC; + *next_sub = IDX_WAIT_SINK_PD_ACK; return chrg_roll_nor_sink_pro_set(pSW); +#if 0 + case IDX_SET_SINK_PD_BEFORE_CC: + /* 协议回码确认后再设置CC,不提前查询电压。 */ + *next_sub = IDX_SET_SINK_CCLINE; + return chrg_roll_nor_sink_pro_set(pSW); +#endif default: return -1; } @@ -1014,9 +1027,12 @@ void chrg_roll_nor_thread_entry (void *data) (pSW->sink.work_mode == SINK_WORK_INIT_AUX_WAIT) || (pSW->sink.work_mode == SINK_WORK_UNLOAD_WAIT) || (pSW->sink.work_mode == SINK_WORK_LOW) || - (pSW->sink.work_mode == SINK_WORK_LOW_AUX_WAIT) || - (pSW->sink.work_mode == SINK_WORK_HANDSHAKE_PREPARE) || - (pSW->sink.work_mode == SINK_WORK_HANDSHAKE_WAIT))) { + (pSW->sink.work_mode == SINK_WORK_LOW_AUX_WAIT) || + (pSW->sink.work_mode == SINK_WORK_HANDSHAKE_PREPARE) || + (pSW->sink.work_mode == SINK_WORK_HANDSHAKE_WAIT) || + (pSW->sink.work_mode == SINK_WORK_STOP_WAIT) || + (pSW->sink.work_mode == SINK_WORK_STOP_RELAY) || + (pSW->sink.work_mode == SINK_WORK_STOP_RELAY_WAIT))) { state_work_ret = chrg_sink_work((eIDX_SOU_CH)idx, pSW); } /* diff --git a/apps/chrg/applications/thread/chrg_roll_nor.h b/apps/chrg/applications/thread/chrg_roll_nor.h index 9bdfa66..e11def5 100644 --- a/apps/chrg/applications/thread/chrg_roll_nor.h +++ b/apps/chrg/applications/thread/chrg_roll_nor.h @@ -52,6 +52,10 @@ enum { IDX_WAIT_SINK_CC, // CC设置应答后的非阻塞稳定等待 IDX_SET_SINK_CC_BEFORE_PD, // 先设置CC,稳定后再设置协议 IDX_WAIT_SINK_CC_BEFORE_PD, // 等待CC稳定后进入协议设置 + IDX_WAIT_SINK_PD_ACK, // 协议回码确认后的非发送过渡状态 +#if 0 + IDX_SET_SINK_PD_BEFORE_CC, // 先设置协议,协议回码后再设置CC +#endif }; struct chrg_rollnor_t { diff --git a/apps/chrg/applications/thread/chrg_roll_sou.c b/apps/chrg/applications/thread/chrg_roll_sou.c index 5b4a706..2b0d540 100644 --- a/apps/chrg/applications/thread/chrg_roll_sou.c +++ b/apps/chrg/applications/thread/chrg_roll_sou.c @@ -29,7 +29,11 @@ #define SOU_CHANNEL_BIT(ch) ((rt_uint8_t)(1U << (ch))) chrg_rollsou_com_t g_sou_com_batch = {0}; -static rt_uint8_t g_sou_measure_once_mask = 0U; +/* 一次性P1量测分别记录待发送请求和正在等待回码的请求。 + * 当前帧尚未结束时再次申请的下一帧保存在pending中,不能被当前帧 + * 的完成处理清除,否则多通道运行时低电流确认会间歇性停止推进。 */ +static rt_uint8_t g_sou_measure_once_pending_mask = 0U; +static rt_uint8_t g_sou_measure_once_active_mask = 0U; struct chrg_rollsou_t chrgrollsou = { .run = RUN_AUTO, @@ -223,7 +227,7 @@ int chrg_sou_measure_once_submit(eIDX_SOU_CH ch) rt_tick_from_millisecond(SOU_MUTEX_TIMEOUT_MS)) != RT_EOK)) { return -1; } - g_sou_measure_once_mask |= SOU_CHANNEL_BIT(ch); + g_sou_measure_once_pending_mask |= SOU_CHANNEL_BIT(ch); rt_mutex_release(pTHR->mutex); return 0; } @@ -247,7 +251,13 @@ static int sou_measure_once_next(rt_uint8_t *ch) return -1; } for (idx = 0; idx < TOTAL_SOU_CHS; idx++) { - if ((g_sou_measure_once_mask & SOU_CHANNEL_BIT(idx)) != 0U) { + rt_uint8_t bit = SOU_CHANNEL_BIT(idx); + + if ((g_sou_measure_once_pending_mask & bit) != 0U) { + /* 发送前从pending转移到active。查询等待期间的新申请会重新 + * 置pending位,并在当前查询结束后继续执行。 */ + g_sou_measure_once_pending_mask &= (rt_uint8_t)~bit; + g_sou_measure_once_active_mask |= bit; *ch = idx; rt_mutex_release(pTHR->mutex); return 1; @@ -274,7 +284,8 @@ static void sou_measure_once_finish(rt_uint8_t ch) rt_tick_from_millisecond(SOU_MUTEX_TIMEOUT_MS)) != RT_EOK)) { return; } - g_sou_measure_once_mask &= (rt_uint8_t)~SOU_CHANNEL_BIT(ch); + /* 只结束当前正在等待的查询;等待期间登记的下一帧pending请求必须保留。 */ + g_sou_measure_once_active_mask &= (rt_uint8_t)~SOU_CHANNEL_BIT(ch); rt_mutex_release(pTHR->mutex); } @@ -607,7 +618,8 @@ int chrg_sou_com_batch_cancel(eIDX_SOU_CH ch) pBatch->reg_cnt = 0; pBatch->next_send_tick = 0U; /* 已取消事务对应的优先P1量测同样失效,后续状态会重新申请新量测。 */ - g_sou_measure_once_mask &= (rt_uint8_t)~SOU_CHANNEL_BIT(ch); + g_sou_measure_once_pending_mask &= (rt_uint8_t)~SOU_CHANNEL_BIT(ch); + g_sou_measure_once_active_mask &= (rt_uint8_t)~SOU_CHANNEL_BIT(ch); rt_mutex_release(pTHR->mutex); return 0; } diff --git a/apps/chrg/applications/utils/chrg_sink.c b/apps/chrg/applications/utils/chrg_sink.c index fa6d1f2..7641b1f 100644 --- a/apps/chrg/applications/utils/chrg_sink.c +++ b/apps/chrg/applications/utils/chrg_sink.c @@ -22,16 +22,29 @@ #define SINK_UNLOAD_QUERY_INTERVAL_MS 20U // 卸载期间两次优先量测请求的最小间隔 #define SINK_UNLOAD_CURRENT_MAX_MA 200U // 判定负载已安全卸载的最大实际电流 -#define SINK_UNLOAD_CONFIRM_COUNT 2U // 连续满足低电流条件的量测帧数 -#define SINK_CLOSE_CURRENT_MA 1000U // 安全关闭阶段写入功率板的电流设定值 +#define SINK_UNLOAD_CONFIRM_COUNT 5U // 连续满足低电流条件的量测帧数 + +/* 主继电器闭合跟踪:1=已提交ALL_REL_ON(主继电器应已闭合) 0=未闭合/已断开。 + * 用于0V硬保护区分"首次开载/握手恢复"(主继电器未闭合,Now_voltage=0属正常) + * 与"运行或待机中主继电器已闭合但输入电压为0"(协议板断电窗口,禁止开载)。 */ +static rt_uint8_t g_sink_rel_main_closed[TOTAL_SOU_CHS] = {0}; + +/* 主继电器电压到位确认:1=提交闭合后实测电压已到达工作下限,继电器确认闭合。 + * 持续0V监控只对已到位通道生效,避免继电器动作期间(电压尚未建立)误触发掉电保护。 */ +static rt_uint8_t g_sink_rel_main_ready[TOTAL_SOU_CHS] = {0}; /* 卸载确认只接受停止批次成功后产生的新P1量测。 */ static rt_uint32_t g_sink_unload_sample_seq[TOTAL_SOU_CHS] = {0}; static rt_bool_t g_sink_unload_batch_confirmed[TOTAL_SOU_CHS] = {RT_FALSE}; -static rt_bool_t g_sink_unload_current_confirmed[TOTAL_SOU_CHS] = {RT_FALSE}; static rt_tick_t g_sink_unload_query_tick[TOTAL_SOU_CHS] = {0}; static rt_uint8_t g_sink_unload_confirm_count[TOTAL_SOU_CHS] = {0}; +enum { + SINK_UNLOAD_NEXT_RUNNING = 0, + SINK_UNLOAD_NEXT_HANDSHAKE, + SINK_UNLOAD_NEXT_STOP_RELAY +}; + /***************************************************************** 函数名称: chrg_sink_load_should_start 函数描述: 判断普通负载的设定值是否允许启动南向电子负载 @@ -68,7 +81,6 @@ static void chrg_sink_unload_confirm_reset(eIDX_SOU_CH idx) } g_sink_unload_sample_seq[idx] = 0U; g_sink_unload_batch_confirmed[idx] = RT_FALSE; - g_sink_unload_current_confirmed[idx] = RT_FALSE; g_sink_unload_query_tick[idx] = 0U; g_sink_unload_confirm_count[idx] = 0U; } @@ -83,14 +95,6 @@ static void chrg_sink_unload_confirm_reset(eIDX_SOU_CH idx) 其它说明: 基线建立后返回成功,实际低电流确认仍由当前状态函数继续执行; 用于允许北向协议/CC与南向低电流确认并行推进 *****************************************************************/ -rt_bool_t chrg_sink_handshake_north_ready(eIDX_SOU_CH idx) -{ - if (idx >= TOTAL_SOU_CHS) { - return RT_FALSE; - } - return g_sink_unload_current_confirmed[idx]; -} - /***************************************************************** 函数名称: chrg_sink_unload_query_submit 函数描述: 按最小间隔提交当前通道的一次性P1量测请求 @@ -253,7 +257,7 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) first_start = (pSW->sink.work_mode != SINK_WORK_INIT_AUX_WAIT) ? RT_TRUE : RT_FALSE; vals[2] = pSW->CV_mode; - vals[3] = pSW->sink.volt_on; + vals[3] = pSW->sink.volt_on <= 500 ? 500 : pSW->sink.volt_on; if (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) { regs[count] = ModbusRTU_ShortTest_CMD_MODE_FLAG; vals[count++] = ModbusRTU_DYNA_CMD_MODE_STOP; @@ -273,6 +277,7 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) /* 南向批次已入队,北向按“CC->协议”顺序立即开始完整握手。 */ chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SINK); pNOR->enable[idx] = 1; + /* Protocol-before-CC test flow is disabled in this version. */ pSW->sub = IDX_SET_SINK_CC_BEFORE_PD; } pSW->sink.work_mode = SINK_WORK_INIT_AUX_WAIT; @@ -312,6 +317,40 @@ static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx, return 0; } +/***************************************************************** +函数名称: chrg_sink_volt_low_protect +函数描述: 主继电器闭合后持续监控南向实测输入电压,掉电立即转掉电保护 +输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 +输出参数: 电压到位时确认ready;掉电时强制进入SINK_WORK_LOW并执行掉电批次 +返回说明: 0:正常或保护批次已提交 <0:参数错误或保护批次提交失败 +其它说明: 由北向轮询线程每轮调用,不依赖北向0x20回码。协议板断电时北向 + 回码会中断(volt_low计数不再累积),而南向P1量测由功率板独立 + 供电持续刷新,是本保护唯一可靠的电量来源。只有"提交闭合且实测 + 电压已到位"的通道才启用掉电判定,继电器动作期间不误触发 +*****************************************************************/ +int chrg_sink_volt_low_protect(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) +{ + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { + return -1; + } + if (g_sink_rel_main_closed[idx] == 0) { + return 0; + } + if (pSW->Now_voltage >= WORK_MIN_VOLT) { + /* 实测电压到达工作下限,确认主继电器已闭合。 */ + g_sink_rel_main_ready[idx] = 1; + return 0; + } + if (g_sink_rel_main_ready[idx] != 0) { + /* 曾经到位后再次掉电:协议板处于断电窗口,禁止负载带载, + * 强制进入掉电安全处理等待协议板重新上电。 */ + pSW->sink.work_mode = SINK_WORK_LOW; + return chrg_sink_work(idx, pSW); + } + /* 已提交闭合但电压尚未建立(继电器动作中),继续等待不保护。 */ + return 0; +} + /***************************************************************** 函数名称: chrg_sink_work_volt_runing 函数描述: 执行负载RUNING状态,闭合全部继电器并启动负载 @@ -342,70 +381,40 @@ static int chrg_sink_work_volt_runing(eIDX_SOU_CH idx, struct chrg_switch_t *pSW ret = chrg_sou_com_batch_submit(idx, stop_regs, stop_vals, 2U); if (ret == 0) { pSW->sink.work_mode = SINK_WORK_LOAD_STANDBY; + g_sink_rel_main_closed[idx] = 1; } return ret; } - if (pSW->CV_mode == MODE_CONSTANT_VOLTAGE) { - regs[2] = REG_VOLTAGE_OUT + 1; - vals[2] = pSW->sink.loadv; - } else { - regs[2] = REG_CURRENT_OUT + 1; - vals[2] = pSW->sink.loadc; + /* 只有南向实测电压曾经到位后再次掉到低压,才判定为掉电。 + * 初次RUNING时继电器批次刚入队,Now_voltage可能仍是上一帧的0, + * 此时不能取消尚未发送到WORK_START的启动批次。 */ + if ((g_sink_rel_main_ready[idx] != 0) && + (pSW->Now_voltage < WORK_MIN_VOLT)) { + pSW->sink.work_mode = SINK_WORK_LOW; + return 0; } - return chrg_sou_com_batch_submit(idx, regs, vals, 3U); -} -/***************************************************************** -函数名称: chrg_sink_work_soft_resume -函数描述: 协议电压或协议电流变化完成后恢复负载 -输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 -输出参数: 命令入队成功后将工作状态切换为SINK_WORK_SOFT_RUNNING -返回说明: 0:命令提交成功 <0:参数或命令提交失败 -其它说明: 命令顺序为ALL_REL_ON、目标电流/电压、WORK_START;快速切换时 - 主继电器可能在完整握手阶段被关闭,恢复必须先确保继电器闭合 - 再启动电子负载,避免WORK_START先于主继电器带载;南向固件 - 继电器独立控制,ALL_REL_ON只开不关,不会误关已闭合的副继电器 -*****************************************************************/ -static int chrg_sink_work_soft_resume(eIDX_SOU_CH idx, - struct chrg_switch_t *pSW) -{ - rt_uint16_t regs[3] = {REG_REL_ON, 0, REG_WORK}; - rt_uint16_t vals[3] = {ALL_REL_ON, 0, WORK_START}; - int ret; - - if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { - return -1; - } - if (!chrg_sink_load_should_start(pSW)) { - /* 软卸载未切继电器,低电流下保持原继电器和协议,只关闭电子负载。 */ - regs[0] = REG_WORK; - vals[0] = WORK_STOP; - ret = chrg_sou_com_batch_submit(idx, regs, vals, 1U); - if (ret == 0) { - pSW->sink.work_mode = SINK_WORK_LOAD_SOFT_STANDBY; - } - return ret; - } if (pSW->CV_mode == MODE_CONSTANT_VOLTAGE) { - regs[2] = REG_VOLTAGE_OUT + 1; - vals[2] = pSW->sink.loadv; + regs[1] = REG_VOLTAGE_OUT + 1; + vals[1] = pSW->sink.loadv; } else { - regs[2] = REG_CURRENT_OUT + 1; - vals[2] = pSW->sink.loadc; + regs[1] = REG_CURRENT_OUT + 1; + vals[1] = pSW->sink.loadc; } - if (chrg_sou_com_batch_submit(idx, regs, vals, 3U) != 0) { - return -1; + /* RUNING批次必须完整发送:ALL_REL_ON、目标负载值、WORK_START。 */ + ret = chrg_sou_com_batch_submit(idx, regs, vals, 3U); + if (ret == 0) { + g_sink_rel_main_closed[idx] = 1; } - pSW->sink.work_mode = SINK_WORK_SOFT_RUNNING; - return 0; + return ret; } /***************************************************************** 函数名称: chrg_sink_work_load_stop 函数描述: 普通负载运行中设定电流降到最低门限以下时安全停止带载 输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 -输出参数: 命令入队成功后进入SINK_WORK_LOAD_SOFT_STANDBY +输出参数: 命令入队成功后进入SINK_WORK_LOAD_STANDBY 返回说明: 0:命令提交成功 <0:参数或命令提交失败 其它说明: 命令只发送WORK_STOP;不改变北向协议、CC、电流设定和 主副继电器,保证后续恢复有效电流时无需重新协议握手 @@ -422,26 +431,7 @@ static int chrg_sink_work_load_stop(eIDX_SOU_CH idx, if (chrg_sou_com_batch_submit(idx, ®, &val, 1U) != 0) { return -1; } - pSW->sink.work_mode = SINK_WORK_LOAD_SOFT_STANDBY; - return 0; -} - -/***************************************************************** -函数名称: chrg_sink_work_load_resume -函数描述: 从保持继电器的低电流待机状态恢复普通电子负载 -输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 -输出参数: 命令入队成功后进入SINK_WORK_SOFT_RUNNING -返回说明: 0:命令提交成功 <0:参数或命令提交失败 -其它说明: 本状态只作为待恢复标记,不直接下发WORK_START;必须由北向解析确认 - 实际电压稳定后转入SINK_WORK_SOFT_RESUME,再恢复目标电流和WORK_START -*****************************************************************/ -static int chrg_sink_work_load_resume(eIDX_SOU_CH idx, - struct chrg_switch_t *pSW) -{ - if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL) || - !chrg_sink_load_should_start(pSW)) { - return -1; - } + pSW->sink.work_mode = SINK_WORK_LOAD_STANDBY; return 0; } @@ -477,12 +467,8 @@ static int chrg_sink_work_load_start(eIDX_SOU_CH idx, *****************************************************************/ static int chrg_sink_nor_work_low(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) { - rt_uint16_t regs[4] = { - REG_WORK, REG_CURRENT_OUT + 1, REG_REL_ON, REG_REL_ON - }; - rt_uint16_t vals[4] = { - WORK_STOP, SINK_CLOSE_CURRENT_MA, ALL_REL_OFF, FU_REL_ON - }; + rt_uint16_t reg = REG_WORK; + rt_uint16_t value = WORK_STOP; if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { return -1; @@ -491,9 +477,14 @@ static int chrg_sink_nor_work_low(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) if (chrg_sou_com_batch_cancel(idx) != 0) { return -1; } - if (chrg_sou_com_batch_submit(idx, regs, vals, 4U) != 0) { + /* Low voltage stops the electronic load only. Do not alter South relays: + * an intentional protocol transition must not cause a relay-induced drop. */ + if (chrg_sou_com_batch_submit(idx, ®, &value, 1U) != 0) { return -1; } + /* 主继电器已随掉电批次断开,闭合跟踪与电压到位确认一并清除。 */ + g_sink_rel_main_closed[idx] = 0; + g_sink_rel_main_ready[idx] = 0; pSW->sink.work_mode = SINK_WORK_LOW_AUX_WAIT; return 0; } @@ -535,22 +526,74 @@ static int chrg_sink_work_low_aux_wait(eIDX_SOU_CH idx, 返回说明: 0:关机成功 <0:停止命令提交失败 其它说明: 先断开功率继电器并发送WORK_STOP,再关闭软件通道 *****************************************************************/ -static int chrg_sink_nor_work_off(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) -{ +static int chrg_sink_work_stop_prepare(eIDX_SOU_CH idx, + struct chrg_switch_t *pSW) +{ + rt_uint16_t reg = REG_WORK; + rt_uint16_t value = WORK_STOP; + + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { + return -1; + } + if (chrg_sou_com_batch_cancel(idx) != 0) { + return -1; + } + if (chrg_sou_com_batch_submit(idx, ®, &value, 1U) != 0) { + return -1; + } + + /* 主动关机先停止电子负载。WORK_STOP收到匹配回码后,必须通过 + * 停止命令之后的新P1量测连续确认低电流,才允许断开功率继电器。 */ + chrg_sink_unload_confirm_reset(idx); + pSW->sink.work_mode = SINK_WORK_STOP_WAIT; + return 0; +} + +static int chrg_sink_work_stop_relay(eIDX_SOU_CH idx, + struct chrg_switch_t *pSW) +{ + rt_uint16_t reg = REG_REL_ON; + rt_uint16_t value = ALL_REL_OFF; + + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { + return -1; + } + if (chrg_sou_com_batch_submit(idx, ®, &value, 1U) != 0) { + return -1; + } + + /* 继电器关闭命令已提交,等待南向回码后再清理软件通道。 */ + pSW->sink.work_mode = SINK_WORK_STOP_RELAY_WAIT; + return 0; +} + +static int chrg_sink_work_stop_relay_wait(eIDX_SOU_CH idx, + struct chrg_switch_t *pSW) +{ struct chrg_south_t *pSOU = &chrgsouth; struct chrg_north_t *pNOR = &chrgnorth; - rt_uint16_t regs[2] = {REG_REL_ON, REG_WORK}; - rt_uint16_t vals[2] = {ALL_REL_OFF, WORK_STOP}; + int result; - if (chrg_sou_com_batch_submit(idx, regs, vals, 2) != 0) { + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { return -1; } + if (chrg_sou_com_batch_is_pending(idx)) { + return 0; + } + result = chrg_sou_com_batch_get_result(idx); + if (result <= 0) { + return chrg_sink_work_stop_relay(idx, pSW); + } pSW->sink.On_work = 0; pSOU->online[idx] = 0; pNOR->enable[idx] = 0; + g_sink_rel_main_closed[idx] = 0; + g_sink_rel_main_ready[idx] = 0; - chrg_nor_sw_rel((eIDX_NOR_CH)idx, 0); //关闭北向继电器 + chrg_nor_sw_rel((eIDX_NOR_CH)idx, 0); + /* 主动停止已经完成,退出异步等待状态,禁止下一轮重复执行。 */ + pSW->sink.work_mode = SINK_WORK_WAIT; return 0; } @@ -585,6 +628,7 @@ static int chrg_sink_work_switch(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) /* 停止成功入队后,清除旧Source运行标志。 */ pSW->source.On_Flag = 0; /* 首次进入Sink时先设置目标CC线,CC稳定后再设置协议。 */ + /* Protocol-before-CC test flow is disabled in this version. */ pSW->sub = IDX_SET_SINK_CC_BEFORE_PD; /* SWITCH只负责旧角色退出,后续启动统一交给Sink INIT状态。 */ pSW->sink.work_mode = SINK_WORK_INIT; @@ -629,12 +673,8 @@ static int chrg_sink_work_protocol_unload(eIDX_SOU_CH idx, struct chrg_switch_t static int chrg_sink_work_handshake_prepare(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) { - rt_uint16_t regs[4] = { - REG_WORK, REG_CURRENT_OUT + 1, REG_REL_ON, REG_REL_ON - }; - rt_uint16_t vals[4] = { - WORK_STOP, SINK_CLOSE_CURRENT_MA, ALL_REL_OFF, FU_REL_ON - }; + rt_uint16_t reg = REG_WORK; + rt_uint16_t value = WORK_STOP; if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { return -1; @@ -643,11 +683,11 @@ static int chrg_sink_work_handshake_prepare(eIDX_SOU_CH idx, if (chrg_sou_com_batch_cancel(idx) != 0) { return -1; } - if (chrg_sou_com_batch_submit(idx, regs, vals, 4) != 0) { + if (chrg_sou_com_batch_submit(idx, ®, &value, 1U) != 0) { return -1; } - /* 四条写回码完成后,还必须连续确认两帧实际电流不大于200mA。 */ + /* 协议或CC切换先停止电子负载,连续5次确认低电流后再操作继电器。 */ chrg_sink_unload_confirm_reset(idx); pSW->sink.work_mode = SINK_WORK_HANDSHAKE_WAIT; return 0; @@ -664,7 +704,7 @@ static int chrg_sink_work_handshake_prepare(eIDX_SOU_CH idx, 还要求CURRENT=1000mA、ALL_REL_OFF和FU_REL_ON回码成功,但保持北向Sink继电器接通 *****************************************************************/ static int chrg_sink_work_current_wait(eIDX_SOU_CH idx, - struct chrg_switch_t *pSW, rt_bool_t full_handshake) + struct chrg_switch_t *pSW, rt_uint8_t next_action) { rt_uint32_t sample_seq; int batch_result; @@ -678,14 +718,24 @@ static int chrg_sink_work_current_wait(eIDX_SOU_CH idx, batch_result = chrg_sou_com_batch_get_result(idx); if (batch_result < 0) { - /* 写命令失败时重新执行完整卸载批次,禁止使用量测值提前放行。 */ - return full_handshake ? chrg_sink_work_handshake_prepare(idx, pSW) : - chrg_sink_work_protocol_unload(idx, pSW); + /* 写命令失败时重新执行停止命令,禁止使用量测值提前放行。 */ + if (next_action == SINK_UNLOAD_NEXT_HANDSHAKE) { + return chrg_sink_work_handshake_prepare(idx, pSW); + } + if (next_action == SINK_UNLOAD_NEXT_STOP_RELAY) { + return chrg_sink_work_stop_prepare(idx, pSW); + } + return chrg_sink_work_protocol_unload(idx, pSW); } if (batch_result == 0) { - /* 无有效批次结果时保持阻塞,并重新提交完整卸载动作。 */ - return full_handshake ? chrg_sink_work_handshake_prepare(idx, pSW) : - chrg_sink_work_protocol_unload(idx, pSW); + /* 无有效批次结果时保持阻塞,并重新提交停止动作。 */ + if (next_action == SINK_UNLOAD_NEXT_HANDSHAKE) { + return chrg_sink_work_handshake_prepare(idx, pSW); + } + if (next_action == SINK_UNLOAD_NEXT_STOP_RELAY) { + return chrg_sink_work_stop_prepare(idx, pSW); + } + return chrg_sink_work_protocol_unload(idx, pSW); } if (!g_sink_unload_batch_confirmed[idx]) { @@ -702,10 +752,17 @@ static int chrg_sink_work_current_wait(eIDX_SOU_CH idx, g_sink_unload_confirm_count[idx]++; if (g_sink_unload_confirm_count[idx] >= SINK_UNLOAD_CONFIRM_COUNT) { g_sink_unload_batch_confirmed[idx] = RT_FALSE; - g_sink_unload_current_confirmed[idx] = RT_TRUE; g_sink_unload_confirm_count[idx] = 0U; - pSW->sink.work_mode = full_handshake ? - SINK_WORK_WAIT : SINK_WORK_SOFT_RESUME_WAIT; + if (next_action == SINK_UNLOAD_NEXT_HANDSHAKE) { + /* 协议或CC切换保持南向继电器状态,低电流确认后直接开始北向配置。 */ + pSW->sink.work_mode = SINK_WORK_WAIT; + } else if (next_action == SINK_UNLOAD_NEXT_STOP_RELAY) { + pSW->sink.work_mode = SINK_WORK_STOP_RELAY; + } else { + /* Keep relays closed and resume through the common + * voltage-confirmed RUNING path. */ + pSW->sink.work_mode = SINK_WORK_WAIT; + } return 0; } } else { @@ -808,6 +865,7 @@ static int chrg_sink_TEST_OCP_ON(rt_uint8_t ch, struct chrg_switch_t *pSW) 返回说明: 0:状态处理成功 <0:参数、状态或命令提交失败 其它说明: 每通道记录上次成功状态,相同状态不重复下发寄存器 *****************************************************************/ +int workmode = 0; int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) { static uint8_t last_state[TOTAL_SOU_CHS] ={100,100,100,100}; @@ -818,9 +876,12 @@ int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) return -1; } work_mode = pSW->sink.work_mode; + workmode = work_mode; /* 异步等待状态需要持续检查批次或新量测,其余相同状态保持去重。 */ if ((work_mode == last_state[idx]) && (work_mode != SINK_WORK_INIT_AUX_WAIT) && + (work_mode != SINK_WORK_STOP_WAIT) && + (work_mode != SINK_WORK_STOP_RELAY_WAIT) && (work_mode != SINK_WORK_UNLOAD_WAIT) && (work_mode != SINK_WORK_LOW_AUX_WAIT) && (work_mode != SINK_WORK_HANDSHAKE_WAIT)) { @@ -858,7 +919,17 @@ int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) ret = 0; break; case SINK_WORK_STOP: - ret = chrg_sink_nor_work_off(idx,pSW); + ret = chrg_sink_work_stop_prepare(idx, pSW); + break; + case SINK_WORK_STOP_WAIT: + ret = chrg_sink_work_current_wait(idx, pSW, + SINK_UNLOAD_NEXT_STOP_RELAY); + break; + case SINK_WORK_STOP_RELAY: + ret = chrg_sink_work_stop_relay(idx, pSW); + break; + case SINK_WORK_STOP_RELAY_WAIT: + ret = chrg_sink_work_stop_relay_wait(idx, pSW); break; case SINK_WORK_SWITCH: ret = chrg_sink_work_switch(idx,pSW); @@ -867,25 +938,17 @@ int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) ret = chrg_sink_work_protocol_unload(idx, pSW); break; case SINK_WORK_UNLOAD_WAIT: - ret = chrg_sink_work_current_wait(idx, pSW, RT_FALSE); - break; - case SINK_WORK_SOFT_RESUME_WAIT: - ret = 0; - break; - case SINK_WORK_SOFT_RESUME: - ret = chrg_sink_work_soft_resume(idx, pSW); - break; - case SINK_WORK_SOFT_RUNNING: - ret = 0; + ret = chrg_sink_work_current_wait(idx, pSW, + SINK_UNLOAD_NEXT_RUNNING); break; case SINK_WORK_HANDSHAKE_PREPARE: ret = chrg_sink_work_handshake_prepare(idx, pSW); break; case SINK_WORK_HANDSHAKE_WAIT: - ret = chrg_sink_work_current_wait(idx, pSW, RT_TRUE); + ret = chrg_sink_work_current_wait(idx, pSW, + SINK_UNLOAD_NEXT_HANDSHAKE); break; case SINK_WORK_LOAD_STANDBY: - case SINK_WORK_LOAD_SOFT_STANDBY: ret = 0; break; case SINK_WORK_LOAD_STOP: @@ -894,9 +957,6 @@ int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) case SINK_WORK_LOAD_START: ret = chrg_sink_work_load_start(idx, pSW); break; - case SINK_WORK_LOAD_RESUME: - ret = chrg_sink_work_load_resume(idx, pSW); - break; default: break; } diff --git a/apps/chrg/applications/utils/chrg_sink.h b/apps/chrg/applications/utils/chrg_sink.h index cec49ec..97b544e 100644 --- a/apps/chrg/applications/utils/chrg_sink.h +++ b/apps/chrg/applications/utils/chrg_sink.h @@ -208,7 +208,8 @@ enum { */ #define SINK_LOAD_ENABLE_MIN_MA 100U -extern rt_bool_t chrg_sink_handshake_north_ready(eIDX_SOU_CH idx); +/* 主继电器闭合后的0V持续监控:由北向轮询线程每轮调用,掉电立即转掉电保护。 */ +extern int chrg_sink_volt_low_protect(eIDX_SOU_CH idx, struct chrg_switch_t *pSW); enum { SINK_WORK_INIT = 0, // 启动入口:第一条南向命令只打开副继电器 @@ -219,23 +220,21 @@ enum { SINK_WORK_LOW, // 运行电压过低,执行掉电安全处理 SINK_WORK_LOW_AUX_WAIT, // 等待掉电处理及副继电器恢复批次完成 SINK_WORK_LOW_MONITOR, // 副继电器已恢复,等待输入电压重新出现 - SINK_WORK_STOP, // 用户主动停止负载 + SINK_WORK_STOP, // 用户主动停止:先停止负载并确认低电流 SINK_WORK_SWITCH, // 停止旧电源后进入负载INIT SINK_WORK_PROTOCOL_UNLOAD, // 协议电压或电流变化:掉载但不切换继电器 SINK_WORK_UNLOAD_WAIT, // 等待软卸载完成并连续两次确认电流不大于200mA - SINK_WORK_SOFT_RESUME_WAIT, // 继电器保持闭合,等待协议电压稳定后恢复负载 - SINK_WORK_SOFT_RESUME, // 只恢复目标电流/电压和WORK_START,不写继电器 - SINK_WORK_SOFT_RUNNING, // 软恢复后的稳定运行状态,禁止重复切换继电器 SINK_WORK_ON_TEST_DYNA, // 动态负载测试启动状态 SINK_WORK_ON_TEST_SHORT, // 短路测试启动状态 SINK_WORK_ON_TEST_OCP, // OCP过流保护测试启动状态 SINK_WORK_HANDSHAKE_PREPARE, // 完整重握手:停止、清流、全关继电器后打开副继电器 SINK_WORK_HANDSHAKE_WAIT, // 南向低电流确认与北向协议/CC并行 SINK_WORK_LOAD_STANDBY, // 协议已就绪但主继电器未打开,低设定电流下保持停止 - SINK_WORK_LOAD_SOFT_STANDBY, // 协议和继电器保持不变,运行中降至低电流后的停止状态 SINK_WORK_LOAD_STOP, // 运行中跨到低电流:只发送WORK_STOP关闭电子负载 SINK_WORK_LOAD_START, // 主继电器未打开的低电流待机恢复:等待北向电压稳定后进入RUNING - SINK_WORK_LOAD_RESUME, // 软待机跨回有效电流:等待北向电压稳定后进入SOFT_RESUME + SINK_WORK_STOP_WAIT, // 关机:等待连续5次实际电流达到安全范围 + SINK_WORK_STOP_RELAY, // 关机:低电流确认后提交关闭南向继电器 + SINK_WORK_STOP_RELAY_WAIT // 关机:等待关闭南向继电器的回码 }; // sink 参数结构 diff --git a/apps/chrg/chrg.uvprojx b/apps/chrg/chrg.uvprojx index 1b82e8a..6090132 100644 --- a/apps/chrg/chrg.uvprojx +++ b/apps/chrg/chrg.uvprojx @@ -132,7 +132,7 @@ 1 0 0 - 0 + 1 1 4096 diff --git a/apps/chrg/codex_low_voltage_relay_verify.log b/apps/chrg/codex_low_voltage_relay_verify.log new file mode 100644 index 0000000..7d4c47d --- /dev/null +++ b/apps/chrg/codex_low_voltage_relay_verify.log @@ -0,0 +1,9 @@ +*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin' +Build target 'chrg' +compiling chrg_sink.c... +linking... +Program Size: Code=147156 RO-data=15312 RW-data=9328 ZI-data=15984 +FromELF: creating hex file... +After Build - User command #1: fromelf --bin .\build\keil\Obj\chrg.axf -o build/chrg.bin +".\build\keil\Obj\chrg.axf" - 0 Error(s), 0 Warning(s). +Build Time Elapsed: 00:00:02 diff --git a/apps/chrg/codex_protocol_ack_verify.log b/apps/chrg/codex_protocol_ack_verify.log new file mode 100644 index 0000000..0b3c0f9 --- /dev/null +++ b/apps/chrg/codex_protocol_ack_verify.log @@ -0,0 +1,18 @@ +*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin' +Build target 'chrg' +compiling chrg_north_pkg.c... +compiling chrg_lcd.c... +compiling chrg_thread.c... +compiling chrg_south.c... +compiling chrg_sink.c... +compiling chrg_north.c... +compiling chrg_source.c... +compiling chrg_roll_nor.c... +compiling chrg_roll_sou.c... +compiling chrg_comm.c... +linking... +Program Size: Code=146988 RO-data=15312 RW-data=9328 ZI-data=15984 +FromELF: creating hex file... +After Build - User command #1: fromelf --bin .\build\keil\Obj\chrg.axf -o build/chrg.bin +".\build\keil\Obj\chrg.axf" - 0 Error(s), 0 Warning(s). +Build Time Elapsed: 00:00:03 diff --git a/apps/chrg/codex_soft_resume_remove.log b/apps/chrg/codex_soft_resume_remove.log new file mode 100644 index 0000000..5f103a7 --- /dev/null +++ b/apps/chrg/codex_soft_resume_remove.log @@ -0,0 +1,21 @@ +*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin' +Build target 'chrg' +compiling chrg_rel.c... +compiling chrg_vcom.c... +compiling chrg_north_pkg.c... +compiling chrg_lcd.c... +compiling chrg_thread.c... +compiling chrg_south.c... +compiling chrg_eload.c... +compiling chrg_sink.c... +compiling chrg_north.c... +compiling chrg_source.c... +compiling chrg_roll_nor.c... +compiling chrg_roll_sou.c... +compiling chrg_comm.c... +linking... +Program Size: Code=146964 RO-data=15312 RW-data=9328 ZI-data=15984 +FromELF: creating hex file... +After Build - User command #1: fromelf --bin .\build\keil\Obj\chrg.axf -o build/chrg.bin +".\build\keil\Obj\chrg.axf" - 0 Error(s), 0 Warning(s). +Build Time Elapsed: 00:00:02 diff --git a/apps/chrg/codex_stop_current_confirm_verify.log b/apps/chrg/codex_stop_current_confirm_verify.log new file mode 100644 index 0000000..df56d49 --- /dev/null +++ b/apps/chrg/codex_stop_current_confirm_verify.log @@ -0,0 +1,21 @@ +*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin' +Build target 'chrg' +compiling chrg_vcom.c... +compiling chrg_thread.c... +compiling chrg_north_pkg.c... +compiling chrg_lcd.c... +compiling chrg_rel.c... +compiling chrg_eload.c... +compiling chrg_sink.c... +compiling chrg_south.c... +compiling chrg_source.c... +compiling chrg_north.c... +compiling chrg_roll_nor.c... +compiling chrg_roll_sou.c... +compiling chrg_comm.c... +linking... +Program Size: Code=147032 RO-data=15312 RW-data=9328 ZI-data=15984 +FromELF: creating hex file... +After Build - User command #1: fromelf --bin .\build\keil\Obj\chrg.axf -o build/chrg.bin +".\build\keil\Obj\chrg.axf" - 0 Error(s), 0 Warning(s). +Build Time Elapsed: 00:00:03 diff --git a/apps/chrg/codex_stop_direct_verify.log b/apps/chrg/codex_stop_direct_verify.log new file mode 100644 index 0000000..53e6e21 --- /dev/null +++ b/apps/chrg/codex_stop_direct_verify.log @@ -0,0 +1,21 @@ +*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin' +Build target 'chrg' +compiling chrg_rel.c... +compiling chrg_north_pkg.c... +compiling chrg_thread.c... +compiling chrg_vcom.c... +compiling chrg_lcd.c... +compiling chrg_eload.c... +compiling chrg_sink.c... +compiling chrg_source.c... +compiling chrg_south.c... +compiling chrg_north.c... +compiling chrg_roll_nor.c... +compiling chrg_roll_sou.c... +compiling chrg_comm.c... +linking... +Program Size: Code=146976 RO-data=15312 RW-data=9328 ZI-data=15984 +FromELF: creating hex file... +After Build - User command #1: fromelf --bin .\build\keil\Obj\chrg.axf -o build/chrg.bin +".\build\keil\Obj\chrg.axf" - 0 Error(s), 0 Warning(s). +Build Time Elapsed: 00:00:03 diff --git a/apps/chrg/codex_stop_repeat_guard_verify.log b/apps/chrg/codex_stop_repeat_guard_verify.log new file mode 100644 index 0000000..ccbd541 --- /dev/null +++ b/apps/chrg/codex_stop_repeat_guard_verify.log @@ -0,0 +1,9 @@ +*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin' +Build target 'chrg' +compiling chrg_comm.c... +linking... +Program Size: Code=147096 RO-data=15312 RW-data=9328 ZI-data=15984 +FromELF: creating hex file... +After Build - User command #1: fromelf --bin .\build\keil\Obj\chrg.axf -o build/chrg.bin +".\build\keil\Obj\chrg.axf" - 0 Error(s), 0 Warning(s). +Build Time Elapsed: 00:00:02 diff --git a/apps/chrg/codex_verify.log b/apps/chrg/codex_verify.log index d874887..72d757a 100644 --- a/apps/chrg/codex_verify.log +++ b/apps/chrg/codex_verify.log @@ -1,11 +1,9 @@ *** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin' Build target 'chrg' -compiling chrg_eload.c... compiling chrg_sink.c... -compiling chrg_roll_sou.c... linking... -Program Size: Code=146936 RO-data=15312 RW-data=9328 ZI-data=15992 +Program Size: Code=147104 RO-data=15312 RW-data=9328 ZI-data=16000 FromELF: creating hex file... After Build - User command #1: fromelf --bin .\build\keil\Obj\chrg.axf -o build/chrg.bin ".\build\keil\Obj\chrg.axf" - 0 Error(s), 0 Warning(s). -Build Time Elapsed: 00:00:04 +Build Time Elapsed: 00:00:01