Initial commit: CCU621_M firmware project with BLE debug link support.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-08 17:28:36 +08:00
commit 9ceb218f80
1597 changed files with 724159 additions and 0 deletions
+706
View File
@@ -0,0 +1,706 @@
#include "flowctrl/mdu_swh_ctrl.h"
#include "flowctrl/flowctrl_task.h"
#include "flowctrl/flow_interface.h"
#include "collect_ctrl/yk_ctrl.h"
#include "publicdata/publicdata.h"
extern S_FLOW_DATA s_flow_data;
#if 1 //母联逻辑控制
/**
* ************************************************************************
* @brief - 功率切换计算 -- 检查另一把枪充电状态 控制母联闭合
*
* @param[in] u8_gunNo - 枪号
*
* @return U8_T - 借用模块动作标志 0正常使用 1新增借用模块 2 退出借用模块
*
* @author jiankalka
* @date 2025-11-20
* ************************************************************************
*/
static U8_T u8_mdu_shw_power_switching(U8_T u8_gunNo)
{
U8_T u8_other_mdu_action = 0; //
U8_T u8_otherGunNo = 1-u8_gunNo; // 双枪桩 另一把枪号
static U32_T u32_bus_action_time = 0;
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //获取充电实时信息
S_FLOW_REAL_DATA *s_other_real_data = &s_flow_data.s_real_data[u8_otherGunNo]; //获取充电实时信息
U16_T u16_other_k1k2_pos,u16_other_k1k2_neg,u16_other_xiefang ;
U16_T u16_mdu_put_vol ,u16_other_mdu_put_vol;
U8_T u8_mdu_inpile_num = u16_flow_get_sys_data(u8_gunNo , E_FLOW_GET_DATA_MDU_IN_NUM , 0); //获取模块分配数量
U16_T u16_other_mdu_state = u16_flow_get_sys_data(u8_otherGunNo, E_FLOW_GET_DATA_MDU_WORK,0); //获取模块运行状态 0空闲 1工作
U8_T u8_mdu_rated_pow = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_MDU_RATED_POW,0); //单模块额定功率 单位kw
U8_T u8_bus_km_state = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_BUS_KM,0); //母联接触器状态 0:断开; 1:闭合
U8_T u8_dc_bus_en = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_DC_BUS_EN,0); //直流母联接触器使能 0 不使能 1使能
U64_T u64_need_pow = (U64_T)(s_real_data->u16_need_vol * s_real_data->u16_need_cur)/100; //需求功率 单位w
U64_T u64_usable_max_pow = u8_mdu_rated_pow * 1000 * u8_mdu_inpile_num; //本枪最大可用功率 单位w
if(u8_bus_km_state) //母联闭合 检查母联断开条件
{
//另一把枪 不可借用时 断开母联并退出模块
if(s_other_real_data->e_flow_real_state != E_FLOW_REAL_FREE &&
s_other_real_data->e_flow_real_state != E_FLOW_REAL_STOP_OK)
{
if(u32_bus_action_time == 0)
u32_bus_action_time = get_current_seconds();
u8_other_mdu_action = 2; //退出借用模块
//借用模块停止运行 或者 借用枪状态大于等于绝缘启动状态 或者 停止时间超过5秒 断开母联
if(u16_other_mdu_state == 0 ||
s_other_real_data->e_flow_real_state >= E_FLOW_REAL_INSUL_START ||
u32_safe_seconds_since(u32_bus_action_time) > 5)
{
u16_flow_put_ctrl(0,E_FLOW_CTRL_DATA_BUS_YK,CMD_OFF,0); //断开母联
FLOWCTRL_LOG("[%d](0-N)Other gun NA[%d], open bus\n",u8_gunNo,s_other_real_data->e_flow_real_state);
}
}
//如果需求功率 小于本枪最大可用功率(5kw冗余防抖) 说明不需要借用模块 则控制模块退出并断开模块
else if(u64_need_pow < u64_usable_max_pow - 5*1000 )
{
if(u32_bus_action_time == 0)
u32_bus_action_time = get_current_seconds();
u8_other_mdu_action = 2; //退出借用模块
//借用模块停止运行 或者 停止时间超过5秒 断开母联
if(u16_other_mdu_state == 0 ||
u32_safe_seconds_since(u32_bus_action_time) > 5)
{
u16_flow_put_ctrl(0,E_FLOW_CTRL_DATA_BUS_YK,CMD_OFF,0); //断开母联
FLOWCTRL_LOG("[%d](0-N)Need drop, open bus\n",u8_gunNo);
}
}
else //正常借用
{
u32_bus_action_time = 0;
}
}
else //母联断开 检查母联闭合条件
{
if(u8_dc_bus_en == 0) //直流母联接触器不使能 则不借用模块
{
return u8_other_mdu_action;
}
//如果需求功率 大于本枪最大可用功率 (此处不单独增加功率防抖,仅在退出时使用防抖)
if(u64_need_pow > u64_usable_max_pow )
{
//另一把枪处于空闲状态 可以借用
if(s_other_real_data->e_flow_real_state == E_FLOW_REAL_FREE ||
s_other_real_data->e_flow_real_state == E_FLOW_REAL_STOP_OK)
{
u16_other_k1k2_pos = u16_flow_get_sys_data(u8_otherGunNo,E_FLOW_GET_DATA_KM_POS,0); //正母线直流输出接触器状态
u16_other_k1k2_neg = u16_flow_get_sys_data(u8_otherGunNo,E_FLOW_GET_DATA_KM_NEG,0); //负母线直流输出接触器状态
u16_other_xiefang = u16_flow_get_sys_data(u8_otherGunNo,E_FLOW_GET_DATA_XF_KM,0); //泄放接触器状态
// 另一把枪K1K2 和 泄放状态都是断开
if(u16_other_k1k2_pos == 0 &&
u16_other_k1k2_neg == 0 &&
u16_other_xiefang == 0)
{
u8_other_mdu_action = 1; //新增借用模块
//控制模块启动
if(u16_other_mdu_state) //模块运行 则检查两组模块输出电压差值
{
u16_mdu_put_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_MDU_PUT_VOL,0); //获取模块输出电压值 精度0.1V
u16_other_mdu_put_vol = u16_flow_get_sys_data(u8_otherGunNo,E_FLOW_GET_DATA_MDU_PUT_VOL,0); //获取模块输出电压值 精度0.1V
//借用模块输出电压 和 本枪模块输出电压 差值在10以内 则闭合母联
if(abs(u16_mdu_put_vol - u16_other_mdu_put_vol) < 10*10)
{
if(u32_bus_action_time == 0)
u32_bus_action_time = get_current_seconds();
if(u32_safe_seconds_since(u32_bus_action_time) > 2) //延时2秒
{
u16_flow_put_ctrl(0,E_FLOW_CTRL_DATA_BUS_YK,CMD_ON,0); //闭合母联
FLOWCTRL_LOG("[%d](0-N)V bal(%d,%d)(0.1V), close bus\n",u8_gunNo,u16_mdu_put_vol,u16_other_mdu_put_vol);
}
}
else
u32_bus_action_time = 0;
}
else
u32_bus_action_time = 0;
}
}
}
}
return u8_other_mdu_action;
}
/**
* ************************************************************************
* @brief - 模块母联控制 充电中切换控制
*
* @param[in] u8_gunNo - 枪号
*
*
* @author jiankalka
* @date 2025-11-20
* ************************************************************************
*/
static void v_mdu_swh_chargeing_ctrl(U8_T u8_gunNo)
{
U8_T u8_otherGunNo = 1-u8_gunNo; // 双枪桩 另一把枪号
S_MDU_ALLOCATE_CTRL *s_mdu_allocate_ctrl = &s_flow_data.s_mdu_allocate_ctrl[u8_gunNo];
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //获取充电实时信息
U16_T u16_mdu_put_vol; //获取模块输出电压值 精度0.1V
U8_T u8_mdu_rung_num = u16_flow_get_sys_data(u8_gunNo , E_FLOW_GET_DATA_MDU_RUN_NUM , 0); //获取模块运行数量
U8_T u8_mdu_inpile_num = u16_flow_get_sys_data(u8_gunNo , E_FLOW_GET_DATA_MDU_IN_NUM , 0); //获取模块分配数量
U8_T u8_othergun_mdu_rung_num = u16_flow_get_sys_data(u8_otherGunNo , E_FLOW_GET_DATA_MDU_RUN_NUM , 0); //获取模块运行数量
U8_T u8_bus_km_state = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_BUS_KM,0); //母联接触器状态 0:断开; 1:闭合
//功率切换计算 -- 检查另一把枪充电状态 控制母联闭合
U8_T u8_other_mdu_action = u8_mdu_shw_power_switching(u8_gunNo); // 模块退出时 要单独控制另外一组模块停止
if(u8_bus_km_state) //母联闭合 则两组模块都为一把枪充电
{
if(u8_other_mdu_action == 0) //借用模块正常使用
{
s_mdu_allocate_ctrl->u8_yk_cmd = 3; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
s_mdu_allocate_ctrl->u16_need_vol = s_real_data->u16_need_vol; //需求电压 精度0.1
s_mdu_allocate_ctrl->u16_need_cur = s_real_data->u16_need_cur; //需求电流 精度0.1
if(u8_mdu_rung_num + u8_othergun_mdu_rung_num != 0)
s_mdu_allocate_ctrl->u16_one_mdu_need_cur = s_real_data->u16_need_cur/(u8_mdu_rung_num + u8_othergun_mdu_rung_num); //单模块需求电流 精度0.1
else
s_mdu_allocate_ctrl->u16_one_mdu_need_cur = 0;
//控制借用模块 启动
s_flow_data.s_mdu_allocate_ctrl[u8_otherGunNo].u8_yk_cmd = 3; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
s_flow_data.s_mdu_allocate_ctrl[u8_otherGunNo].u16_need_vol = s_real_data->u16_need_vol; //需求电压 精度0.1
s_flow_data.s_mdu_allocate_ctrl[u8_otherGunNo].u16_need_cur = s_real_data->u16_need_cur; //需求电流 精度0.1
s_flow_data.s_mdu_allocate_ctrl[u8_otherGunNo].u16_one_mdu_need_cur = s_mdu_allocate_ctrl->u16_one_mdu_need_cur;
}
else if(u8_other_mdu_action == 2) //模块退出
{
s_mdu_allocate_ctrl->u8_yk_cmd = 3; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
s_mdu_allocate_ctrl->u16_need_vol = s_real_data->u16_need_vol; //需求电压 精度0.1
s_mdu_allocate_ctrl->u16_need_cur = s_real_data->u16_need_cur; //需求电流 精度0.1
if(u8_mdu_rung_num != 0)
s_mdu_allocate_ctrl->u16_one_mdu_need_cur = s_real_data->u16_need_cur/(u8_mdu_rung_num); //单模块需求电流 精度0.1
else
s_mdu_allocate_ctrl->u16_one_mdu_need_cur = 0;
//另一组控制停止
memset(&s_flow_data.s_mdu_allocate_ctrl[u8_otherGunNo] , 0 ,sizeof(S_MDU_ALLOCATE_CTRL));
s_flow_data.s_mdu_allocate_ctrl[u8_otherGunNo].u8_yk_cmd = 4; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
}
}
else //母联断开 则各算各的
{
s_mdu_allocate_ctrl->u8_yk_cmd = 3; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
s_mdu_allocate_ctrl->u16_need_vol = s_real_data->u16_need_vol; //需求电压 精度0.1
s_mdu_allocate_ctrl->u16_need_cur = s_real_data->u16_need_cur; //需求电流 精度0.1
if(u8_mdu_rung_num != 0)
s_mdu_allocate_ctrl->u16_one_mdu_need_cur = s_real_data->u16_need_cur/u8_mdu_rung_num; //单模块需求电流 精度0.1
else
s_mdu_allocate_ctrl->u16_one_mdu_need_cur = 0;
if(u8_other_mdu_action == 1) //新增借用模块
{
u16_mdu_put_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_MDU_PUT_VOL,0); //获取模块输出电压值 精度0.1V
if(abs(s_real_data->u16_need_vol - u16_mdu_put_vol) < 50) //如果输出电压和需求电压 误差5V以内 则认为是测试仪 避免优优绿能模块卡500V飘动 导致模块反复启停
u16_mdu_put_vol = s_real_data->u16_need_vol;
//控制借用模块 启动
s_flow_data.s_mdu_allocate_ctrl[u8_otherGunNo].u8_yk_cmd = 3; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
s_flow_data.s_mdu_allocate_ctrl[u8_otherGunNo].u16_need_vol = u16_mdu_put_vol; //需求电压 精度0.1
s_flow_data.s_mdu_allocate_ctrl[u8_otherGunNo].u16_one_mdu_need_cur = 0;
}
}
}
/**
* ************************************************************************
* @brief - 充电停止判断函数 检测母联状态和借用模块状态
*
* @param[in] u8_gunNo -
*
*
* @author jiankalka
* @date 2025-11-21
* ************************************************************************
*/
static void v_mdu_swh_charge_stop_ctrl(U8_T u8_gunNo)
{
U8_T u8_otherGunNo = 1-u8_gunNo; // 双枪桩 另一把枪号
S_MDU_ALLOCATE_CTRL *s_mdu_allocate_ctrl = &s_flow_data.s_mdu_allocate_ctrl[u8_gunNo];
S_MDU_ALLOCATE_CTRL *s_other_mdu_allocate_ctrl = &s_flow_data.s_mdu_allocate_ctrl[u8_otherGunNo];
S_FLOW_REAL_DATA *s_other_real_data = &s_flow_data.s_real_data[u8_otherGunNo]; //获取充电实时信息
U8_T u8_bus_km_state = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_BUS_KM,0); //母联接触器状态 0:断开; 1:闭合
U16_T u16_other_mdu_state = u16_flow_get_sys_data(u8_otherGunNo, E_FLOW_GET_DATA_MDU_WORK,0); //获取模块运行状态 0空闲 1工作
//首先停掉自身模块
memset(s_mdu_allocate_ctrl , 0 ,sizeof(S_MDU_ALLOCATE_CTRL));
s_mdu_allocate_ctrl->u8_yk_cmd = 4; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
//判断母联状态 母联闭合时 需要判断借用枪的状态是否为空闲 空闲时则控制停止与断开
if(u8_bus_km_state)
{
if(s_other_real_data->e_flow_real_state == E_FLOW_REAL_FREE || //另一把枪未充电
s_other_real_data->e_flow_real_state == E_FLOW_REAL_STOP_OK)
{
if(u16_other_mdu_state) //借用模块在运行 则停止运行
{
memset(s_other_mdu_allocate_ctrl , 0 ,sizeof(S_MDU_ALLOCATE_CTRL));
s_other_mdu_allocate_ctrl->u8_yk_cmd = 4; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
}
else
{
u16_flow_put_ctrl(0,E_FLOW_CTRL_DATA_BUS_YK,CMD_OFF,0); //断开母联
FLOWCTRL_LOG("[%d](0-N)Gun stop, open bus\n",u8_gunNo);
}
}
}
}
/**
* ************************************************************************
* @brief - 母联切换控制
*
* @param[in] u16_leep_time -
*
*
* @author jiankalka
* @date 2025-11-18
* ************************************************************************
*/
static void v_mdu_shw_ctrl_bus_coupler(U16_T u16_leep_time)
{
U8_T u8_gunNo,u8_otherGunNo;
S_FLOW_REAL_DATA *s_real_data = NULL; //充电实时信息 空闲时清零
S_MDU_ALLOCATE_CTRL *s_mdu_allocate_ctrl = NULL;
for ( u8_gunNo = 0; u8_gunNo < s_flow_data.u8_gunCnt; u8_gunNo++)
{
s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //获取充电实时信息
s_mdu_allocate_ctrl = &s_flow_data.s_mdu_allocate_ctrl[u8_gunNo];
u8_otherGunNo = 1-u8_gunNo; // 双枪桩 另一把枪号
switch (s_real_data->e_flow_real_state)
{
case E_FLOW_REAL_FREE : //空闲
case E_FLOW_REAL_STOP_OK : //充电停止完成
{
U8_T u8_bus_km_state = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_BUS_KM,0); //母联接触器状态 0:断开; 1:闭合
U16_T u16_mdu_state = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_MDU_WORK,0); //获取模块运行状态 0空闲 1工作
if(s_flow_data.s_real_data[u8_otherGunNo].e_flow_real_state == E_FLOW_REAL_FREE ||
s_flow_data.s_real_data[u8_otherGunNo].e_flow_real_state == E_FLOW_REAL_STOP_OK) //另一把枪也是空闲 则清空、停止 否则可能在借用
{
memset(s_mdu_allocate_ctrl , 0 ,sizeof(S_MDU_ALLOCATE_CTRL));
s_mdu_allocate_ctrl->u8_yk_cmd = 4; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
}
//对面不是空闲 但是本枪模块是空闲 则断开母联(防止充电停止时未能断开母联,此时如果另一把枪借用模块也是先启动模块再闭合母联 不会影响)
else if(u8_bus_km_state == 1 && u16_mdu_state == 0)
{
u16_flow_put_ctrl(0,E_FLOW_CTRL_DATA_BUS_YK,CMD_OFF,0); //断开母联
// FLOWCTRL_LOG("[%d](0-N)Gun stop, MDU idle, open bus\n",u8_gunNo);
}
break;
}
case E_FLOW_REAL_CHARGE_START : //充电启动 --借用后的模块如何能确保此状态下能完全停止?
{
memset(s_mdu_allocate_ctrl , 0 ,sizeof(S_MDU_ALLOCATE_CTRL));
s_mdu_allocate_ctrl->u8_yk_cmd = 4; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
break;
}
case E_FLOW_REAL_INSUL_START : //绝缘启动 -- 控制模块启动充电
{
s_mdu_allocate_ctrl->u8_yk_cmd = 1; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
s_mdu_allocate_ctrl->u16_need_vol = s_real_data->u16_need_vol; //需求电压 精度0.1
s_mdu_allocate_ctrl->u16_need_cur = 5; //需求电流 精度0.1
s_mdu_allocate_ctrl->u16_one_mdu_need_cur = 5; //单模块需求电流 精度0.1
break;
}
case E_FLOW_REAL_INSUL_OK : //绝缘计算完成
case E_FLOW_REAL_INSUL_MDU_STOP : //绝缘检测模块停止
case E_FLOW_REAL_BMS_OUTTIME : //BMS通讯超时
{
memset(s_mdu_allocate_ctrl , 0 ,sizeof(S_MDU_ALLOCATE_CTRL));
s_mdu_allocate_ctrl->u8_yk_cmd = 2; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
break;
}
case E_FLOW_REAL_PRE_START : //开始预充 --预充启动电压
{
s_mdu_allocate_ctrl->u8_yk_cmd = 3; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
s_mdu_allocate_ctrl->u16_need_vol = s_real_data->u16_need_vol; //需求电压 精度0.1
s_mdu_allocate_ctrl->u16_need_cur = 5; //需求电流 精度0.1
s_mdu_allocate_ctrl->u16_one_mdu_need_cur = 5; //单模块需求电流 精度0.1
break;
}
case E_FLOW_REAL_PRE_OK : //预充完成 -- 充电中 计算需求电流和分配模块
case E_FLOW_REAL_CHARGEING : //充电中
{
v_mdu_swh_chargeing_ctrl(u8_gunNo); //充电中控制函数
break;
}
case E_FLOW_REAL_STOP : //充电停止
{
v_mdu_swh_charge_stop_ctrl(u8_gunNo);
break;
}
default:
break;
}
}
}
#endif
#if 1 //交流接触器 风扇 控制
/**
* ************************************************************************
* @brief - 交流接触器闭合条件判断
* 如没有枪闭合,直接断开
* 如有枪闭合,且工作状态不为空闲或充电完成,即为充电状态中,闭合交流接触器
* 如有枪闭合,且工作状态为空闲或充电完成,则充电借宿5分钟内闭合接触器,5分钟外,断开接触器
*
* @return U8_T - 0断开 1闭合
*
* @author jiankalka
* @date 2025-09-05
* ************************************************************************
*/
static U8_T u8_flow_get_acky_action()
{
U8_T i, u8_ret = 0; //默认断开
U8_T u8_state = 0; //状态检查 0都未插枪 1存在插枪且不存在充电中 2存在插枪且存在充电中
static ULONG long_timer = 0;
static U8_T u8_old_state = 0; //保存上一次的状态
static U8_T u8_first_run = 1; //首次运行标志,用于排除系统刚启动时的误动作
U8_T u8_gunLink; //枪连接状态 0未连接 1已连接
S_FLOW_REAL_DATA *s_real_data = NULL; //充电实时信息 空闲时清零
for (i = 0; i < s_flow_data.u8_gunCnt; i++) //遍历所有枪
{
u8_gunLink = u16_flow_get_sys_data(i, E_FLOW_GET_DATA_GUN_LINK, 0); //枪连接状态 0未连接 1已连接
s_real_data = &s_flow_data.s_real_data[i]; //获取充电实时信息
if(u8_gunLink == 1) //枪连接
{
u8_state = 1; //1存在插枪且不存在充电中
if(s_real_data->e_flow_real_state > E_FLOW_REAL_FREE && //充电状态 大于空闲 且小于充电完成,则为充电中
s_real_data->e_flow_real_state < E_FLOW_REAL_STOP_OK)
{
u8_state = 2; //2存在插枪且存在充电中
break;
}
}
}
/*
* 状态改变时重置计时器
* 特殊要求:
* - 1->0(插枪未充电超过5分钟后拔枪)时,不希望再次闭合3秒,因此该场景下不重置long_timer,
* 让“无连接”分支直接按已超时状态处理(保持断开)。
*/
U8_T u8_prev_state = u8_old_state;
if(u8_state != u8_old_state)
{
// 除了 1->0 的场景,其余状态切换都重置计时器
if (!(u8_prev_state == 1 && u8_state == 0)) {
long_timer = get_current_seconds();
}
u8_first_run = 0; //一旦发生过状态变化,即退出“首次运行保护”
// printf("acky_action state %d -> %d\r\n",u8_prev_state,u8_state);
u8_old_state = u8_state;
}
if(u8_state == 2) //存在插枪且存在充电中,直接闭合交流接触器
{
u8_ret = 1; //控制闭合
}
else if(u8_state == 1) //存在插枪但未充电 == 延时5分钟后断开
{
if(u32_safe_seconds_since(long_timer) < 10 * 60) //5分钟以内闭合
{
u8_ret = 1;
}
else
{
u8_ret = 0; //5分钟后断开
}
}
else //状态0:无连接
{
// 特殊情况:刚从状态1切换到0(即拔枪),如果之前在状态1时已经因为超过5分钟而断开,
// 不希望再次闭合3秒,这里直接保持断开。
if (u8_prev_state == 1)
{
u8_ret = 0; //系统刚启动,直接断开,避免误动作
}
else
{
// 普通“无连接”场景:考虑首次运行保护 + 3秒延时断开
// 排除系统刚运行时的误动作:系统运行时间小于30秒时直接断开
if(u8_first_run && get_current_seconds() < 30)
{
u8_ret = 0; //系统刚启动,直接断开,避免误动作
}
else if(u32_safe_seconds_since(long_timer) < 3) //3秒以内保持闭合
{
u8_ret = 1;
}
else
{
u8_ret = 0; //3秒后断开
}
}
}
return u8_ret;
}
#endif
#if 1 //风扇控制
static void v_fan_ctrl(U16_T u16_leep_time)
{
U8_T u8_gunNo,u8_run_flag = 0;
S_FLOW_REAL_DATA *s_real_data = NULL; //充电实时信息 空闲时清零
/* 风扇关机延时逻辑:
* - 只在“从工作->不工作”切换瞬间开始计时
* - 若 5 分钟内又进入“工作”(任一枪充电中),则取消关机并保持开启
*/
static U8_T u8_prev_run_flag = 0;
static U32_T u32_fan_off_start_sec = 0; //进入“需要延时关机”的起始秒数
static U8_T u8_fan_off_delay_active = 0; //是否处于延时关机有效期
const U32_T u32_fan_off_delay_sec = (5U * 60U); // 5分钟
for ( u8_gunNo = 0; u8_gunNo < s_flow_data.u8_gunCnt; u8_gunNo++)
{
s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //获取充电实时信息
// printf("gun %d state %d\r\n",u8_gunNo,s_real_data->e_flow_real_state);
if(s_real_data->e_flow_real_state >= E_FLOW_REAL_CHARGEING &&
s_real_data->e_flow_real_state < E_FLOW_REAL_STOP_OK) //大于等于充电中且小于充电停止完成
{
u8_run_flag = 1;
break;
}
}
//printf("fan ctrl %d\r\n",u8_run_flag);
if(u8_run_flag) //风扇保持开启
{
u32_fan_off_start_sec = 0; //取消延时关机
u8_fan_off_delay_active = 0;
u8_prev_run_flag = 1;
u16_flow_put_ctrl(0,E_FLOW_CTRL_DATA_FAN_YK,CMD_ON,0);
}
else //不工作:从工作->不工作切换时延时5分钟关机
{
if(u8_prev_run_flag == 1 && u32_fan_off_start_sec == 0)
{
u32_fan_off_start_sec = get_current_seconds();
u8_fan_off_delay_active = 1;
}
if(u8_fan_off_delay_active &&
u32_safe_seconds_since(u32_fan_off_start_sec) < u32_fan_off_delay_sec)
{
// 延时未到:保持风扇开启
u16_flow_put_ctrl(0,E_FLOW_CTRL_DATA_FAN_YK,CMD_ON,0);
}
else
{
// 延时到或非延时场景:关机
u16_flow_put_ctrl(0,E_FLOW_CTRL_DATA_FAN_YK,CMD_OFF,0);
u32_fan_off_start_sec = 0;
u8_fan_off_delay_active = 0;
}
u8_prev_run_flag = 0;
}
}
#endif
#if 1 //模块交流脉冲上电控制
/**
* ************************************************************************
* @brief - 启动脉冲控制(带互斥机制,确保AC1和AC2不会同时闭合)
*
* @param[in] e_cmd - CMD_ON=AC1 CMD_OFF=AC2
*
* @author YZG
* @date 2026-05-03
* ************************************************************************
*/
static void v_yk_ctrl_pulse(E_CMD e_cmd)
{
U8_T u8_ac_ctrlNo;
u8_ac_ctrlNo = (e_cmd == CMD_ON) ? 1U : 2U;
if(u8_ac_ctrlNo != s_flow_data.u8_pulse_target_ac)
{
s_flow_data.e_pulse_state = E_PULSE_STATE_IDLE;
}
if(u8_ac_ctrlNo == s_flow_data.u8_pulse_target_ac &&
s_flow_data.e_pulse_state != E_PULSE_STATE_IDLE)
{
return;
}
u16_flow_put_ctrl(1,E_FLOW_CTRL_DATA_AC_YK , CMD_OFF ,0);
u16_flow_put_ctrl(1,E_FLOW_CTRL_DATA_AC_YK , CMD_OFF ,0);
s_flow_data.u8_pulse_target_ac = u8_ac_ctrlNo;
s_flow_data.u8_pulse_cycle_count = 0;
s_flow_data.e_pulse_state = E_PULSE_STATE_ON;
s_flow_data.u64_pulse_timer = u64_get_current_millis();
if(s_flow_data.u8_pulse_target_ac == 1U)
{
u16_flow_put_ctrl(1,E_FLOW_CTRL_DATA_AC_YK , CMD_ON ,0);
}
else
{
u16_flow_put_ctrl(2,E_FLOW_CTRL_DATA_AC_YK , CMD_ON ,0);
}
}
/**
* ************************************************************************
* @brief - 脉冲控制状态处理
*
*
*
* @author YZG
* @date 2026-05-03
* ************************************************************************
*/
static void v_yk_pulse_process(void)
{
switch(s_flow_data.e_pulse_state)
{
case E_PULSE_STATE_ON:
{
if(u64_safe_millis_since(s_flow_data.u64_pulse_timer) >= 200U)
{
if(s_flow_data.u8_pulse_target_ac == 1U)
{
u16_flow_put_ctrl(1,E_FLOW_CTRL_DATA_AC_YK , CMD_OFF ,0);
}
else
{
u16_flow_put_ctrl(2,E_FLOW_CTRL_DATA_AC_YK , CMD_OFF ,0);
}
s_flow_data.u64_pulse_timer = u64_get_current_millis();
s_flow_data.e_pulse_state = E_PULSE_STATE_OFF;
}
break;
}
case E_PULSE_STATE_OFF:
{
if(u64_safe_millis_since(s_flow_data.u64_pulse_timer) >= 2000U)
{
s_flow_data.u8_pulse_cycle_count++;
if(s_flow_data.u8_pulse_cycle_count >= 3U)
{
s_flow_data.e_pulse_state = E_PULSE_STATE_STOP;
}
else
{
if(s_flow_data.u8_pulse_target_ac == 1U)
{
u16_flow_put_ctrl(2,E_FLOW_CTRL_DATA_AC_YK , CMD_OFF ,0);
u16_flow_put_ctrl(1,E_FLOW_CTRL_DATA_AC_YK , CMD_ON ,0);
}
else
{
u16_flow_put_ctrl(1,E_FLOW_CTRL_DATA_AC_YK , CMD_OFF ,0);
u16_flow_put_ctrl(2,E_FLOW_CTRL_DATA_AC_YK , CMD_ON ,0);
}
s_flow_data.u64_pulse_timer = u64_get_current_millis();
s_flow_data.e_pulse_state = E_PULSE_STATE_ON;
}
}
break;
}
default:
break;
}
}
#endif
#if 1 //对外接口提供
/**********************************************************
* 函数名称: v_mdu_shw_control()
* 函数说明: 充电模块、开关模块控制函数
* 根据 充电模块控制命令 控制充电模块和开关模块
*
* 参数说明: u16_leep_time 执行周期 单位ms
* 输出说明: void
***********************************************************/
void v_mdu_shw_control(U16_T u16_leep_time)
{
v_mdu_shw_ctrl_bus_coupler(u16_leep_time);
}
/**
* ************************************************************************
* @brief - 风扇 交流接触器控制
*
* @param[in] u16_sleep - 线程任务睡眠周期值
*
*
* @author jiankalka
* @date 2025-09-05
* ************************************************************************
*/
void v_flow_ac_fan_ctrl(U16_T u16_sleep)
{
v_fan_ctrl(u16_sleep); //风扇控制
if(u8_flow_get_acky_action() == 1)
{
s_flow_data.u8_start_flag = 1; //模块任务运行
if(u16_flow_get_sys_data(0, E_FLOW_GET_DATA_MDU_RATED_POW, 0) == 80)
{
v_yk_ctrl_pulse(CMD_ON); //模块上电,控AC1脉冲
v_yk_pulse_process(); //脉冲控制状态处理
}
else
{
u16_flow_put_ctrl(1,E_FLOW_CTRL_DATA_AC_YK , CMD_ON ,0);
u16_flow_put_ctrl(2,E_FLOW_CTRL_DATA_AC_YK , CMD_ON ,0);
}
}
else
{
s_flow_data.u8_start_flag = 0; //模块任务停止
if(u16_flow_get_sys_data(0, E_FLOW_GET_DATA_MDU_RATED_POW, 0) == 80)
{
v_yk_ctrl_pulse(CMD_OFF); //模块下电,控AC2脉冲
v_yk_pulse_process(); //脉冲控制状态处理
}
else
{
u16_flow_put_ctrl(1,E_FLOW_CTRL_DATA_AC_YK , CMD_OFF ,0);
u16_flow_put_ctrl(2,E_FLOW_CTRL_DATA_AC_YK , CMD_OFF ,0);
}
}
}
#endif