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
+822
View File
@@ -0,0 +1,822 @@
#include "flowctrl/flow_interface.h"
#include "publicdata/publicdata.h"
#include "flowctrl/flowctrl_task.h"
#include "ui/ui_interface.h"
#include "collect_ctrl/yk_ctrl.h"
#include "collect_ctrl/collect_task.h"
#include "meter_calculate/meter_calculate_impl.h"
#include "bms/bms_interface.h"
#include "fault_cheak/fault_interface.h"
#include "flowctrl/insulation_ctrl.h"
#include "plat_comm/impl/bs_public_impl.h"
extern S_FLOW_DATA s_flow_data;
/**
* ************************************************************************
* @brief - 流程控制任务 获取外部数据接口
*
* @param[in] u8_gunNo - 枪号 0-N 对于不分区枪号的数据,无意义
* @param[in] e_dateType - 数据类型标志 详看枚举定义
* @param[in] u16_dataPara - 数据参数 不同数据类型,参数含义不同 对于不分区参数的数据,无意义
*
* @return U16_T - 数据返回值
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
U16_T u16_flow_get_sys_data(U8_T u8_gunNo,E_FLOW_GET_DATA_TYPE e_dateType,U16_T u16_dataPara)
{
U16_T u16_ret = 0;
switch (e_dateType)
{
case E_FLOW_GET_DATA_GUN_CNT: //枪数量
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u8_gunCnt;
break;
}
case E_FLOW_GET_DATA_GB_EN: //国标使能标志
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u_enable.bit_enable.bit_GBEnable;
break;
}
case E_FLOW_GET_DATA_GUN_FAN_EN: //枪风扇使能 0不使能 1使能
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u_enable.bit_enable.bit_gunFanEn;
break;
}
case E_FLOW_GET_DATA_GUNLOCK_EN: //枪锁使能 0不使能 1使能
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u_enable.bit_enable.bit_gunLockEna;
break;
}
case E_FLOW_GET_DATA_AUXPOWER_EN: //辅源状态监测使能 0不使能 1使能
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u_enable.bit_enable.bit_auxpower;
break;
}
case E_FLOW_GET_DATA_MDU_ZERO_POW_CTRL: //零功控制方式
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u_enable.bit_enable.bit_mduzeropowEn;
break;
}
case E_FLOW_GET_DATA_FAULT_FLAG: //获取故障内容存在标志 0不存在 1存在;需要传入 故障代码参数
{
u16_ret = u8_flow_cheak_fault_flag((E_FAULT_INFO)u16_dataPara, (E_FAULT_SITE)u8_gunNo);
break;
}
case E_FLOW_GET_DATA_GUN_TOW_CHR: //双枪同充标志 0单枪充电 1双枪充电且为主枪 2双枪充电且为辅枪
{
u16_ret = 0;
break;
}
case E_FLOW_GET_DATA_GUN_LINK: //枪连接状态 0未连接 1已连接
{
u16_ret = u8_get_gun_yx_data(YX_GUN_LINK,u8_gunNo);
break;
}
case E_FLOW_GET_DATA_GUN_LOCK: //枪锁状态 0未锁 1已锁
{
u16_ret = u8_get_gun_yx_data(YX_GUN_LOCK,u8_gunNo);
break;
}
case E_FLOW_GET_DATA_GUN_AUXPOWER: //辅源闭合状态 0未 1已
{
u16_ret = u8_get_gun_yx_data(YX_GUN_AUXPOWER,u8_gunNo);
break;
}
case E_FLOW_GET_DATA_KM_POS: //正母线直流输出接触器状态 0:断开; 1:闭合
{
u16_ret = u8_get_gun_yx_data(YX_GUN_DC_KM_POS,u8_gunNo);
break;
}
case E_FLOW_GET_DATA_KM_NEG: //负母线直流输出接触器状态 0:断开; 1:闭合
{
u16_ret = u8_get_gun_yx_data(YX_GUN_DC_KM_NEG,u8_gunNo);
break;
}
case E_FLOW_GET_DATA_XF_KM: //泄放接触器状态 0:断开; 1:闭合
{
u16_ret = u8_get_gun_yx_data(YX_GUN_RELIF,u8_gunNo);
break;
}
case E_FLOW_GET_DATA_BUS_KM: //母联接触器状态 0:断开; 1:闭合
{
u16_ret = u8_get_sys_yx_data(YX_PILE_BUS_KM);
break;
}
case E_FLOW_GET_DATA_DC_BUS_EN: //直流母联接触器使能 0 不使能 1使能
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u_enable.bit_enable.bit_dcBusEn;
break;
}
case E_FLOW_GET_DATA_GUN_BATT_ADC_VOL: //电池外侧采集电压 精度 0.1V
{
u16_ret = (U16_T)(f32_get_gun_yc_data(ADC_GUN_BAT,u8_gunNo)*10);
break;
}
case E_FLOW_GET_DATA_GUN_MAX_VOL: //充电枪最大数据电压值 精度 0.1V
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u16_max_volt;
break;
}
case E_FLOW_GET_DATA_GUN_MIN_VOL: //充电枪最小数据电压值 精度 0.1V
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u16_min_volt;
break;
}
case E_FLOW_GET_DATA_GUN_MAX_CUR: //充电枪最大数据电流值 精度 0.1V
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u16_max_cur;
break;
}
case E_FLOW_GET_DATA_GUN_MIN_CUR: //充电枪最小数据电流值 精度 0.1V
{
u16_ret = 50; //默认5A
break;
}
case E_FLOW_GET_DATA_GUN_SOC_LIMIT: //充电枪SOC阈值
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u8_soc_limit;
break;
}
case E_FLOW_GET_DATA_GUN_TRICKLE_LIMIT: //充电枪涓流充电停机阈值
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u16_trickle_limit;
break;
}
case E_FLOW_GET_DATA_GUN_BUS_VOL: //充电枪接触器内侧电压值 精度 0.1V
{
u16_ret = (U16_T)((f32_get_gun_yc_data(ADC_GUN_VOLT_PLUS,u8_gunNo) + f32_get_gun_yc_data(ADC_GUN_VOLT_MINUS,u8_gunNo))*10);
//printf("[%d]枪内侧adc %f,%f\n",u8_gunNo,f32_get_gun_yc_data(ADC_GUN_VOLT_PLUS,u8_gunNo) , f32_get_gun_yc_data(ADC_GUN_VOLT_MINUS,u8_gunNo));
break;
}
case E_FLOW_GET_DATA_GUN_FAULT_INFO: //获取整桩和该枪首个故障内容 0无故障 详见E_FAULT_INFO枚举内容 -整桩故障也代表本枪无法使用
{
if(u8_get_fault_sum(0,0) == 0 && u8_get_fault_sum(u8_gunNo+E_GUN,0) == 0) //整桩故障
u16_ret = 0;
else
{
REAL_FAULT_DATA_T rl_data;
v_get_fault_data(&rl_data); //获取故障信息
u16_ret = E_FAULT_13102; //控制器 未知停机故障
for (U8_T i = 0; i < CURR_FAULT_MAX_CNT; i++) //遍历所有故障位置
{
if(rl_data.fault_data[i].e_mag != 0 &&
(rl_data.fault_data[i].e_ingun == E_WHOLE_PILE ||
rl_data.fault_data[i].e_ingun == E_WHOLE_HOST ||
rl_data.fault_data[i].e_ingun == E_GUN+u8_gunNo))
{
u16_ret = rl_data.fault_data[i].e_mag;
}
}
}
break;
}
case E_FLOW_GET_DATA_GUN_POWER_LIMIT: //充电枪的限制功率值 单位kW 0表示不限制
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u8_gun_power_limit[u8_gunNo];
break;
}
case E_FLOW_GET_DATA_BS_VIN_RES: //VIN 鉴权结果 0wu 1成功 2平台鉴权超时 3非法VIN 4车辆识别鉴权帧超时 5即插即充鉴权失败 6鉴权VIN与车辆VIN不一致
{
u16_ret = u8_bs_get_txFlag_autoRwsult(u8_gunNo);
break;
}
case E_FLOW_GET_DATA_METER_VOL: //电表采集电压 精度0.1V
{
u16_ret = (U16_T)(u64_get_meter_data(u8_gunNo,0,E_METER_DATA_VOL)/1000);
break;
}
case E_FLOW_GET_DATA_METER_CUR: //电表采集电流 精度0.1V
{
u16_ret = (U16_T)(u64_get_meter_data(u8_gunNo,0,E_METER_DATA_CUR)/1000);
break;
}
case E_FLOW_GET_DATA_MDU_RATED_POW: //单模块额定功率 单位kw
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u8_mdu_rated_pow;
break;
}
case E_FLOW_GET_DATA_MDU_POWER: //模块额定功率 单位kw
{
u16_ret = g_t_share_data.t_sys_fix_cfg.u8_mdu_rated_pow;
break;
}
case E_FLOW_GET_DATA_PILE_TYPE: //获取桩类型 0一体一枪 1一体双枪 2分体一枪 3分体双枪
{
u16_ret = (U16_T)g_t_share_data.t_sys_fix_cfg.u8_pile_type;
break;
}
case E_FLOW_GET_DATA_MDU_WORK: //获取模块运行状态 0空闲 1工作
{
u16_ret = u16_mdu_put_data(u8_gunNo,E_MDU_PUT_DATA_GROUP_WORK_STATE);
break;
}
case E_FLOW_GET_DATA_MDU_PUT_VOL: //获取模块输出电压值 精度0.1V
{
u16_ret = u16_mdu_put_data(u8_gunNo,E_MDU_PUT_DATA_GROUP_putVol);
break;
}
case E_FLOW_GET_DATA_MDU_PUT_CUR: //获取模块输出电流值 精度0.1A
{
u16_ret = u16_mdu_put_data(u8_gunNo,E_MDU_PUT_DATA_GROUP_putCur);
break;
}
case E_FLOW_GET_DATA_MDU_IN_NUM: //获取模块分配数量
{
u16_ret = u16_mdu_put_data(u8_gunNo,E_MDU_PUT_DATA_GROUP_mduNum);
break;
}
case E_FLOW_GET_DATA_MDU_RUN_NUM: //获取模块运行数量
{
u16_ret = u16_mdu_put_data(u8_gunNo,E_MDU_PUT_DATA_GROUP_RUNING_mduNum);
break;
}
case E_FLOW_GET_DATA_BMS_GB_VER: //BMS 国标协议版本 0 2011版 1 2015版
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_GB_VER,0);
break;
}
case E_FLOW_GET_DATA_BMS_STATE: //BMS 获取BMS状态 0无 1握手完成 2握手失败 3开始预充 4开始充电 5禁止充电 6停止充电 7报文接收超时
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_STATE,0);
break;
}
case E_FLOW_GET_DATA_BMS_SOC: //BMS 获取车辆SOC
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_GUN_SOC,0);
break;
}
case E_FLOW_GET_DATA_BMS_MAX_VOL: //BMS 最大充电电压值 精度 0.1V
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_MAX_VOL,0);
break;
}
case E_FLOW_GET_DATA_BMS_MAX_CUR: //BMS 最大充电电流值 精度 0.1V
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_MAX_CUR,0);
break;
}
case E_FLOW_GET_DATA_BMS_REAL_BATT_VOL: //BMS 当前电池电压值 精度 0.1V
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_REAL_BATT_VOL,0);
break;
}
case E_FLOW_GET_DATA_BMS_NEED_VOL: //BMS 需求电压值 精度 0.1V
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_NEED_VOL,0);
break;
}
case E_FLOW_GET_DATA_BMS_NEED_CUR: //BMS 需求电流值 精度 0.1V
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_NEED_CUR,0);
break;
}
case E_FLOW_GET_DATA_BMS_CAN_SEND_CNT: //BMS 报文发送次数 参数值 0代表cem 1代表csd
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_CAN_SEND_CNT,u16_dataPara);
break;
}
case E_FLOW_GET_DATA_BMS_STOP_RES: //BMS 停止原因 详看E_FAULT_INFO枚举内容 BMS部分
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_STOP_RES,0);
break;
}
case E_FLOW_GET_DATA_BMS_RECONN_FLAG: //BMS 重连标志 0不重连 1重连
{
u16_ret = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_RECONN_FLAG,0);
break;
}
case E_FLOW_GET_DATA_GUN_STOP_REASON_0: //枪停止原因 e_stop_reason[0]
{
if (u8_gunNo < GUN_MAX_CNT)
u16_ret = (U16_T)s_flow_data.s_real_data[u8_gunNo].e_stop_reason[0];
break;
}
case E_FLOW_GET_DATA_METER_CHARGE: //充电金额 u16_dataPara: 0已充合计低16 1高16 2下周期预估低16 3高16 单位0.0001元
{
U32_T u32v;
if (u8_gunNo >= GUN_MAX_CNT)
break;
if (u16_dataPara == 0 || u16_dataPara == 1)
{
u32v = u32_meterlog_put_data(u8_gunNo, E_METERLOG_PUT_LOG_INFO_USED_MONEY, NULL, 0)
+ u32_meterlog_put_data(u8_gunNo, E_METERLOG_PUT_LOG_INFO_USED_SERVICE, NULL, 0);
u16_ret = (u16_dataPara == 0) ? (U16_T)(u32v & 0xFFFFu) : (U16_T)((u32v >> 16) & 0xFFFFu);
}
else if (u16_dataPara == 2 || u16_dataPara == 3)
{
u32v = u32_meterlog_next_cycle_money(u8_gunNo);
u16_ret = (u16_dataPara == 2) ? (U16_T)(u32v & 0xFFFFu) : (U16_T)((u32v >> 16) & 0xFFFFu);
}
break;
}
case E_FLOW_GET_DATA_FLOW_STATE:
{
if (u8_gunNo < GUN_MAX_CNT)
u16_ret = (U16_T)s_flow_data.s_real_data[u8_gunNo].e_flow_state;
break;
}
case E_FLOW_GET_DATA_CHAR_TIME:
{
if (u8_gunNo < GUN_MAX_CNT)
u16_ret = s_flow_data.s_log_data[u8_gunNo].u16_char_time;
break;
}
default:
break;
}
return u16_ret;
}
/**
* ************************************************************************
* @brief - 流程控制任务 对外输出数据
*
* @param[in] u8_gunNo - 枪号 0-N 对于不分区枪号的数据,无意义
* @param[in] e_dateType - 数据类型标志 详看枚举定义
* @param[in] u16_dataPara - 数据参数 不同数据类型,参数含义不同 对于不分区参数的数据,无意义
*
* @return U16_T - 数据返回值
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
U16_T u16_flow_put_data(U8_T u8_gunNo,E_FLOW_PUT_DATA_TYPE e_dateType,U16_T u16_dataPara)
{
U16_T u16_ret = 0;
switch (e_dateType)
{
case E_FLOW_PUT_DATA_GUN_REAL_STATE : //对外状态 0空闲 1充电启动 2绝缘启动 3绝缘计算完成 4绝缘检测模块停止 5开始预充 6预充完成 7充电中 8BMS通讯超时 9充电停止 10充电停止完成
u16_ret = s_flow_data.s_real_data[u8_gunNo].e_flow_real_state;
break;
case E_FLOW_PUT_DATA_GUN_RECONN_FLAG: //输出bms重连开始标志 参数:0获取 1清空
if(u16_dataPara == 0)
u16_ret = s_flow_data.s_real_data[u8_gunNo].u8_bms_renew_ctrl;
else
s_flow_data.s_real_data[u8_gunNo].u8_bms_renew_ctrl = 0;
break;
case E_FLOW_PUT_DATA_GUN_NEED_VOL: //BMS 需求电压值 精度 0.1V
{
u16_ret = s_flow_data.s_real_data[u8_gunNo].u16_need_vol;
break;
}
case E_FLOW_PUT_DATA_GUN_NEED_CUR: //BMS 需求电流值 精度 0.1A
{
u16_ret = s_flow_data.s_real_data[u8_gunNo].u16_need_cur;
break;
}
case E_FLOW_PUT_DATA_GUN_START_TIME: //充电开始时间 时间戳
{
u16_ret = s_flow_data.s_log_data[u8_gunNo].u32_satrt_time;
break;
}
case E_FLOW_PUT_DATA_GUN_STOP_TIME: //充电停止时间 时间戳
{
u16_ret = s_flow_data.s_log_data[u8_gunNo].u32_stop_time;
break;
}
case E_FLOW_PUT_DATA_GUN_STOP_RES: //充电停止原因 详看枚举
{
u16_ret = s_flow_data.s_log_data[u8_gunNo].u_stop_res;
break;
}
case E_FLOW_PUT_DATA_USED_ENERGY: //以充电量,精度 0.0001kWh
{
u16_ret = (U16_T)s_flow_data.s_log_data[u8_gunNo].u32_used_energy;
break;
}
case E_FLOW_PUT_DATA_MDU_STAR_FLAG: //模块任务 开始标志
{
u16_ret = (U16_T)s_flow_data.u8_start_flag;
break;
}
case E_FLOW_PUT_DATA_MDU_YK_CMD: //模块遥控命令 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
{
u16_ret = (U16_T)s_flow_data.s_mdu_allocate_ctrl[u8_gunNo].u8_yk_cmd;
break;
}
case E_FLOW_PUT_DATA_MDU_NEED_VOL: //模块需求电压值 精度0.1
{
u16_ret = (U16_T)s_flow_data.s_mdu_allocate_ctrl[u8_gunNo].u16_need_vol;
break;
}
case E_FLOW_PUT_DATA_MDU_ONE_NEED_CUR: //单模块需求电流值 精度0.1
{
u16_ret = (U16_T)s_flow_data.s_mdu_allocate_ctrl[u8_gunNo].u16_one_mdu_need_cur;
break;
}
default:
break;
}
return u16_ret;
}
/**
* ************************************************************************
* @brief - 流程控制任务 对外输出无符号整型数据
*
* @param[in] u8_gunNo -枪号
* @param[in] e_dateType -数据类型标志 详看枚举定义
*
* @return U32_T -数据返回值
*
* @author YZG
* @date 2025-09-29
* ************************************************************************
*/
U32_T u32_flow_put_data(U8_T u8_gunNo,E_FLOW_PUT_DATA_TYPE e_dateType)
{
U32_T u32_ret = 0;
switch (e_dateType)
{
case E_FLOW_PUT_DATA_USED_ENERGY: //以充电量,精度 0.0001kWh
{
u32_ret = s_flow_data.s_log_data[u8_gunNo].u32_used_energy;
break;
}
case E_FLOW_PUT_DATA_USED_MONEY: //以充电费,精度 0.0001元
{
u32_ret = s_flow_data.s_log_data[u8_gunNo].u32_used_money;
break;
}
case E_FLOW_PUT_DATA_USED_SERV_MONEY: //已充服务费,精度 0.0001元
{
u32_ret = s_flow_data.s_log_data[u8_gunNo].u32_used_service_money;
break;
}
default:
break;
}
return u32_ret;
}
/**
* ************************************************************************
* @brief - 流程控制任务 对外控制 -例如枪锁控制 风扇控制等
*
* @param[in] u8_gunNo - 枪号 0-N 对于不分区枪号的数据,无意义
* @param[in] e_dateType - 数据类型标志 详看枚举定义
* @param[in] u16_dataPara1 -数据参数1 不同数据类型,参数含义不同 对于不分区参数的数据,无意义
* @param[in] u16_dataPara2 -数据参数2 不同数据类型,参数含义不同 对于不分区参数的数据,无意义
*
* @return U16_T - 0 执行成功 1执行失败
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
U16_T u16_flow_put_ctrl(U8_T u8_gunNo,E_FLOW_CTRL_DATA_TYPE e_dateType,U16_T u16_dataPara1,U16_T u16_dataPara2)
{
U16_T u16_ret = 0;
(void)u16_dataPara2;
switch (e_dateType)
{
case E_FLOW_CTRL_DATA_GUN_LOCK : //枪锁控制 0解锁 1锁枪
{
if(u8_gunNo == 0)
v_yk_ctrl_impl(E_KY_TYPE_GUN_LOCK1 , (E_CMD) u16_dataPara1);
else
v_yk_ctrl_impl(E_KY_TYPE_GUN_LOCK2 , (E_CMD) u16_dataPara1);
break;
}
case E_FLOW_CTRL_DATA_AUXPOWER : //辅源控制 0断开 1闭合
{
if(u8_gunNo == 0)
v_yk_ctrl_impl(E_KY_TYPE_AUX_POWER1 , (E_CMD) u16_dataPara1);
else
v_yk_ctrl_impl(E_KY_TYPE_AUX_POWER2 , (E_CMD) u16_dataPara1);
break;
}
case E_FLOW_CTRL_DATA_K1K2 : //K1K2控制 0断开 1闭合
{
if(u8_gunNo == 0)
v_yk_ctrl_impl(E_KY_TYPE_DC_CONT1 , (E_CMD) u16_dataPara1);
else
v_yk_ctrl_impl(E_KY_TYPE_DC_CONT2 , (E_CMD) u16_dataPara1);
break;
}
case E_FLOW_CTRL_DATA_AC_YK : //交流接触器控制 0断开 1闭合
{
if(u8_gunNo == 1)
v_yk_ctrl_impl(E_KY_TYPE_AC1 , (E_CMD) u16_dataPara1);
else
v_yk_ctrl_impl(E_KY_TYPE_AC2 , (E_CMD) u16_dataPara1);
break;
}
case E_FLOW_CTRL_DATA_BUS_YK : //母联接触器控制 0断开 1闭合
{
v_yk_ctrl_impl(E_KY_TYPE_DC_CONT_BUS , (E_CMD) u16_dataPara1);
break;
}
case E_FLOW_CTRL_DATA_FAN_YK: //风扇
{
v_yk_ctrl_impl(E_KY_TYPE_FAN_CONT , (E_CMD) u16_dataPara1);
break;
}
default:
break;
}
return u16_ret;
}
/**
* ************************************************************************
* @brief - 获取 故障是否存在在列表中
*
* @param[in] e_info - 告警数据
* @param[in] f_site - 故障位置
*
* @return U8_T - 0 未存在 1存在为故障 2存在为告警
*
* @author jiankalka
* @date 2025-09-09
* ************************************************************************
*/
U8_T u8_flow_cheak_fault_flag(E_FAULT_INFO e_info , E_FAULT_SITE f_site)
{
U8_T u8_ret;
if(f_site > 0)
{
f_site += E_GUN; //故障存储枪地址从100开始
}
u8_ret = u8_cheak_fault_flag(e_info,f_site);
return u8_ret;
}
/**
* ************************************************************************
* @brief - 流程控制任务 触发故障告警
*
* @param[in] f_site - 故障位置 0整桩 1A枪 2B枪
* @param[in] e_type - 动作类型 0回复 1故障 2告警
* @param[in] e_info - 故障名称 详看故障枚举
* @param[in] u8_action_type - 拔枪恢复标志 0拔枪不恢复 1拔枪恢复
* @param[in] s16_data1 - 故障参数1 自定义
* @param[in] s16_data2 - 故障参数2 自定义
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
void v_flow_set_fault_data(E_FAULT_SITE f_site ,E_FAULT_TYPE e_type , E_FAULT_INFO e_info, U8_T u8_action_type, S16_T s16_data1 , S16_T s16_data2)
{
if(f_site > 0)
{
f_site = (E_FAULT_SITE)(f_site - 1);
f_site += E_GUN; //故障存储枪地址从1000开始
}
v_set_fault_data(f_site,e_type,e_info,u8_action_type,s16_data1,s16_data2);
}
/**
* ************************************************************************
* @brief - 流程控制任务 获取故障代码内容 中文
*
* @param[in] e_info - 故障代码
* @param[in] mag - 故障代码对应中文字符
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
void v_flow_get_fault_mag(E_FAULT_INFO e_info , char *mag,U16_T u16_len)
{
v_get_fault_info(e_info,mag,u16_len);
}
/**
* ************************************************************************
* @brief - 绝缘监测执行函数
*
* @param[in] u8_gunNo - 枪号
* @param[in] u32_insul_Rx - 绝缘监测电阻值 DC正对地
* @param[in] u32_insul_Ry - 绝缘监测电阻值 DC负对地
*
* @return S8_T - -1 未完成 0失败 1成功 2成功但告警
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
S8_T s8_flow_gun_insulation(U8_T u8_gunNo,U32_T *u32_insul_Rx,U32_T *u32_insul_Ry)
{
S8_T s8_ret = -1;
F32_T f32_rz, f32_rf;
s8_ret = s8_insulation_action(u8_gunNo ,&f32_rz, &f32_rf);
*u32_insul_Rx = (U32_T)f32_rz;
*u32_insul_Ry = (U32_T)f32_rf;
// printf("flow 绝缘检查结果= %d %d\n",s8_ret,u16_data );
return s8_ret;
}
/**
* ************************************************************************
* @brief - 绝缘监测资源控制
*
* @param[in] u8_gunNo - 枪号 0-N
* @param[in] u8_ctrlType - 控制类型 0绝缘监测资源初始化-绝缘监测开始前调用 1绝缘监测资源释放-绝缘监测结束后调用
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
void v_flow_gun_insulation_data_ctrl(U8_T u8_gunNo,U8_T u8_ctrlType)
{
if(u8_ctrlType == 1)
v_insulation_stop( u8_gunNo); //设置绝缘检测停止
// printf("flow 绝缘启停= %d %d\n",u8_gunNo,u8_ctrlType );
}
/**
* ************************************************************************
* @brief - 电压泄放执行
*
* @param[in] u8_gunNo - 枪号 0-N
*
* @return S8_T - 泄放执行结果 -1未完成 0泄放失败 1完成且泄放成功
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
S8_T s8_flow_volt_relief_do(U8_T u8_gunNo)
{
S8_T s8_ret = 1;
return s8_ret;
}
/**
* ************************************************************************
* @brief - 泄放控制资源操作
*
* @param[in] u8_gunNo - 枪号 0-N
* @param[in] u8_ctrlType - 控制类型 0泄放控制资源初始化-泄放开始前调用 1泄放控制资源释放-泄放控制结束后调用
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
void v_flow_gun_volt_relief_free(U8_T u8_gunNo ,U8_T u8_ctrlType)
{
}
/**
* ************************************************************************
* @brief - 设置启停命令
*
* @param[in] u8_gunNo - 抢号 0-N
* @param[in] s_charge_ctrl_info - 充电启停控制信息
*
*
* @author jiankalka
* @date 2025-09-08
* ************************************************************************
*/
void v_flow_start_stop_ctrl(U8_T u8_gunNo , S_FLOW_CHARGE_CTRL_INFO *s_charge_ctrl_info )
{
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo];
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
if(s_charge_ctrl_info->e_cmd == CMD_OFF) //停止充电
{
s_ctrl_data->e_stop_flag = s_charge_ctrl_info->e_stop_res;
s_ctrl_data->s16_fault_stop_cnt = TIMER_NONE; //默认调用此接口停止充电的操作 都是正常停止(异常停止情况在本任务其他地方判断)
FLOWCTRL_LOG("Stop cmd, reason=%d\n",s_ctrl_data->e_stop_flag);
}
else //开始充电
{
if(s_real_data->e_flow_state != E_FLOW_FREE) //不是空闲 直接停止
{
return;
}
memset(s_ctrl_data, 0 , sizeof(S_FLOW_CTRL_DATA)); //清空控制信息
// 防止 s_over_time 初值为0导致首次判定直接超时
{
U32_T now_s = get_current_seconds();
s_ctrl_data->s_over_time.u32_trickle_limit_time = now_s;
s_ctrl_data->s_over_time.u32_dc_km_time = now_s;
s_ctrl_data->s_over_time.u32_mdu_free_time = now_s;
s_ctrl_data->s_over_time.u32_over_vol_time = now_s;
s_ctrl_data->s_over_time.u32_under_vol_time = now_s;
s_ctrl_data->s_over_time.u32_over_curr_time = now_s;
s_ctrl_data->s_over_time.u32_over_needCur_time = now_s;
s_ctrl_data->s_over_time.u32_over_needCur_max_time = now_s;
s_ctrl_data->s_over_time.u32_over_max_vol_time = now_s;
}
s_ctrl_data->s16_fault_stop_cnt = TIMER_NONE;
s_ctrl_data->e_start_flag = s_charge_ctrl_info->e_start_res; //启动原因
s_ctrl_data->e_sdk_chargMode = s_charge_ctrl_info->e_sdk_chargMode;
s_ctrl_data->u32_limit_data = s_charge_ctrl_info->u32_limit_data;
FLOWCTRL_LOG("Start cmd, reason=%d\n",s_ctrl_data->e_start_flag);
}
}
/**
* ************************************************************************
* @brief - 设置充电订单结算信息
*
* @param[in] u8_gunNo - 抢号0-N
* @param[in] u16_res - 结果
*
*
* @author jiankalka
* @date 2025-09-24
* ************************************************************************
*/
void v_flow_set_stop_log_info(U8_T u8_gunNo , U16_T u16_res)
{
//v_pcu_set_gun_char_flag(u8_gunNo,0 ,u16_res);
v_meterlog_set_stop_char_log_info(u8_gunNo, (E_FAULT_INFO)u16_res);
}
/**
* ************************************************************************
* @brief - 设置平台充电鉴权标志
*
* @param[in] u8_gunNo - 0-N
*
*
* @author jiankalka
* @date 2025-12-04
* ************************************************************************
*/
void v_flow_set_plat_vin_up(U8_T u8_gunNo)
{
v_bs_log_txFlag_autoStart(u8_gunNo); //设置充电鉴权上送标志
}
/**
* ************************************************************************
* @brief -充电中,更新充电订单中的充电电量与充电金额
*
* @param[in] u8_gunNo -充电枪号
*
*
* @author YZG
* @date 2025-09-29
* ************************************************************************
*/
void v_flow_log_info_updata(U8_T u8_gunNo)
{
S_FLOW_LOG_DATA *s_flow_log = &s_flow_data.s_log_data[u8_gunNo];
s_flow_log->u32_used_energy = u32_meterlog_put_data(u8_gunNo,E_METERLOG_PUT_LOG_INFO_USED_ENERGY,NULL,0); //获取充电电量
s_flow_log->u32_used_money = u32_meterlog_put_data(u8_gunNo,E_METERLOG_PUT_LOG_INFO_USED_MONEY,NULL,0);//获取充电金额
s_flow_log->u32_used_service_money = u32_meterlog_put_data(u8_gunNo,E_METERLOG_PUT_LOG_INFO_USED_SERVICE,NULL,0); //充电服务金额
s_flow_log->u16_char_time = u32_meterlog_put_data(u8_gunNo,E_METERLOG_PUT_LOG_INFO_CHAR_TIME,NULL,0); //获取充电时间
}
/**
* ************************************************************************
* @brief -设置充电枪流程控制状态初始化
*
* @param[in] u8_gunNo -
*
*
* @author jiankalka
* @date 2026-03-03
* ************************************************************************
*/
void v_flow_set_gun_flow_real_state_init(U8_T u8_gunNo)
{
s_flow_data.s_real_data[u8_gunNo].e_flow_real_state = E_FLOW_REAL_FREE;
}
void v_flow_request_ui_idle_recover(void)
{
v_ui_request_idle_screen_recover();
}
+177
View File
@@ -0,0 +1,177 @@
#ifndef FLOW_INTERFACE_H
#define FLOW_INTERFACE_H
#ifdef __cplusplus /*C++编译环境下兼容C语言*/
extern "C" {
#endif
/*------ Exported includes(头文件) ----------------------*/
#include "main.h"
#include "fault_cheak/fault_interface.h"
#include "meter_calculate/meter_calculate_impl.h"
/*------ Exported macro(宏定义) -------------------------*/
/*------ Exported struct(结构体定义) --------------------*/
typedef enum //充电流程控制对外状态
{
E_FLOW_REAL_FREE=0 , //空闲
E_FLOW_REAL_CHARGE_START , //充电启动
E_FLOW_REAL_INSUL_START , //绝缘启动
E_FLOW_REAL_INSUL_OK , //绝缘计算完成
E_FLOW_REAL_INSUL_MDU_STOP , //绝缘检测模块停止
E_FLOW_REAL_PRE_START , //开始预充
E_FLOW_REAL_PRE_OK , //预充完成
E_FLOW_REAL_CHARGEING , //充电中
E_FLOW_REAL_BMS_OUTTIME , //BMS通讯超时
E_FLOW_REAL_STOP , //充电停止
E_FLOW_REAL_STOP_OK , //充电停止完成
}E_FLOW_REAL_STATE;
typedef enum
{
E_FLOW_GET_DATA_GUN_CNT = 0, //枪数量
E_FLOW_GET_DATA_GB_EN, //国标使能标志 0不使能 1使用
E_FLOW_GET_DATA_GUN_FAN_EN, //枪风扇使能 0不使能 1使能
E_FLOW_GET_DATA_GUNLOCK_EN, //枪锁使能 0不使能 1使能
E_FLOW_GET_DATA_AUXPOWER_EN, //辅源状态监测使能 0不使能 1使能
E_FLOW_GET_DATA_FAULT_FLAG, //获取故障内容存在标志 0不存在 1存在;需要传入 故障代码参数
E_FLOW_GET_DATA_GUN_TOW_CHR, //双枪同充标志 0单枪充电 1双枪充电且为主枪 2双枪充电且为辅枪
E_FLOW_GET_DATA_GUN_LINK, //枪连接状态 0未连接 1已连接
E_FLOW_GET_DATA_GUN_LOCK, //枪锁状态 0未锁 1已锁
E_FLOW_GET_DATA_GUN_AUXPOWER, //辅源闭合状态 0未 1已
E_FLOW_GET_DATA_KM_POS, //正母线直流输出接触器状态 0:断开; 1:闭合
E_FLOW_GET_DATA_KM_NEG, //负母线直流输出接触器状态 0:断开; 1:闭合
E_FLOW_GET_DATA_XF_KM, //泄放接触器状态 0:断开; 1:闭合
E_FLOW_GET_DATA_BUS_KM, //母联接触器状态 0:断开; 1:闭合
E_FLOW_GET_DATA_DC_BUS_EN, //直流母联接触器使能 0 不使能 1使能
E_FLOW_GET_DATA_GUN_BATT_ADC_VOL, //电池外侧采集电压 精度 0.1V
E_FLOW_GET_DATA_GUN_MAX_VOL, //充电枪最大数据电压值 精度 0.1V
E_FLOW_GET_DATA_GUN_MIN_VOL, //充电枪最小数据电压值 精度 0.1V
E_FLOW_GET_DATA_GUN_MAX_CUR, //充电枪最大数据电流值 精度 0.1A
E_FLOW_GET_DATA_GUN_MIN_CUR, //充电枪最小数据电流值 精度 0.1A
E_FLOW_GET_DATA_GUN_SOC_LIMIT, //充电枪SOC阈值
E_FLOW_GET_DATA_GUN_TRICKLE_LIMIT, //充电枪涓流充电停机阈值
E_FLOW_GET_DATA_GUN_BUS_VOL, //充电枪接触器内侧电压值 精度 0.1V
E_FLOW_GET_DATA_GUN_FAULT_INFO, //获取整桩和该枪首个故障内容 0无故障 详见E_FAULT_INFO枚举内容 -整桩故障也代表本枪无法使用
E_FLOW_GET_DATA_GUN_POWER_LIMIT, //充电枪的限制功率值 单位kW 0表示不限制
E_FLOW_GET_DATA_METER_VOL, //电表采集电压 精度0.1V
E_FLOW_GET_DATA_METER_CUR, //电表采集电流 精度0.1V
E_FLOW_GET_DATA_BS_VIN_RES, //VIN 鉴权结果 0wu 1成功 2平台鉴权超时 3非法VIN 4车辆识别鉴权帧超时 5即插即充鉴权失败 6鉴权VIN与车辆VIN不一致
E_FLOW_GET_DATA_MDU_RATED_POW, //单模块额定功率 单位kw
E_FLOW_GET_DATA_MDU_POWER, //模块额定功率 单位kw(与 MDU_RATED_POW 同源)
E_FLOW_GET_DATA_MDU_ZERO_POW_CTRL, //零功控制方式 0普通控制 1脉冲控制
E_FLOW_GET_DATA_PILE_TYPE, //获取桩类型 0一体一枪 1一体双枪 2分体一枪 3分体双枪
E_FLOW_GET_DATA_MDU_WORK, //获取模块运行状态 0空闲 1工作
E_FLOW_GET_DATA_MDU_PUT_VOL, //获取模块输出电压值 精度0.1V
E_FLOW_GET_DATA_MDU_PUT_CUR, //获取模块输出电流值 精度0.1A
E_FLOW_GET_DATA_MDU_IN_NUM, //获取模块分配数量
E_FLOW_GET_DATA_MDU_RUN_NUM, //获取模块运行数量
E_FLOW_GET_DATA_BMS_GB_VER, //BMS 国标协议版本 0 2011版 1 2015版
E_FLOW_GET_DATA_BMS_STATE, //BMS 获取BMS状态 0无 1握手完成 2握手失败 3开始预充 4开始充电 5禁止充电 6停止充电 7报文接收超时
E_FLOW_GET_DATA_BMS_SOC, //BMS 获取车辆SOC
E_FLOW_GET_DATA_BMS_MAX_VOL, //BMS 最大充电电压值 精度 0.1V
E_FLOW_GET_DATA_BMS_MAX_CUR, //BMS 最大充电电流值 精度 0.1A
E_FLOW_GET_DATA_BMS_REAL_BATT_VOL, //BMS 当前电池电压值 精度 0.1V
E_FLOW_GET_DATA_BMS_NEED_VOL, //BMS 需求电压值 精度 0.1V
E_FLOW_GET_DATA_BMS_NEED_CUR, //BMS 需求电流值 精度 0.1A
E_FLOW_GET_DATA_BMS_CAN_SEND_CNT, //BMS 报文发送次数 参数值 0代表cem 1代表csd
E_FLOW_GET_DATA_BMS_STOP_RES, //BMS 停止原因 详看E_FAULT_INFO枚举内容 BMS部分
E_FLOW_GET_DATA_BMS_RECONN_FLAG, //BMS 重连标志 0不重连 1重连
/** 充电金额(计量订单),u16_dataPara:0已充(电费+服务费)低16位 1同左高16位 2下周期预估低16位 3同左高16位;单位0.0001元;内部 u32_meterlog_put_data / u32_meterlog_next_cycle_money */
E_FLOW_GET_DATA_METER_CHARGE,
E_FLOW_GET_DATA_FLOW_STATE, //本枪流程状态 E_FLOW_STATE(与 s_real_data.e_flow_state 一致)
E_FLOW_GET_DATA_GUN_STOP_REASON_0, //枪停止原因 e_stop_reason[0]
E_FLOW_GET_DATA_CHAR_TIME, //本枪充电持续时间 秒(s_log_data.u16_char_time
}E_FLOW_GET_DATA_TYPE;
typedef enum
{
E_FLOW_PUT_DATA_GUN_REAL_STATE =0, //对外状态 0空闲 1充电启动 2绝缘启动 3绝缘计算完成 4绝缘检测模块停止 5开始预充 6预充完成 7充电中 8BMS通讯超时 9充电停止 10充电停止完成
E_FLOW_PUT_DATA_GUN_RECONN_FLAG, //输出bms重连开始标志 参数:0获取 1清空
E_FLOW_PUT_DATA_GUN_NEED_VOL, //BMS 需求电压值 精度 0.1V
E_FLOW_PUT_DATA_GUN_NEED_CUR, //BMS 需求电流值 精度 0.1A
E_FLOW_PUT_DATA_GUN_START_TIME, //充电开始时间 时间戳
E_FLOW_PUT_DATA_GUN_STOP_TIME, //充电停止时间 时间戳
E_FLOW_PUT_DATA_GUN_STOP_RES, //充电停止原因 详看枚举
E_FLOW_PUT_DATA_USED_ENERGY, //以充电量,精度0.0001kWh
E_FLOW_PUT_DATA_USED_MONEY, //以充金额,精度0.0001元
E_FLOW_PUT_DATA_USED_SERV_MONEY, //以充服务金额,精度0.0001元
E_FLOW_PUT_DATA_MDU_STAR_FLAG, //模块运行开始标志 0未开始 1开始
E_FLOW_PUT_DATA_MDU_YK_CMD, //模块遥控命令 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
E_FLOW_PUT_DATA_MDU_NEED_VOL, //模块需求电压值 精度0.1
E_FLOW_PUT_DATA_MDU_ONE_NEED_CUR, //单模块需求电流值 精度0.1
}E_FLOW_PUT_DATA_TYPE;
typedef enum
{
E_FLOW_CTRL_DATA_GUN_LOCK =0, //枪锁控制 0解锁 1锁枪
E_FLOW_CTRL_DATA_AUXPOWER , //辅源控制 0断开 1闭合
E_FLOW_CTRL_DATA_K1K2 , //K1K2控制 0断开 1闭合
E_FLOW_CTRL_DATA_AC_YK , //交流接触器控制 0断开 1闭合
E_FLOW_CTRL_DATA_BUS_YK , //母联接触器控制 0断开 1闭合
E_FLOW_CTRL_DATA_FAN_YK, //风扇
E_FLOW_CTRL_DATA_GUN_FAN_YK, //枪风扇
}E_FLOW_CTRL_DATA_TYPE;
typedef enum //充电模式
{
E_SDK_CHGMOD_NONE = 0, //不做限制的充电(默认)
E_SDK_CHGMOD_MONEY, //限制金额
E_SDK_CHGMOD_ELE, //限制电量 electricity
E_SDK_CHGMOD_SOC, //限制SOC
E_SDK_CHGMOD_TIME, //限制充电时长
E_SDK_CHGMOD_PWOER, //限制功率
}E_CHRG_LIMIT_MOD;
typedef struct
{
E_CMD e_cmd; //充电启停标志 CMD_ON 启动 CMD_OFF停止
START_REASON e_start_res; //启动原因
E_FAULT_INFO e_stop_res; //停止原因
E_CHRG_LIMIT_MOD e_sdk_chargMode; //充电限制方式
U32_T u32_limit_data; //限制参数:金额模式为0.01元;电量0.1kWh等见流程使用处
}S_FLOW_CHARGE_CTRL_INFO;
/*------ Exported variables(变量定义) -------------------*/
/*------ Exported function prototypes (函数声明) -------*/
U16_T u16_flow_get_sys_data(U8_T u8_gunNo,E_FLOW_GET_DATA_TYPE e_dateType,U16_T u16_dataPara);
U16_T u16_flow_put_data(U8_T u8_gunNo,E_FLOW_PUT_DATA_TYPE e_dateType,U16_T u16_dataPara);
U16_T u16_flow_put_ctrl(U8_T u8_gunNo,E_FLOW_CTRL_DATA_TYPE e_dateType,U16_T u16_dataPara1,U16_T u16_dataPara2);
U32_T u32_flow_put_data(U8_T u8_gunNo,E_FLOW_PUT_DATA_TYPE e_dateType);
void v_flow_set_fault_data(E_FAULT_SITE f_site ,E_FAULT_TYPE e_type , E_FAULT_INFO e_info, U8_T u8_action_type, S16_T s16_data1 , S16_T s16_data2);
U8_T u8_flow_cheak_fault_flag(E_FAULT_INFO e_info , E_FAULT_SITE f_site);
void v_flow_get_fault_mag(E_FAULT_INFO e_info , char *mag,U16_T u16_len);
S8_T s8_flow_gun_insulation(U8_T u8_gunNo,U32_T *u32_insul_Rx,U32_T *u32_insul_Ry);
void v_flow_gun_insulation_data_ctrl(U8_T u8_gunNo,U8_T u8_ctrlType);
S8_T s8_flow_volt_relief_do(U8_T u8_gunNo);
void v_flow_gun_volt_relief_free(U8_T u8_gunNo ,U8_T u8_ctrlType);
void v_flow_set_stop_log_info(U8_T u8_gunNo , U16_T u16_res);
void v_flow_start_stop_ctrl(U8_T u8_gunNo , S_FLOW_CHARGE_CTRL_INFO *s_charge_ctrl_info );
void v_flow_set_plat_vin_up(U8_T u8_gunNo);
void v_flow_log_info_updata(U8_T u8_gunNo);
void v_flow_set_gun_flow_real_state_init(U8_T u8_gunNo);
/** 空闲态在线鉴权失败/超时等:请求界面回到待机(封装 UI 接口,供流程任务调用) */
void v_flow_request_ui_idle_recover(void);
#ifdef __cplusplus
}
#endif
#endif /* FLOW_INTERFACE_H */
File diff suppressed because it is too large Load Diff
+193
View File
@@ -0,0 +1,193 @@
#ifndef FLOWCTRL_TASK_H
#define FLOWCTRL_TASK_H
#ifdef __cplusplus /*C++编译环境下兼容C语言*/
extern "C" {
#endif
#include "main.h"
#include "flowctrl/flow_interface.h"
#include "flowctrl/mdu_swh_ctrl.h"
#include "mylog/mylog.h"
#define FLOWCTRL_LOG(fmt, ...) MYLOG_MSG(TASK_ID_FlowCtrl, (fmt), ##__VA_ARGS__)
#define TIMER_NONE -1 //正常动作
#define TIMER_SPECIAL_2 -2 //状态未恢复 依旧响应结束充电命令
#define TIMER_0ms NUM_0 //计时0ms
#define TIMER_20ms NUM_20 //计时20ms
#define TIMER_100ms NUM_100 //计时100ms
#define TIMER_1s NUM_1000 //计时1s
#define TIMER_10s (NUM_1000 * NUM_10) //计时30s
#define TIMER_30s (NUM_1000 * NUM_30) //计时30s
#define FLOW_TIMEOUT_GUNLOCK 15 //枪锁辅源检查超时时间5秒
#define FLOW_TIMEOUT_PCM_STATE 15 //从发送01快速启机/02停止充电,PCM状态切换
#define FLOW_TIMEOUT_VOLT 10 //接触器内测电压在绝缘检测电压/电池电压(设置电压值)-(1~10V)范围内
#define FLOW_TIMEOUT_INSULATION 30 //绝缘检测30s 27930
#define FLOW_TIMEOUT_PRECHARGE (60+5) //预充60s 自发送BRO-0xAA起60未收到CRO-0xAA 27930 模块输出电压调整15s
#define FLOW_TIMEOUT_CHANGE_STOPTIME (60*10+1) //充电暂停 10分钟 测试快了500ms 加一
/*------ Exported struct(结构体定义) --------------------*/
//充电详细过程枚举
typedef enum
{
e_free = 0 , // 0 正常
e_gunLink , // 1 枪连接检查
e_gunlock , // 2 枪锁动作
e_auxpower , // 3 辅源动作
e_wiat_bms_hand , // 4 获取bms握手完成标志
e_check_bms_vol , // 5 检查bms最大允许充电电压
e_battvol_check , // 6 绝缘前电池测电压检查
e_insulmdu_check, // 7 绝缘检测模块启动
e_insulvol_check, // 8 绝缘检测电压达标
e_insul_ing_ok , // 9 绝缘检测完成
e_insul_mdu_stop, // 10 绝缘检测完成
e_insul_relief , // 11 绝缘泄放
e_wiat_bms_pre , // 12 等待bms预充电状态
e_wiat_batt_vol , // 13 检查电压测电压与标准是否符合
e_wiat_pre_mdu , // 14 等待预充模块启动
e_wiat_pre_vol , // 15 等待预充电压达标
e_wiat_bms_change, // 16 等待bms开始进入充电
e_change, // 17 进入充电中
e_change_suspend, // 18 充电暂停
}CHARGE_STATE;
typedef enum //充电流程控制状态
{
E_FLOW_FREE = 0, //空闲
E_FLOW_START_CHECK, //启动前检查
E_FLOW_START_CHECK_OK, //启动前检查完成
E_FLOW_INSUL_BEFORE, //绝缘检查前准备
E_FLOW_INSUL_RUNING, //绝缘检测中
E_FLOW_INSUL_OK, //绝缘检测完成
E_FLOW_WAIT_PRE_CHARGE, //等待预充
E_FLOW_PRE_CHARGE_BEFORE, //预充前检查
E_FLOW_PRE_CHARGE_RUNING, //预充电中
E_FLOW_PRE_CHARGE_OK, //预充完成
E_FLOW_CHARGE_RUNING, //充电中
E_FLOW_CHARGE_SUSPEND, //充电暂停
E_FLOW_BMS_TIMEOUT, //BMS通讯超时
E_FLOW_STOP_CHARGE, //停止充电
E_FLOW_STOP_CHARGE_OK, //停止充电完成
}E_FLOW_STATE;
typedef struct //flow实时运行变量
{
E_FLOW_STATE e_flow_state; //流程控制状态 0x0D
E_FLOW_REAL_STATE e_flow_real_state; //流程控制对外状态 0x09
CHARGE_STATE e_charge_state; //充电详细步骤
START_REASON e_start_reason; //启动充电原因
E_FAULT_INFO e_stop_reason[5]; //停止原因
U8_T u8_bms_renew_cnt; //bms重连次数
U8_T u8_bms_renew_ctrl; //BMS重连控制标志
U8_T log_stop_flag; //订单停止标志
U32_T ulong_flow_timer; //状态超时计时
U32_T ulong_mdu_stop_timer; //状态超时计时
U16_T u16_anti_shake_cnt; //防抖计数
U16_T u16_anti_shake_cnt2; //防抖计数
//bms状态标志位
U8_T u8_bms_chm_flag; //bms握手辨识标志 0无 1成功 2失败
U8_T u8_bms_pre_flag; //bms开始预充标志 0无 1成功
U8_T u8_bms_charge_flag; //bms进入充电标志 0无 1成功
U8_T u8_bms_suspend_flag; //bms禁止充电标志 0无 1成功
U8_T u8_bms_stop_flag; //bms停止充电标志 0无 1成功
U8_T u8_insul_ret; //绝缘检测结果
U32_T u32_insul_Rx; //绝缘检测正对地电阻 单位 0.1欧姆
U32_T u32_insul_Ry; //绝缘检测负对地电阻 单位 0.1欧姆
U16_T u16_need_vol; //需求电压 精度0.1V
U16_T u16_need_cur; //需求电流 精度0.1A
U16_T u16_real_put_vol; //实际输出电压
U16_T u16_real_put_cur; //实际输出电流
}S_FLOW_REAL_DATA;
typedef struct //故障超时判定起始时间
{
U32_T u32_trickle_limit_time; //涓流停机超时起始时间
U32_T u32_dc_km_time; //直流输出接触器超时起始时间
U32_T u32_mdu_free_time; //充电模块空闲超时起始时间
U32_T u32_over_vol_time; //直流输出过压超时起始时间
U32_T u32_under_vol_time; //直流输出欠压超时起始时间
U32_T u32_over_curr_time; //直流输出欠压超时起始时间
U32_T u32_over_needCur_time; //直流输出大于需求超时起始时间
U32_T u32_over_needCur_max_time; //输出大于最高允许超时起始时间
U32_T u32_over_max_vol_time; //直流输出电压超过最高允许超时起始时间
}S_FLOW_OVER_TIME;
typedef struct
{
U8_T u8_twoGun_flag; //双枪同充标志 0不是单枪充电 1双枪同充且是主枪 2双枪同充且是辅助枪
U8_T u8_gunlock_cnt; //枪锁动作次数
START_REASON e_start_flag; //充电启停标志 0不启动 1正常启动 2即插即充 0x05
E_FAULT_INFO e_stop_flag; //外部停止充电标志
S16_T s16_fault_stop_cnt; //异常停止计数 -1 正常动作 0 直接都做 +N需要延时
E_CHRG_LIMIT_MOD e_sdk_chargMode; //充电限制方式 0 不做限制的充电(默认) 1 限制金额 2 限制电量 electricity 3 限制SOC 4 限制充电时长 5 限制功率
S_FLOW_OVER_TIME s_over_time; //故障超时判定起始时间
U32_T u32_limit_data; //限制参数 限制金额默认精度 0.01元 限制电量默认精度0.1kWh
}S_FLOW_CTRL_DATA;
typedef struct
{
U32_T u32_satrt_time; //启动充电时间 时间戳
U32_T u32_stop_time; //停止充电时间 时间戳
U16_T u16_char_time; //充电时间 单位秒
U32_T u32_used_energy; //己用电量,单位是0.0001KWh
U32_T u32_used_money; //充电金额,,单位是0.0001元
U32_T u32_used_service_money; //充电服务,单位是0.0001元
E_FAULT_INFO u_stop_res; //停止充电原因
}S_FLOW_LOG_DATA;
typedef enum
{
E_PULSE_STATE_IDLE = 0, //脉冲空闲
E_PULSE_STATE_ON, //脉冲闭合阶段
E_PULSE_STATE_OFF, //脉冲断开阶段
E_PULSE_STATE_STOP, //脉冲完成
} E_PULSE_STATE;
typedef struct //流程任务变量结构体定义
{
U8_T u8_gunCnt; //充电枪数量
U8_T u8_gb_en; //国标使能标志 0不使能 1使能
U8_T u8_gun_type[GUN_MAX_CNT]; //枪类型
U8_T u8_gunlock_num; //枪锁解锁最大次数
U8_T u8_relief_time; //泄放时间 单位 秒
U8_T u8_not_enable_flag; //不允许充电标志
U16_T u16_timer_cnt; //计时计数
U16_T u16_insul_before_vol; //绝缘前电压判断值 精度 0.1V
U16_T u16_insul_putvol_range; //绝缘检测输出电压误差值 精度 0.1V
U8_T u8_start_flag; //模块任务运行标志 0停止 1运行
U8_T u8_pulse_target_ac; //脉冲目标AC 1=AC1 2=AC2
U8_T u8_pulse_cycle_count; //脉冲周期计数
E_PULSE_STATE e_pulse_state; //脉冲控制状态
U64_T u64_pulse_timer; //脉冲计时器 ms
S_FLOW_CTRL_DATA s_ctrl_data[GUN_MAX_CNT]; //控制命令
S_FLOW_REAL_DATA s_real_data[GUN_MAX_CNT]; //充电实时信息 空闲时清零
S_FLOW_LOG_DATA s_log_data[GUN_MAX_CNT]; //充电订单信息 -- 用于显示
S_MDU_ALLOCATE_CTRL s_mdu_allocate_ctrl[GUN_MAX_CNT];//模块控制信息
}S_FLOW_DATA;
void v_flowctrl_task(void *arg);
U8_T u8_flowctrl_get_gun_num(void);
void v_flow_set_stop_charge(U8_T u8_gunNo , E_FAULT_INFO e_stop_reason , S16_T s16_fault_stop_cnt);
#endif
+86
View File
@@ -0,0 +1,86 @@
# flowctrl 模块说明
> 路径:`app/flowctrl/`
> 返回主说明:[README](../../README.md)
## 1. 模块职责
- 实现充电流程控制主逻辑与状态机;
- 提供流程对外数据接口与控制接口;
- 处理流程关键保护与异常停机条件。
## 2. 关键文件
- `flowctrl_task.c/h`
- `flow_interface.c/h`
- `insulation_ctrl.c/h`
- `mdu_swh_ctrl.c/h`
## 3. 功能说明
- 管理充电开始、运行、停止、故障等流程状态切换;
- 对接故障模块、BMS、计量模块及外部控制命令;
- 对外提供流程运行数据和控制入口,供 UI/TCP 等模块调用。
## 4. 调度与对外接口
该模块由 FreeRTOS 任务 `FlowCtrl` 周期运行(单位:ms),周期来自 `app/app_init/app_init.c`
- `FlowCtrl``20ms`(任务入口:`v_flowctrl_task(void *arg)`
对外接口(来自 `flowctrl_task.h`):
- `void v_flowctrl_task_init(void)`:初始化流程状态机/内部缓存
- `void v_flowctrl_task(void *arg)`:流程控制任务入口
- `U8_T u8_flowctrl_get_gun_num(void)`:返回枪数量(供上层界面/通信使用)
## 5. 维护建议
- 流程状态跳转新增分支时需同步检查故障与恢复路径;
- 对外接口字段建议统一经 `flow_interface` 暴露,减少模块耦合。
## 6. 绝缘检查步骤(详细)
绝缘检查主流程由 `flowctrl_task.c` 状态机调度,核心计算在 `insulation_ctrl.c`
- 状态入口:`E_FLOW_INSUL_BEFORE``v_flow_ctrl_insul_before`
- 条件:模块进入工作态,且绝缘电压到位(或欧标 15s 跳过电压到位检查);
- 动作:切到 `E_FLOW_INSUL_RUNING`,调用 `v_flow_gun_insulation_data_ctrl(gun,0)` 开始绝缘检测资源控制;
- 典型日志:`INS V ok...``15s skip V chk...`
- 检测执行:`E_FLOW_INSUL_RUNING``v_flow_ctrl_insul_runing`
- 调用:`s8_flow_gun_insulation()` -> `s8_insulation_action()` -> `v_insulation_Calculate()`
- 返回:`-1` 检测中,`0` 失败,`1` 正常,`2` 告警;
- 完成后记录 `u32_insul_Rx/Ry``u8_insul_ret`,并切到 `E_FLOW_INSUL_OK`
- 典型日志:`INS res=%d(0F,1OK,2WARN), R+=..., R-=...`
- 结果收尾:`E_FLOW_INSUL_OK``v_flow_ctrl_insul_ok`
- 先等待模块停机/母线下降并执行泄放;
- 再根据 `u8_insul_ret` 判定:
- `0`:失败,停机故障 `E_FAULT_13042`(绝缘检测失败);
- `2`:告警,置 `E_FAULT_13043`(绝缘告警)后允许继续;
- `1`:通过,进入后续预充/充电流程。
`insulation_ctrl.c` 内部两阶段计算要点:
- 阶段1(大地继电器闭合后):
- 采样 `U+gnd``U-gnd`
- 计算单侧绝缘电阻粗判,若小于阈值直接失败(结果码2);
- 阈值规则:`R_min = 100 * (U+gnd + U-gnd)``R_max = 500 * (U+gnd + U-gnd)`
- 阶段2(光耦继电器闭合后):
- 二次采样并按公式计算 `R+gnd``R-gnd`
- 判定规则:
- 任一 `< R_min` => 失败(结果码3);
- 任一 `<= R_max` => 告警(结果码4);
- 否则 => 正常(结果码5)。
调试建议(结合日志):
- 先看 `Th: min/max` 是否与当时 `U+gnd + U-gnd` 一致;
- 再看 `R+gnd/R-gnd` 是否显著低于 `R_min`(会触发 `13042`);
- 若经常走 `15s skip V chk`,优先排查模块电压到位与采样链路。
## 7. 关联文档
- 主索引:[README](../../README.md)
+325
View File
@@ -0,0 +1,325 @@
#include "flowctrl/insulation_ctrl.h"
#include "flowctrl/flowctrl_task.h"
#include "collect_ctrl/collect_task.h"
#include <float.h>
typedef struct
{
U32_T u32_ins_timer; //绝缘开始秒数存储,用于与当前时间比较
F32_T f32_ADC_VOL1[2]; //控制大地闭合后,ADC_VOL1[0]正对地电压,ADC_VOL1[1]负对地电压
F32_T f32_R_min; //绝缘检测失败阈值(100欧/伏)
F32_T f32_R_max; //绝缘检测告警阈值(500欧/伏)
F32_T f32_R_m; //控制大地闭合后,最小电阻值;
F32_T f32_ADC_VOL2[2]; //控制绝缘检测光电继电器闭合后,ADC_VOL2[0]正对地电压,ADC_VOL2[1]负对地电压
F32_T f32_ins_RZ; //控制绝缘检测光电继电器闭合后,正对地电阻
F32_T f32_ins_RF; //控制绝缘检测光电继电器闭合后,负对地电阻
F64_T f64_V1;
F64_T f64_V2;
U8_T u8_step; //绝缘步骤控制
}INS_EXTE_DATA; //绝缘检测相关数据
INS_EXTE_DATA s_ins_ctrl[GUN_MAX_CNT];
static void v_insulation_Calculate(U8_T gunNo,U8_T *u8_result,F32_T *f32_rz, F32_T *f32_rf) ;
#if 1 //外部数据获取
/**
* ************************************************************************
* @brief - 获取直流母线adc采样电压值
*
* @param[in] u8_gunNo - 枪号 0-1
* @param[in] u8_type - 数据类型 1直流母线正对地电压 0直流母线负对地电压
*
* @return F32_T -
*
* @author jiankalka
* @date 2025-11-14
* ************************************************************************
*/
static F32_T f32_insl_get_adc_vol(U8_T u8_gunNo, U8_T u8_type )
{
F32_T f32_ret;
f32_ret = u8_type?f32_get_gun_yc_data(ADC_GUN_VOLT_PLUS,u8_gunNo):f32_get_gun_yc_data(ADC_GUN_VOLT_MINUS,u8_gunNo);
return f32_ret;
}
#endif
#if 1 //对外提供控制接口
/*
函数功能:绝缘控制终止 断开大地与光电继电器
输入:U8_T gunNo 充电枪号
*/
void v_insulation_stop(U8_T gunNo)
{
INS_EXTE_DATA *ins_data = NULL;
if (gunNo >= GUN_MAX_CNT) return;
ins_data = &(s_ins_ctrl[gunNo]);
switch(gunNo) //大地、光电继电器控分
{
case 0:
GUN1_INS_CTL(0);
GUN1_UBAL_CTL(0);
break;
case 1:
GUN2_INS_CTL(0);
GUN2_UBAL_CTL(0);
break;
}
ins_data->u8_step = 0; //绝缘检测终止,step置0
ins_data->u32_ins_timer = 0; //绝缘检测终止,u32_insu_timer置0
}
/**
* ************************************************************************
* @brief - 绝缘检查动作执行
*
* @param[in] gunNo - 枪号 0-1
* @param[in] f32_rz - 正对地电阻
* @param[in] f32_rf - 负对地电阻
*
* @return S8_T - -1 未完成 0失败 1成功 2成功但告警
*
* @author jiankalka
* @date 2025-11-14
* ************************************************************************
*/
S8_T s8_insulation_action(U8_T gunNo ,F32_T *f32_rz, F32_T *f32_rf)
{
S8_T s8_ret = -1;
U8_T u8_result = 1; //1:绝缘检测中; 2:大地闭合阶段绝缘检测失败; 3:光电继电器闭合阶段绝缘检测失败; 4:绝缘检测告警,但可以正常充电; 5:绝缘检测正常
v_insulation_Calculate(gunNo,&u8_result,f32_rz,f32_rf); //绝缘监测执行
//FLOWCTRL_LOG("insulation res = %d\n",u8_result);
if(u8_result == 1) //绝缘检测中;
{
s8_ret = -1;
}
else if(u8_result == 5) //绝缘监测正常
{
s8_ret = 1;
}
else if(u8_result == 4) //绝缘监测告警
{
s8_ret = 2;
}
else //绝缘监测失败
{
s8_ret = 0;
}
return s8_ret;
}
#endif
#if 1 //绝缘监测控制
/*
函数功能:进行绝缘检测流程 计算绝缘检测电阻
输入:U8_T gunNo 充电枪号
输出:绝缘检测结果:U8_T *u8_result 1:绝缘检测中;
2:大地闭合阶段绝缘检测失败;
3:光电继电器闭合阶段绝缘检测失败;
4:绝缘检测告警,但可以正常充电;
5:绝缘检测正常
*f32_rz 正对地电阻
*f32_rf 负对地电阻
备注:绝缘流程及公式说明
1、控制系统接大地(PE)高压继电器®闭合
U𝑃:充电机输出正极(DC+)对大地(PE)的电压值
U𝑁:大地(PE)对充电机输出负极(DC-)的电压值
V1 = U𝑁/801.5K - U𝑃/801.5K
(1)如果U𝑃>U𝑁: R𝑁 = (801.5K × U𝑁)/(U𝑃 U𝑁)
判断 R𝑁绝缘达标,控制短接正桥臂电阻的光电继电器®闭合,不符合直接报绝缘故障;
(2)如果U𝑃<U𝑁:R𝑃 = (801.5K × U𝑃)/(U𝑁 U𝑃)
判断 R𝑃绝缘达标,控制短接正桥臂电阻的光电继电器®闭合,不符合直接报绝缘故障;
(3)如果U𝑃=U𝑁,控制短接正桥臂电阻的光电继电器®闭合;
2、闭合光电继电器® 绝缘电阻值计算
U𝑃′:充电机输出正极(DC+)对大地(PE)的电压值
U𝑁′:大地(PE)对充电机输出负极(DC-)的电压值
V2 = U𝑁′/801.5K - U𝑃′/801.5K
R𝑃 = (U𝑁′ × U𝑃 − U𝑁 × U𝑃′)/(U𝑁′ × V1 U𝑁 × V2)
R𝑁 = (U𝑃 × U𝑁′ − U𝑃′ × U𝑁)/(U𝑃′ × V1 U𝑃 × V2)
*/
static void v_insulation_Calculate(U8_T gunNo,U8_T *u8_result,F32_T *f32_rz, F32_T *f32_rf)
{
INS_EXTE_DATA *ins_data = NULL;
float volt = 0.0;
if (gunNo >= GUN_MAX_CNT || u8_result == NULL ||
f32_rz == NULL || f32_rf == NULL)
return;
ins_data = &(s_ins_ctrl[gunNo]);
F32_T f32_vol1 = f32_insl_get_adc_vol(gunNo,1); //直流母线 正对地电压
F32_T f32_vol2 = f32_insl_get_adc_vol(gunNo,0); //直流母线 负对地电压
//FLOWCTRL_LOG("INS adcV=%f,%f\n",f32_vol1,f32_vol2);
if(ins_data->u8_step == 0)
{
if(ins_data->u32_ins_timer == 0) //参数初始化
{
memset(ins_data,0,sizeof(INS_EXTE_DATA)); //开始绝缘检测前,对本枪绝缘检测数据存储结构体初始化
volt = f32_vol1 + f32_vol2; //绝缘检测开始前获取当前回路输出电压,计算出该电压等级下绝缘告警与失败的电阻值
ins_data->f32_R_min = 100 * volt;
ins_data->f32_R_max = 500 * volt;
ins_data->u32_ins_timer = get_current_seconds(); //记录绝缘检测开始的时间
FLOWCTRL_LOG("Gun%d(0-N) INS start, adcV=%f,%f\n",gunNo,f32_vol1,f32_vol2);
switch(gunNo) //绝缘检测开始,大地控合,光电继电器控分
{
case 0:
GUN1_INS_CTL(1);
GUN1_UBAL_CTL(0);
break;
case 1:
GUN2_INS_CTL(1);
GUN2_UBAL_CTL(0);
break;
}
*u8_result = 1; // 1:绝缘检测中;
}
else if(u32_safe_seconds_since(ins_data->u32_ins_timer) > 1) //大地控合1S后开始采集电压,进行绝缘电阻计算
{
ins_data->f64_V1 = (f32_vol2 - f32_vol1) / 801500;
if(f32_vol1 == f32_vol2) //正对地与负对地电压相等,控合光电继电器,进入下一步
{
switch(gunNo)
{
case 0:
GUN1_UBAL_CTL(1);
break;
case 1:
GUN2_UBAL_CTL(1);
break;
}
ins_data->u8_step = 1;
*u8_result = 1; // 1:绝缘检测中;
}
else if (f32_vol1 > f32_vol2)
{
ins_data->f32_R_m = (801500 * f32_vol2) / (f32_vol1 - f32_vol2);
*f32_rf = ins_data->f32_R_m; //负对地电压小,只计算负对地电阻
*f32_rz = FLT_MAX; //正对地赋值为最大值
}
else
{
ins_data->f32_R_m = (801500 * f32_vol1) / (f32_vol2 - f32_vol1);
*f32_rz = ins_data->f32_R_m; //正对地电压小,只计算负对地电阻
*f32_rf = FLT_MAX; //负对地赋值为最大值
}
if(ins_data->f32_R_m < ins_data->f32_R_min) //判定不达标,大地控合阶段绝缘检测失败,断开大地与光电继电器,返回1
{
FLOWCTRL_LOG("Gun%d(0-N) INS1 fail, adcV=%f,%f\n",gunNo,f32_vol1,f32_vol2);
FLOWCTRL_LOG("R= %f ,%f\n",ins_data->f32_R_m,ins_data->f32_R_min);
switch(gunNo)
{
case 0:
GUN1_INS_CTL(0);
GUN1_UBAL_CTL(0);
break;
case 1:
GUN2_INS_CTL(0);
GUN2_UBAL_CTL(0);
break;
}
*u8_result = 2; //2:大地闭合阶段绝缘检测失败;
}
else //判定达标,控合光电继电器,step置1,进入下一阶段,
{
switch(gunNo)
{
case 0:
GUN1_UBAL_CTL(1);
break;
case 1:
GUN2_UBAL_CTL(1);
break;
}
//FLOWCTRL_LOG("Close opto relay\n");
ins_data->f32_ADC_VOL1[0] = f32_vol1; //保存此时的采样值 在第二部计算时使用
ins_data->f32_ADC_VOL1[1] = f32_vol2;
ins_data->u8_step = 1;
*u8_result = 1 ; // 1:绝缘检测中;
}
}
}
else if (ins_data->u8_step == 1)
{
if(u32_safe_seconds_since(ins_data->u32_ins_timer) > 2)//光电继电器控合1s后,开始绝缘计算
{
volt = f32_vol1 + f32_vol2; //光电继电器闭合后,采集DC+、DC-对地电压
ins_data->f32_R_min = 100 * volt;
ins_data->f32_R_max = 500 * volt;
ins_data->f64_V2 = f32_vol2/801500 - f32_vol1/801500; //计算 V2
ins_data->f32_ADC_VOL2[0] = f32_vol1;
ins_data->f32_ADC_VOL2[1] = f32_vol2;
ins_data->f32_ins_RZ = (ins_data->f32_ADC_VOL2[1]*ins_data->f32_ADC_VOL1[0] - ins_data->f32_ADC_VOL1[1]*ins_data->f32_ADC_VOL2[0])
/(ins_data->f32_ADC_VOL2[1]*ins_data->f64_V1 - ins_data->f32_ADC_VOL1[1]*ins_data->f64_V2);
ins_data->f32_ins_RF = (ins_data->f32_ADC_VOL1[0]*ins_data->f32_ADC_VOL2[1] - ins_data->f32_ADC_VOL2[0]*ins_data->f32_ADC_VOL1[1])
/(ins_data->f32_ADC_VOL2[0]*ins_data->f64_V1 - ins_data->f32_ADC_VOL1[0]*ins_data->f64_V2);
FLOWCTRL_LOG("1 V+gnd=%.2f, V-gnd=%.2f\n",ins_data->f32_ADC_VOL1[0],ins_data->f32_ADC_VOL1[1]);
FLOWCTRL_LOG("2 V+gnd=%.2f, V-gnd=%.2f\n",ins_data->f32_ADC_VOL2[0],ins_data->f32_ADC_VOL2[1]);
FLOWCTRL_LOG("V1: %.10f ,V2: %.10f\n",ins_data->f64_V1,ins_data->f64_V2);
ins_data->f32_ins_RZ = fabs(ins_data->f32_ins_RZ);
ins_data->f32_ins_RF = fabs(ins_data->f32_ins_RF);
*f32_rz = ins_data->f32_ins_RZ;
*f32_rf = ins_data->f32_ins_RF;
switch(gunNo) //绝缘计算完成,大地与光耦控分
{
case 0:
GUN1_INS_CTL(0);
GUN1_UBAL_CTL(0);
break;
case 1:
GUN2_INS_CTL(0);
GUN2_UBAL_CTL(0);
break;
}
ins_data->u8_step = 0; //绝缘检测完成,step置0
ins_data->u32_ins_timer = 0; //绝缘检测完成,u32_insu_timer置0
FLOWCTRL_LOG("Th: min=%.2f, max=%.2f\n",ins_data->f32_R_min,ins_data->f32_R_max);
FLOWCTRL_LOG("R+gnd=%.2f, R-gnd=%.2f\n",ins_data->f32_ins_RZ,ins_data->f32_ins_RF);
//光电继电器闭合后,直流回路绝缘情况判定
if(ins_data->f32_ins_RF < ins_data->f32_R_min || ins_data->f32_ins_RZ < ins_data->f32_R_min )
{
*u8_result = 3; //3:光电继电器闭合阶段绝缘检测失败;
}
else if (ins_data->f32_ins_RF <= ins_data->f32_R_max || ins_data->f32_ins_RZ <= ins_data->f32_R_max )
{
*u8_result = 4; //4:绝缘检测告警,但可以正常充电;
}
else
{
*u8_result = 5; //5:绝缘检测正常
}
}
}
}
#endif
+26
View File
@@ -0,0 +1,26 @@
#ifndef INSULATION_CTRL_H
#define INSULATION_CTRL_H
#ifdef __cplusplus /*C++编译环境下兼容C语言*/
extern "C" {
#endif
/*------ Exported includes(头文件) ----------------------*/
#include "main.h"
/*------ Exported macro(宏定义) -------------------------*/
/*------ Exported struct(结构体定义) --------------------*/
/*------ Exported variables(变量定义) -------------------*/
/*------ Exported function prototypes (函数声明) -------*/
S8_T s8_insulation_action(U8_T gunNo ,F32_T *f32_rz, F32_T *f32_rf);
void v_insulation_stop(U8_T gunNo);
#ifdef __cplusplus
}
#endif
#endif /* INSULATION_CTRL_H */
+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
+33
View File
@@ -0,0 +1,33 @@
#ifndef MDU_SWH_CTRL_H
#define MDU_SWH_CTRL_H
#ifdef __cplusplus /*C++编译环境下兼容C语言*/
extern "C" {
#endif
/*------ Exported includes(头文件) ----------------------*/
#include "main.h"
#include "mdu_comm/mdu_interface.h"
/*------ Exported macro(宏定义) -------------------------*/
/*------ Exported struct(结构体定义) --------------------*/
typedef struct
{
U8_T u8_start_flag; //模块运行开始标志 0未开始 1开始
U8_T u8_other_borrow_flag; //另一把枪 借用标志
U8_T u8_yk_cmd; //遥控命令枚举 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组)
U16_T u16_need_vol; //需求电压 精度0.1
U16_T u16_need_cur; //需求电流 精度0.1
U16_T u16_one_mdu_need_cur; //单模块需求电流 精度0.1
}S_MDU_ALLOCATE_CTRL;
/*------ Exported variables(变量定义) -------------------*/
/*------ Exported function prototypes (函数声明) -------*/
void v_flow_ac_fan_ctrl(U16_T u16_sleep);
void v_mdu_shw_control(U16_T u16_leep_time);
#ifdef __cplusplus
}
#endif
#endif /* MDU_SWH_CTRL_H */