Files
CCU621M/app/flowctrl/flowctrl_task.c
T

2110 lines
87 KiB
C

#include "flowctrl/flowctrl_task.h"
#include "app_init/app_init.h"
#include "app_init/task_lock.h"
#include "mylog/mylog.h"
#include "publicdata/publicdata.h"
#include "app_rtc/app_rtc.h"
#include "wdt_task/wdt_task.h"
#define FLOWCTRL_TASK_ID (TASK_ID_FlowCtrl)
#define FLOWCTRL_SLEEP_TIME_MS() (MY_GET_SLEEP_TIME(FLOWCTRL_TASK_ID))
#define FLOWCTRL_LOCK_INIT() (u8_task_lock_ctrl(FLOWCTRL_TASK_ID, TASK_LOCK_OP_INIT))
#define FLOWCTRL_LOCK_TAKE() (u8_task_lock_ctrl(FLOWCTRL_TASK_ID, TASK_LOCK_OP_TAKE))
#define FLOWCTRL_LOCK_GIVE() (u8_task_lock_ctrl(FLOWCTRL_TASK_ID, TASK_LOCK_OP_GIVE))
#define FLOWCTRL_FEED_DOG() (v_wdt_setFlag(FLOWCTRL_TASK_ID))
const char flow_real_mag[][30] =
{
"IDLE ",
"CHG START ",
"INS START ",
"INS DONE ",
"INS MDU STOP ",
"PRECHG START ",
"PRECHG DONE ",
"CHARGING ",
"BMS TIMEOUT ",
"CHG STOP ",
"CHG STOP OK ",
};
S_FLOW_DATA s_flow_data;
#define TEST_FLOW_NO_DCU (0) //测试标志 - 无DCU测试 主要是不判断绝缘监测和采集电压
#if 1 //公共逻辑使用
/**
* ************************************************************************
* @brief - 充电流程控制状态 跳转
*
* @param[in] u8_gunNo - 枪号 0-N
* @param[in] e_state - 跳转后状态
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
static void v_flow_ctrl_state_change(U8_T u8_gunNo, E_FLOW_STATE e_state)
{
S_FLOW_REAL_DATA *s_data = &s_flow_data.s_real_data[u8_gunNo];
if(s_data->e_flow_state != e_state)
{
FLOWCTRL_LOG("State chg: %d -> %d\n", s_data->e_flow_state, e_state);
s_data->e_flow_state = e_state; //状态赋值
s_data->u16_anti_shake_cnt = 0; //防抖计数清零
s_data->u16_anti_shake_cnt2 = 0; //防抖计数清零
s_data->ulong_flow_timer = get_current_seconds(); //状态跳转时间赋值
// 防止 s_over_time 初值为0/陈旧值导致首次判定直接超时
{
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo];
U32_T now_s = s_data->ulong_flow_timer;
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;
}
}
}
/**
* ************************************************************************
* @brief - 充电流程对外实时状态 跳转
*
* @param[in] u8_gunNo - 枪号 0-N
* @param[in] e_state - 跳转后状态
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
static void v_flow_real_state_change(U8_T u8_gunNo, E_FLOW_REAL_STATE e_state)
{
S_FLOW_REAL_DATA *s_data = &s_flow_data.s_real_data[u8_gunNo];
if(s_data->e_flow_real_state != e_state)
{
FLOWCTRL_LOG("Ext st chg: %d %s -> %d %s\n", s_data->e_flow_real_state,
flow_real_mag[s_data->e_flow_real_state], e_state , flow_real_mag[e_state]);
s_data->e_flow_real_state = e_state; //状态赋值
}
}
/**
* ************************************************************************
* @brief - 流程控制任务 空闲状态 枪锁动作检查
*
* @param[in] u8_gunNo - 抢号 0-N
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
static void v_flow_free_gunlock_check(U8_T u8_gunNo)
{
if (!(s_flow_data.u8_gun_type[u8_gunNo] == 0)) /* 国标枪:枪锁检查 */
{
static U8_T u8_flag = 0; //确保每个周期只执行一次
U8_T u8_gunlock_en = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_GUNLOCK_EN,0); //枪锁使能 0不使能 1使能
U8_T u8_gunlock_st = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_LOCK,0); //枪锁状态 0未锁 1已锁
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo];
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
U16_T u16_batt_adc_vol;
if(u8_gunlock_en && u8_gunlock_st) //枪锁使能并且枪锁为锁的
{
if(s_ctrl_data->u8_gunlock_cnt < s_flow_data.u8_gunlock_num) //动作次数小于规定动作次数
{
u16_batt_adc_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_BATT_ADC_VOL,0); //电池外侧采集电压 精度 0.1V
if(u16_batt_adc_vol < s_flow_data.u16_insul_before_vol || //外侧电压小于60V 才做解锁
u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= 5) //状态 跳转过来大于5秒
{
if((s_flow_data.u16_timer_cnt/NUM_1000) % 4 == 0 ) //4秒一次 且取余4的为0
{
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_GUN_LOCK,1,1); //枪锁上锁
u8_flag = 1;
}
else if((s_flow_data.u16_timer_cnt/NUM_1000) % 4 == 2 ) //4秒一次 且取余4为2
{
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_GUN_LOCK,0,0); //枪锁解锁
if(u8_flag == 1)
{
u8_flag = 0;
s_ctrl_data->u8_gunlock_cnt++; //枪锁动作次数+1
}
}
}
}
else
{
//枪锁解锁失败 做什么?
//v_set_fault_data(u8_gunNo+1,E_FAULT,E_FAULT_13011,1,*u8_cnt,0); //告警 解枪锁失败 拔枪恢复
}
}
else
{
s_ctrl_data->u8_gunlock_cnt = 0; //解锁成功 计数清零
if(u16_flow_get_sys_data(u8_gunNo+1,E_FLOW_GET_DATA_FAULT_FLAG,E_FAULT_13011)) //获取故障内容存在标志 0不存在 1存在;需要传入 故障代码参数)
{
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_RES, E_FAULT_13011, 0, 0, 0);
}
}
}
}
/**
* ************************************************************************
* @brief - 流程控制任务 计时计数累加
*
* @param[in] u16_sleep_time - 周期值 ms
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
static void v_flow_timer_add(U16_T u16_sleep_time)
{
U8_T i;
//周期累加计数 单位ms 注意计数为周期值累加,使用时为周期值的倍数
if(s_flow_data.u16_timer_cnt < 0xFF00)
s_flow_data.u16_timer_cnt += u16_sleep_time;
else
s_flow_data.u16_timer_cnt = 0;
for (i = 0; i < s_flow_data.u8_gunCnt; i++)
{
//防抖计数 累加
if(s_flow_data.s_real_data[i].u16_anti_shake_cnt < 0xFF00)
s_flow_data.s_real_data[i].u16_anti_shake_cnt += u16_sleep_time;
else
s_flow_data.s_real_data[i].u16_anti_shake_cnt = 0;
if(s_flow_data.s_real_data[i].u16_anti_shake_cnt2 < 0xFF00)
s_flow_data.s_real_data[i].u16_anti_shake_cnt2 += u16_sleep_time;
else
s_flow_data.s_real_data[i].u16_anti_shake_cnt2 = 0;
//故障计数倒计时 累减
if(s_flow_data.s_ctrl_data[i].s16_fault_stop_cnt >= u16_sleep_time)
s_flow_data.s_ctrl_data[i].s16_fault_stop_cnt -= u16_sleep_time;
else if(s_flow_data.s_ctrl_data[i].s16_fault_stop_cnt >= 0)
s_flow_data.s_ctrl_data[i].s16_fault_stop_cnt = 0;
}
}
/**
* ************************************************************************
* @brief - 充电枪限制功率检查 充电枪有功率限制时,计算当前需求功率是否超过限制功率,若超过则根据当前需求电压计算出限制电流,并更新需求电流为限制电流
*
* @param[in] u8_gunNo - 抢号 0-N
* @param[in] u16_need_vol - BMS需求电压 单位0.1V
* @param[in] u16_need_cur - BMS需求电流 单位0.1A
*
*
* @author jiankalka
* @date 2026-03-04
* ************************************************************************
*/
static void v_flow_check_gun_power_limit(U8_T u8_gunNo,U16_T *u16_need_vol,U16_T *u16_need_cur)
{
U16_T u16_gun_power_limit = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_POWER_LIMIT,0); //充电枪的限制功率值 单位kW 0表示不限制
U16_T u16_meter_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_VOL,0); //电表采集电压 精度0.1V
if(u16_gun_power_limit != 0)
{
U32_T u32_need_power = (*u16_need_vol) * (*u16_need_cur) / 100; //计算需求功率 单位W
if(u16_meter_vol != 0 && u32_need_power > (U32_T)u16_gun_power_limit * 1000) //需求功率大于限制功率才进行限制计算
{
U32_T u32_limit_cur = (U32_T)(u16_gun_power_limit * 100000) / (u16_meter_vol); //根据限制功率和电表电压计算限制电流 单位0.1A
if(u32_limit_cur < *u16_need_cur)
{
// FLOWCTRL_LOG("Gun%d pwr limit on, limit=%d kW, reqI=%d.%d->%d.%d A\n",
// u8_gunNo,u16_gun_power_limit,*u16_need_cur/10,*u16_need_cur%10,u32_limit_cur/10,u32_limit_cur%10);
*u16_need_cur = u32_limit_cur; //更新需求电流为限制电流
}
}
}
}
#endif
#if 1 //充电订单信息管理
/**
* ************************************************************************
* @brief - 充电订单信息管理 充电启停时触发
*
* @param[in] u8_gunNo - 抢号
* @param[in] u8_flag - 标志 0充电停止 1充电启动 2充电中计算充电时间
*
*
* @author jiankalka
* @date 2025-09-11
* ************************************************************************
*/
void v_flow_log_info_ctrl(U8_T u8_gunNo,U8_T u8_flag)
{
S_FLOW_LOG_DATA *s_flow_log = &s_flow_data.s_log_data[u8_gunNo];
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo];
Comm_Time rel_time;
U32_T u32_time;
GetCurrentTime(&rel_time);
u32_time = xDate2Seconds(&rel_time);
if(u8_flag == 0) //停止充电
{
s_flow_log->u32_stop_time = u32_time;
s_flow_log->u_stop_res = s_real_data->e_stop_reason[0];
v_flow_set_stop_log_info(u8_gunNo , s_flow_log->u_stop_res);
}
else if(u8_flag == 1) //启动充电
{
memset(s_flow_log, 0, sizeof(S_FLOW_LOG_DATA));
s_flow_log->u32_satrt_time = u32_time;
}
else{
if(s_flow_log->u32_satrt_time != 0 &&
s_flow_log->u32_stop_time == 0)
{
// s_flow_log->u16_char_time = u32_time - s_flow_log->u32_satrt_time;
// if(s_flow_log->u16_char_time > 7200 ) //为检查充电时长跳变问题,充电时长对大于2h,打印当前时间信息
// {
// FLOWCTRL_LOG("Chg dur: %u\n",s_flow_log->u16_char_time);
// FLOWCTRL_LOG("Now: %d-%d-%d %d:%d:%d\n",rel_time.iYear,rel_time.ucMonth,rel_time.ucDay,rel_time.ucHour,rel_time.ucMin,rel_time.ucSec);
// FLOWCTRL_LOG("Start ts: %u\n",s_flow_log->u32_satrt_time);
// FLOWCTRL_LOG("Now ts: %u\n",u32_time);
// }
}
}
}
#endif
#if 1 //充电启停相关
/**
* ************************************************************************
* @brief - 流程控制任务 停止充电
*
* @param[in] u8_gunNo - 抢号 0-N
* @param[in] e_stop_reason - 停止原因 详看停止原因枚举
* @param[in] s16_fault_stop_cnt - 故障停止计数 - 用于直流继电器断开时间
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
void v_flow_set_stop_charge(U8_T u8_gunNo , E_FAULT_INFO e_stop_reason , S16_T s16_fault_stop_cnt)
{
U8_T i;
char mag[FAULT_GET_MAG_MAX_LEN] = {0};
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo];
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo];
if((s16_fault_stop_cnt != TIMER_SPECIAL_2) &&
(s_real_data->e_flow_state == E_FLOW_FREE ||
s_real_data->e_flow_state == E_FLOW_STOP_CHARGE || //已经停止就不再执行了
s_real_data->e_flow_state == E_FLOW_STOP_CHARGE_OK))
return;
v_flow_get_fault_mag(e_stop_reason , mag,FAULT_GET_MAG_MAX_LEN); //获取停止原因对应故障代码内容 中文
FLOWCTRL_LOG("(%d)Gun stop, reason=%d %s\n",u8_gunNo,e_stop_reason,mag);
for(i=0;i<5;i++)
{
if(s_real_data->e_stop_reason[i] == 0)
{
s_real_data->e_stop_reason[i] = e_stop_reason; //充电停止原因
break;
}
}
s_ctrl_data->s16_fault_stop_cnt = s16_fault_stop_cnt; //故障停止计数
if(s16_fault_stop_cnt == TIMER_SPECIAL_2)
{
s_real_data->log_stop_flag = 0;
}
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_STOP_CHARGE); //流程跳转到充电停止
}
/**
* ************************************************************************
* @brief - vin鉴权失败执行 ,由于会多次用到 单独做一个函数
*
* @param[in] u8_gunNo - 抢号 0-N
* @param[in] u8_flag - 失败原因 2平台鉴权超时 3非法VIN 4车辆识别鉴权帧超时 5即插即充鉴权失败 6鉴权VIN与车辆VIN不一致
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_vin_fail_stop(U8_T u8_gunNo,U8_T u8_flag)
{
if(u8_flag != 0)
FLOWCTRL_LOG("Auth res=%d\n",u8_flag);
if(u8_flag == 2) //2平台鉴权超时
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13067, TIMER_NONE ); //停止流程
}
else if(u8_flag == 3) //3非法VIN
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13064, TIMER_NONE ); //停止流程
}
else if(u8_flag == 4) //4车辆识别鉴权帧超时
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13078, TIMER_NONE ); //停止流程
}
else if(u8_flag == 5) //5即插即充鉴权失败
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13067, TIMER_NONE ); //停止流程
}
else if(u8_flag == 6) //6鉴权VIN与车辆VIN不一致
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13057, TIMER_NONE ); //停止流程
}
}
/**
* ************************************************************************
* @brief - 停止命令检查
*
* @param[in] u8_gunNo - 抢号 0-N
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_stop_cmd_check(U8_T u8_gunNo)
{
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_real_data->e_flow_state == E_FLOW_FREE ||
s_real_data->e_flow_state == E_FLOW_STOP_CHARGE || //已经停止就不再执行了
s_real_data->e_flow_state == E_FLOW_STOP_CHARGE_OK)
return;
if(s_ctrl_data->e_stop_flag != 0)
{
v_flow_set_stop_charge(u8_gunNo , s_ctrl_data->e_stop_flag , s_ctrl_data->s16_fault_stop_cnt);
s_ctrl_data->e_stop_flag = E_FAULT_NULL; //停止动作完成后 清零
}
}
#endif
#if 1 //充电停止条件、故障信息检查
/**
* ************************************************************************
* @brief - 充电停止条件、故障信息检查
* 门禁、急停、抢连接中断、过压、过流、欠压、
* @param[in] u8_gunNo - 抢号
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
void v_flow_stop_fault_check(U8_T u8_gunNo)
{
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]; //实时数据指针
S_FLOW_LOG_DATA *s_log_data = &s_flow_data.s_log_data[u8_gunNo];
U16_T u16_data,u16_data1,u16_data2;
U8_T u8_gunLink = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_LINK,0); //枪连接状态 0未连接 1已连接
U16_T u16_fault_info = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_FAULT_INFO,0); //获取整桩和该枪首个故障内容 0无故障 详见E_FAULT_INFO枚举内容 -整桩故障也代表本枪无法使用
//故障信息检查
if(u16_fault_info != 0)
{
//FLOWCTRL_LOG("Fault in chg=%d\n",u16_fault_info);
v_flow_set_stop_charge(u8_gunNo, (E_FAULT_INFO)u16_fault_info, TIMER_NONE ); //停止流程 函数内有判定 ,不在充电中,不会置位
}
//启动、充电中枪连接状态检查
if(s_real_data->e_flow_state > E_FLOW_FREE &&
s_real_data->e_flow_state <= E_FLOW_STOP_CHARGE)
{
//充电中枪连接断开
if(u8_gunLink == 0) //数据采集时有做防抖 所以在此直接使用;如需增加防抖时间 去采集处修改
{
FLOWCTRL_LOG("Gun link lost\n");
//互操枪连接断开、开关S断开不在此增加直流接触器断开都能过,在接地测试时过不去
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,0,0); //K1K2控制 控制k1k2断开 -- 故障停止、计时结束后立马控制k1k2断开
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13016, TIMER_0ms ); //停止流程 充电枪连接断开
}
}
//空闲时,直流输出接触器粘连故障检测
if(s_real_data->e_flow_state == E_FLOW_FREE)
{
}
//充电中故障状态检查
else if(s_real_data->e_flow_state == E_FLOW_CHARGE_RUNING) //充电
{
//充电限制条件达标检查 - 限制电量、限制SOC、限制时长等
switch (s_ctrl_data->e_sdk_chargMode)
{
case E_SDK_CHGMOD_MONEY: //限制金额,u32_limit_data 单位 0.01 元;计量为 0.0001 元
{
U32_T u32_used_money = ((U32_T)u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_METER_CHARGE, 1) << 16)
| (U32_T)u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_METER_CHARGE, 0);
U32_T u32_next_cyc = ((U32_T)u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_METER_CHARGE, 3) << 16)
| (U32_T)u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_METER_CHARGE, 2);
if (s_ctrl_data->u32_limit_data != 0
&& (U64_T)s_ctrl_data->u32_limit_data * 100u <= (U64_T)u32_used_money + (U64_T)u32_next_cyc)
{
v_flow_set_stop_charge(u8_gunNo, E_NORMAL_1005, TIMER_0ms ); //停止流程 达到限值金额
}
break;
}
case E_SDK_CHGMOD_ELE: //限制电量
{
if(s_ctrl_data->u32_limit_data != 0
&& s_ctrl_data->u32_limit_data*1000 <= u32_flow_put_data(u8_gunNo,E_FLOW_PUT_DATA_USED_ENERGY))//已充电量大于等于限值电量
{
v_flow_set_stop_charge(u8_gunNo, E_NORMAL_1004, TIMER_0ms ); //停止流程 达到限值电量
}
break;
}
case E_SDK_CHGMOD_SOC:
{
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_SOC,0); //获取车辆SOC
if(s_ctrl_data->u32_limit_data != 0 //SOC限值不为0
&& s_ctrl_data->u32_limit_data <= u16_data ) //车辆SOC大于等于SOC限值
{
v_flow_set_stop_charge(u8_gunNo, E_NORMAL_1007, TIMER_0ms ); //停止流程 达到SOC阈值
}
break;
}
case E_SDK_CHGMOD_TIME:
{
if(s_ctrl_data->u32_limit_data != 0 //时间限值不为0
&& s_ctrl_data->u32_limit_data <= u32_safe_seconds_since(s_log_data->u32_satrt_time)/60)//充电时间大于限值时间
{
v_flow_set_stop_charge(u8_gunNo, E_NORMAL_1003, TIMER_0ms ); //停止流程 达到时间限值
}
break;
}
default:
break;
}
//SOC阈值达标检查-- 此检查为充电系统设置SOC限制值,和充电下发的限值判断不一样
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_SOC,0); //获取车辆SOC
u16_data1 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_SOC_LIMIT,0); //获取设备SOC限值
if(u16_data != 0 && u16_data1 != 0 && u16_data >= u16_data1) //车辆SOC大于等于设备SOC的限值
{
u16_data2 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_TRICKLE_LIMIT,0); //获取涓流停机阈值
if(u16_data2 != 0 && u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_CUR,0) < u16_data2) //输出电流小于涓流限值
{
if(u32_safe_seconds_since(s_ctrl_data->s_over_time.u32_trickle_limit_time) > NUM_60) //处于该阶段一分钟
{
FLOWCTRL_LOG("Trickle stop, SOC_th=%d, I_trk_th=%d\n",u16_data1,u16_data2);
v_flow_set_stop_charge(u8_gunNo, E_NORMAL_1016, TIMER_0ms ); //停止流程 达到SOC阈值,涓流充电停机
}
}
else
{
s_ctrl_data->s_over_time.u32_trickle_limit_time = get_current_seconds(); //更新计算超时起始时间
FLOWCTRL_LOG("SOC stop, SOC=%d, th=%d\n",u16_data,u16_data1);
v_flow_set_stop_charge(u8_gunNo, E_NORMAL_1007, TIMER_0ms ); //停止流程 达到SOC阈值
}
}
else
{
s_ctrl_data->s_over_time.u32_trickle_limit_time = get_current_seconds(); //更新计算超时起始时间
}
//枪锁检查(仅国标枪,u8_gun_type 0欧标 1国标)
if (s_flow_data.u8_gun_type[u8_gunNo] != 0)
{
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUNLOCK_EN,0); //枪锁使能状态
u16_data1 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_LOCK,0); //充电枪电子锁状态
if(u16_data == 1 && u16_data1 == 0) //枪锁使能且充电枪电子锁解锁
{
FLOWCTRL_LOG("E-lock unlock in chg\n");
v_flow_set_fault_data(u8_gunNo+1,E_FAULT,E_FAULT_13010,1,0,0);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13010, TIMER_0ms ); //停止流程 枪锁异常解锁
}
}
//充电中检测到模块运行状态为空闲 3分钟
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_VOL,0); //电表采集电压
u16_data1 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_CUR,0); //电表采集电流
if(u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_MDU_WORK,0) == 0 //模块工作状态变为空闲
&& u16_data < 100 && u16_data1 < 100) //电表采集到的电压小于10V,电流小于10A
{
if(u32_safe_seconds_since(s_ctrl_data->s_over_time.u32_mdu_free_time) > 3*NUM_60) //3分钟延时
{
FLOWCTRL_LOG("MDU idle in chg\n");
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_FAULT, E_FAULT_13055, 1, 0, 0);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13055, TIMER_0ms ); //停止流程 充电中检测到模块运行状态为空闲
}
}
else
{
s_ctrl_data->s_over_time.u32_mdu_free_time = get_current_seconds();
}
//直流输出过压
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_VOL,0); //电表采集电压
u16_data1 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MAX_VOL,0) + 100;//充电机调压上限+10V
if(u16_data > u16_data1) //输出电压大于调压上限
{
if(u32_safe_seconds_since(s_ctrl_data->s_over_time.u32_over_vol_time) > NUM_5) //5S延时
{
FLOWCTRL_LOG("DC OVP\n");
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_FAULT, E_FAULT_13048, 1, u16_data, u16_data1);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13048, TIMER_0ms ); //停止流程 充电中检测到模块运行状态为空闲
}
}
else
{
s_ctrl_data->s_over_time.u32_over_vol_time = get_current_seconds();
}
//直流输出欠压
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_VOL,0); //电表采集电压
u16_data1 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MIN_VOL,0) - 100;//充电机调压下限-10V
if(s_log_data->u16_char_time > NUM_60 //充电开始1min 后开始判定
&& u16_data < u16_data1) //输出电压大于调压上限
{
if(u32_safe_seconds_since(s_ctrl_data->s_over_time.u32_under_vol_time) > NUM_5) //5S延时
{
FLOWCTRL_LOG("DC UVP: V=%dV, Vmin=%dV\n",u16_data,u16_data1);
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_FAULT, E_FAULT_13050, 1, u16_data, u16_data1);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13050, TIMER_0ms ); //停止流程 充电中检测到模块运行状态为空闲
}
}
else
{
s_ctrl_data->s_over_time.u32_under_vol_time = get_current_seconds();
}
//直流输出过压超过最高允许电压(互操输出电压超过车辆允许值测试,使用电表采集值和延时5S会导致K1K2及CST执行慢)
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_BUS_VOL,0); //电表采集电压(接触器内测电压)
u16_data1 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_MAX_VOL,0) + 100;//充电机调压上限+10V
if(u16_data > u16_data1) //输出电压大于最高允许电压
{
if(s_flow_data.u8_gb_en == 1 || u32_safe_seconds_since(s_ctrl_data->s_over_time.u32_over_max_vol_time) > NUM_5) //5S延时
{
FLOWCTRL_LOG("DC MAX_OVP\n");
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_FAULT, E_FAULT_15037, 1, u16_data, u16_data1);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15037, TIMER_0ms ); //停止流程 充电中检测到模块运行状态为空闲
}
}
else
{
s_ctrl_data->s_over_time.u32_over_max_vol_time = get_current_seconds();
}
//直流输出过流
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_CUR,0); //电表采集电流
u16_data1 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MAX_CUR,0) + 50;//充电机电流上限+5V
if(u32_safe_seconds_since(s_log_data->u32_satrt_time) > NUM_60 //充电开始1min 后开始判定
&& u16_data > u16_data1) //输出电压大于调压上限
{
if(u32_safe_seconds_since(s_ctrl_data->s_over_time.u32_over_curr_time) > NUM_5) //5S防抖延时
{
FLOWCTRL_LOG("DC OCP\n");
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_FAULT, E_FAULT_13049, 1, u16_data, u16_data1);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13049, TIMER_0ms ); //停止流程 充电中检测到模块运行状态为空闲
}
}
else
{
s_ctrl_data->s_over_time.u32_over_curr_time = get_current_seconds();
}
//直流输出大于需求
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_CUR,0); //电表采集电流
u16_data1 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_NEED_CUR,0) + 50;//车辆需求电流+5
if(u16_data1 != 0 &&u16_data > u16_data1) //采集电流大于车辆需求电流
{
if(u32_safe_seconds_since(s_ctrl_data->s_over_time.u32_over_needCur_time) > NUM_5) //5S延时
{
FLOWCTRL_LOG("DC out > req\n");
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_FAULT, E_FAULT_13054, 1, u16_data, u16_data1);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13054, TIMER_0ms ); //停止流程 充电中检测到模块运行状态为空闲
}
}
else
{
s_ctrl_data->s_over_time.u32_over_needCur_time = get_current_seconds();
}
//直流电流输出大于需求
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_CUR,0); //电表采集电流
u16_data1 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_NEED_CUR,0) + 50;//车辆需求电流
if(u16_data1 != 0 &&u16_data > u16_data1) //输出电压大于调压上限
{
if(u32_safe_seconds_since(s_ctrl_data->s_over_time.u32_over_needCur_time) > NUM_5) //5S延时
{
FLOWCTRL_LOG("DC out > req\n");
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_FAULT, E_FAULT_13054, 1, u16_data, u16_data1);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13054, TIMER_0ms ); //停止流程 充电中检测到模块运行状态为空闲
}
}
else
{
s_ctrl_data->s_over_time.u32_over_needCur_time = get_current_seconds();
}
//直流输出大于最高允许充电电流
u16_data = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_CUR,0); //电表采集电流
u16_data1 = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_MAX_CUR,0) + 50; //车辆最大允许充电电流
if(u16_data1 != 0 && u16_data > u16_data1) //输出流大于车辆最大允许充电电流
{
if(u32_safe_seconds_since(s_ctrl_data->s_over_time.u32_over_needCur_max_time) > NUM_5) //5S延时
{
FLOWCTRL_LOG("DC out > req\n");
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_FAULT, E_FAULT_13054, 1, u16_data, u16_data1);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13054, TIMER_0ms ); //停止流程 充电中检测到模块运行状态为空闲
}
}
else
{
s_ctrl_data->s_over_time.u32_over_needCur_max_time = get_current_seconds();
}
}
}
#endif
#if 1 //BMS状态跳转检查
/**
* ************************************************************************
* @brief - bms状态判断及处理
*
* @param[in] u8_gunNo - 抢号 0-N
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_bms_state_cheak(U8_T u8_gunNo)
{
//BMS 获取BMS状态 0无 1握手完成 2握手失败 3开始预充 4开始充电 5禁止充电 6停止充电 7报文接收超时
U8_T u8_state = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_STATE,0);
U16_T u16_bms_stop = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_STOP_RES,0); //BMS 停止原因 详看E_FAULT_INFO枚举内容 BMS部分
U16_T u16_bms_cem_send_cnt = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_BMS_CAN_SEND_CNT,0); //BMS 报文发送次数 参数值 0代表cem 1代表csd
U16_T u16_bms_reconn_flag = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_RECONN_FLAG,0); //BMS 重连标志 0不重连 1重连
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
static U8_T u8_state_old[GUN_MAX_CNT] = {0}; //上次状态值 用于判断状态变化
if(u8_state != u8_state_old[u8_gunNo]) //状态未变化 不执行
{
FLOWCTRL_LOG("[%d] BMS st chg: %d -> %d\n",u8_gunNo,u8_state_old[u8_gunNo],u8_state);
u8_state_old[u8_gunNo] = u8_state; //更新状态值
}
if(s_real_data->e_flow_state == E_FLOW_FREE ||
s_real_data->e_flow_state == E_FLOW_STOP_CHARGE || //已经停止就不再执行了
s_real_data->e_flow_state == E_FLOW_STOP_CHARGE_OK)
return;
if(u8_state == 0xFF) //0xFF表示锁申请失败
return;
if(s_real_data->u8_bms_suspend_flag && u8_state != 5)
s_real_data->u8_bms_suspend_flag = 0;
if(u8_state == 0)
{
//流程状态为 等待预充和停止充电之间,bms状态为空闲 则停止充电
if(s_real_data->e_flow_state >= E_FLOW_WAIT_PRE_CHARGE &&
s_real_data->e_flow_state < E_FLOW_STOP_CHARGE)
{
FLOWCTRL_LOG("Start: BMS idle stop, st=%d\n",s_real_data->e_flow_state);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15002, TIMER_NONE ); //停止流程 充电中bms状态空闲
}
}
else if(u8_state == 1) //握手完成
{
s_real_data->u8_bms_chm_flag = 1;
}
else if(u8_state == 2) //握手失败
{
s_real_data->u8_bms_chm_flag = 2;
}
else if(u8_state == 3) //开始预充
{
s_real_data->u8_bms_pre_flag = 1;
//s_real_data->u8_bms_renew_cnt = 0; //bms状态更新 说明重连通讯成功,重连次数清零
}
else if(u8_state == 4) //开始充电
{
s_real_data->u8_bms_charge_flag = 1;
}
else if(u8_state == 5) //禁止充电
{
s_real_data->u8_bms_suspend_flag = 1;
}
else if(u8_state == 6) //停止充电
{
if(s_real_data->u8_bms_stop_flag == 0) //未有停机原因且bms停止 则bms异常
{
s_real_data->u8_bms_stop_flag = 1;
v_flow_set_stop_charge(u8_gunNo, (E_FAULT_INFO)u16_bms_stop, TIMER_NONE ); //停止流程
}
}
else if(u8_state == 7) //报文接收超时
{
if(u16_bms_reconn_flag == 0) //报文超时不重连,直接停止充电
{
if(s_real_data->u8_bms_stop_flag == 0)
FLOWCTRL_LOG("RX timeout no reconn, stop\n");
s_real_data->u8_bms_stop_flag = 1;
if(u16_bms_stop == E_FAULT_NULL)
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15032, TIMER_NONE ); //停止流程 BRM 报文数据项异常
else
v_flow_set_stop_charge(u8_gunNo, (E_FAULT_INFO)u16_bms_stop, TIMER_NONE ); //停止流程
}
else if(s_real_data->u8_bms_renew_cnt < 4) //重连次数 小于3次 0 1 2 //修改为4原因是测试D0.4501项,原来3只会重连2次,故修改为4
{
s_real_data->u8_bms_charge_flag = 0; //bms标志清零
s_real_data->u8_bms_pre_flag = 0;
if(s_real_data->u8_bms_renew_ctrl == 0 &&
u16_bms_cem_send_cnt > 3 ) //CEM报文发送 3条以上
{
s_real_data->u8_bms_renew_ctrl = 1;
FLOWCTRL_LOG("BMS timeout, reconn #%d\n",s_real_data->u8_bms_renew_cnt);
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_BMS_TIMEOUT); //状态跳转到通讯超时
if( s_real_data->u8_bms_renew_cnt < 5)
s_real_data->u8_bms_renew_cnt++;
}
}
else
{
if(s_real_data->u8_bms_renew_cnt == 3)
FLOWCTRL_LOG("Reconn fail, stop, st=%d\n",s_real_data->e_flow_state);
if(u16_bms_stop == E_FAULT_NULL)
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15000, TIMER_NONE ); //停止流程 bms通讯超时
else
v_flow_set_stop_charge(u8_gunNo, (E_FAULT_INFO)u16_bms_stop, TIMER_1s ); //停止流程
s_real_data->u8_bms_renew_cnt = 0;//三次重连后将重连计数清0
}
}
else if(u8_state == 8) //数据错误 1s断接触器
{
v_flow_set_stop_charge(u8_gunNo,E_FAULT_15020 ,TIMER_100ms );
}
else
{
v_flow_set_stop_charge(u8_gunNo,E_FAULT_15000 ,TIMER_1s );
}
}
#endif
#if 1 //充电流程控制
/**
* ************************************************************************
* @brief -充电流程控制执行 空闲执行
* 检查枪锁解锁状态、检查插枪标志、检查启动标志、清空对外状态
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
static void v_flow_ctrl_free(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
U8_T u8_gunLink = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_LINK,0); //枪连接状态 0未连接 1已连接
if(s_ctrl_data->e_start_flag != 0) //获取启停状态
{
if(s_ctrl_data->e_start_flag == CTR_CMD_ONCARD_START) //在线卡启动
{
if(s_ctrl_data->u8_gunlock_cnt == 0)
{
v_flow_set_plat_vin_up(u8_gunNo); //只发一次
s_ctrl_data->u8_gunlock_cnt ++;
FLOWCTRL_LOG("Send plat auth\n");
}
U8_T u8_vin_res = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BS_VIN_RES,0); //VIN 鉴权结果 0wu 1成功 2平台鉴权超时 3非法VIN 4车辆识别鉴权帧超时 5即插即充鉴权失败 6鉴权VIN与车辆VIN不一致
if(u8_vin_res == 1) //鉴权成功
{
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_START_CHECK); //状态跳转到启动前检查
FLOWCTRL_LOG("Start chg, reason=%d\n",s_ctrl_data->e_start_flag);
s_ctrl_data->e_start_flag = CTR_CMD_NONE; //启动后清零
v_flow_log_info_ctrl(u8_gunNo,1); //充电订单控制
}
else if(u8_vin_res > 1) /* 平台/本地鉴权已给出失败(如 OCPP Invalid/Blocked → txFlag_autoRwsult=2) */
{
FLOWCTRL_LOG("Plat auth fail, res=%u gun=%u\n", (unsigned)u8_vin_res, (unsigned)u8_gunNo);
s_ctrl_data->e_start_flag = 0;
s_ctrl_data->u8_gunlock_cnt = 0;
s_real_data->ulong_flow_timer = 0;
v_flow_request_ui_idle_recover();
return;
}
else //鉴权中
{
//超时判断
if(s_real_data->ulong_flow_timer == 0) //未记录过时间 则记录当前时间
s_real_data->ulong_flow_timer = get_current_seconds();
if(u8_gunLink != 1 || u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_INSULATION) //30秒超时
{
FLOWCTRL_LOG("Plat auth wait TO gun=%u link=%u\n", (unsigned)u8_gunNo, (unsigned)u8_gunLink);
s_ctrl_data->e_start_flag = 0;
s_ctrl_data->u8_gunlock_cnt = 0;
s_real_data->ulong_flow_timer = 0;
v_flow_request_ui_idle_recover();
}
return;
}
}
else
{
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_START_CHECK); //状态跳转到启动前检查
FLOWCTRL_LOG("Start chg, reason=%d\n",s_ctrl_data->e_start_flag);
s_ctrl_data->e_start_flag = CTR_CMD_NONE; //启动后清零
v_flow_log_info_ctrl(u8_gunNo,1); //充电订单控制
}
}
else if(u8_gunLink == 1) //已插枪
{
if(s_real_data->e_flow_real_state == E_FLOW_REAL_STOP_OK) //插枪 且对外状态不是空闲 应为充电完成未拔枪
{
//清空状态
memset(s_real_data, 0 , sizeof(S_FLOW_REAL_DATA));
s_real_data->e_flow_real_state = E_FLOW_REAL_STOP_OK;
}
}
else
{
//清空状态
memset(s_real_data, 0 , sizeof(S_FLOW_REAL_DATA));
}
v_flow_free_gunlock_check(u8_gunNo); //枪锁状态检查 解枪锁
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 充电启动前检查执行
* 检查插枪状态、控制枪锁闭合并检查、控制辅源闭合并检查
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
static void v_flow_ctrl_start_check(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
U8_T u8_gunLink = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_LINK,0); //枪连接状态 0未连接 1已连接
U8_T u8_gunlock_en = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_GUNLOCK_EN,0); //枪锁使能 0不使能 1使能
U8_T u8_gunlock_st = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_LOCK,0); //枪锁状态 0未锁 1已锁
U8_T u8_auxPower_en = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_AUXPOWER_EN,0); //辅源状态检测使能
U8_T u8_auxPower_st = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_AUXPOWER,0); //辅源状态 0未闭合 1闭合
if(s_real_data->e_charge_state <= e_gunLink) //检查插枪状态
{
if(u8_gunLink == 1)
{
if ((s_flow_data.u8_gun_type[u8_gunNo] == 0)) /* 欧标 */
{
s_real_data->e_charge_state = e_wiat_bms_hand; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_START_CHECK_OK); //状态跳转到启动前检查
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_CHARGE_START); //对外状态跳转充电启动
}
else /* 国标 */
s_real_data->e_charge_state = e_gunlock; //详细状态跳转
FLOWCTRL_LOG("Gun link chk ok gun type =%d\n",s_flow_data.u8_gun_type[u8_gunNo]);
}
else
{
if(s_real_data->u16_anti_shake_cnt++ > TIMER_100ms) //100ms
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13041, TIMER_NONE ); //停止流程 枪连接失败
}
}
}
else if (!(s_flow_data.u8_gun_type[u8_gunNo] == 0) && s_real_data->e_charge_state == e_gunlock) //国标枪:检查枪锁状态
{
if(u8_gunlock_en && u8_gunlock_st == 0) //枪锁使能并且枪锁未连接
{
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) <= FLOW_TIMEOUT_GUNLOCK) //15秒内 一直尝试上锁
{
if((s_flow_data.u16_timer_cnt/NUM_1000) % 2 == 0 ) //2秒一次
{
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_GUN_LOCK,1,1); //枪锁上锁
}
else if((s_flow_data.u16_timer_cnt/NUM_1000) % 2 == 1 ) //2秒一次
{
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_GUN_LOCK,0,0); //枪锁解锁
}
}
else
{
if(s_flow_data.u8_gb_en == 1) //国标使能 枪锁失败停止充电
{
v_flow_set_stop_charge(u8_gunNo,E_FAULT_13010 ,TIMER_NONE ); //充电停止 枪锁失败
}
else //国标不使能 枪锁失败后也继续执行
{
s_real_data->e_charge_state = e_auxpower; //详细状态跳转
FLOWCTRL_LOG("GB disabled, skip gunlock\n");
}
}
}
else
{
s_real_data->e_charge_state = e_auxpower; //详细状态跳转
FLOWCTRL_LOG("Gunlock chk ok, en[%d]\n",u8_gunlock_en);
}
}
else if(s_real_data->e_charge_state == e_auxpower) //检查辅源控制
{
//辅源动作
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_AUXPOWER,1,1); //辅源闭合
//状态判断
if(s_flow_data.u8_gb_en == 1 && //国标不使能 不判断这个
(u8_auxPower_en && (u8_auxPower_st == 0))) //辅源状态使能,并且辅源状态未动作
{
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) <= FLOW_TIMEOUT_GUNLOCK)
{
if(s_flow_data.u16_timer_cnt % 2 == 0 ) //2秒一次
{
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_AUXPOWER,1,1); //辅源闭合
}
}
else
{
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_AUXPOWER,0,0); //辅源断开
v_flow_set_stop_charge(u8_gunNo,E_FAULT_13007 ,TIMER_NONE ); //充电停止 辅源动作失败
}
}
else
{
s_real_data->e_charge_state = e_wiat_bms_hand; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_START_CHECK_OK); //状态跳转到启动前检查
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_CHARGE_START); //对外状态跳转充电启动
FLOWCTRL_LOG("Aux pwr chk ok\n");
}
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 充电启动前检查完成执行
* 等待BHM报文接收 并获取赋值绝缘电压值、检查电池测电压小于标准范围,可进行绝缘监测
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
static void v_flow_ctrl_start_check_ok(U8_T u8_gunNo)
{
U8_T u8_bms_chm_ok = 0;
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
U16_T u16_gun_max_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MAX_VOL,0); //充电枪最大数据电压值 精度 0.1V
U16_T u16_gun_min_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MIN_VOL,0); //充电枪最小数据电压值 精度 0.1V
U16_T u16_gun_min_cur = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MIN_CUR,0); //充电枪最小数据电流值 精度 0.1V
U16_T u16_bms_max_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_MAX_VOL,0); //BMS 最大充电电压值 精度 0.1V
U16_T u16_batt_adc_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_BATT_ADC_VOL,0); //电池外侧采集电压 精度 0.1V
U16_T u16_bms_ver = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_GB_VER,0); //BMS 国标协议版本 0 2011版 1 2015版
U16_T u16_bus_km = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_BUS_KM,0); //母联接触器状态
//BMS状态检查
if(s_real_data->u8_bms_chm_flag == 1) //bms状态准备就绪 握手成功
{
if(u16_bms_max_vol > u16_gun_max_vol) //检查bms值和充电桩最大电压值
{
//互操测试:BMS最高允许电压超出桩上限时,不允许进入充电流程
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15045, TIMER_NONE);
FLOWCTRL_LOG("15045 BMSmax>%d, bms=%d\n", u16_gun_max_vol, u16_bms_max_vol);
}
else
s_real_data->u16_need_vol = u16_bms_max_vol - NUM_50; //BMS最大允许输出电压 - 5V
s_real_data->u16_need_cur = u16_gun_min_cur; //系统最小输出电流
s_real_data->e_charge_state = e_check_bms_vol; //详细状态跳转
u8_bms_chm_ok = 1;
}
else if (!(s_flow_data.u8_gun_type[u8_gunNo] == 0) && s_real_data->u8_bms_chm_flag == 2) //国标:bms状态准备就绪 握手失败
{
s_real_data->u16_need_vol = u16_gun_max_vol - NUM_50; //充电柱最大输出电压 - 5V
s_real_data->u16_need_cur = u16_gun_min_cur; //充电桩最小输出电流
s_real_data->e_charge_state = e_check_bms_vol; //详细状态跳转
u8_bms_chm_ok = 1; //使能标志
}
//绝缘前电池电压检测
if(u8_bms_chm_ok == 1)
{
if(s_real_data->u16_need_vol >= u16_gun_min_vol) //如果车辆最高允许电压比充电桩最小输出电压大 则正常执行 否则停止充电
{
s_real_data->e_charge_state = e_battvol_check; //详细状态跳转
if(u16_batt_adc_vol > s_flow_data.u16_insul_before_vol) //外侧电池电压 大于标准
{
if(s_real_data->u16_anti_shake_cnt++ > TIMER_100ms) //100ms
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15034, TIMER_NONE ); //停止流程 电池测电压大于标准
FLOWCTRL_LOG("Batt adcV high=%d\n",u16_batt_adc_vol);
}
}
else
{
if( u16_bus_km == 0 ) //母联接触器断开才运行执行以下流程,
{
if(u16_bms_ver >= 1) //2015版国标 控制闭合--非2011版本 都闭合接触器做绝缘
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,1,1); //K1K2控制 控制k1k2闭合
s_real_data->e_charge_state = e_insulmdu_check; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_INSUL_BEFORE); //状态跳转到启动前检查
FLOWCTRL_LOG("K1K2 on, INS start, Vins=%d\n",s_real_data->u16_need_vol);
}
}
}
else
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15036, TIMER_NONE ); //停止流程 车辆最大电压小于充电桩最小
}
}
if ((s_flow_data.u8_gun_type[u8_gunNo] == 0)) /* 欧标:超时判断 */
{
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= 60*2) //按照欧标PLC流程 此状态下最多2分钟左右 一直到BROAA接收到
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15018, TIMER_NONE ); //停止流程 状态跳转失败 理论上不会走到这 赋值 15018 BSM 报文中动力蓄电池绝缘状态异常
}
}
else /* 国标:超时判断 */
{
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_PCM_STATE) //30秒绝缘电压还未输出稳定
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15018, TIMER_NONE ); //停止流程 状态跳转失败 理论上不会走到这 赋值 15018 BSM 报文中动力蓄电池绝缘状态异常
}
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 绝缘监测前执行
* 判断模块是否为运行状态、判断模块输出电压是否达到绝缘电压、30秒未达标超时判断
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
static void v_flow_ctrl_insul_before(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
U16_T u16_mdu_state = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_MDU_WORK,0); //获取模块运行状态 0空闲 1工作
U16_T u16_bus_vol = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_GUN_BUS_VOL,0); //充电枪接触器内侧电压值 精度 0.1V
U16_T u16_batt_adc_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_BATT_ADC_VOL,0); //电池外侧采集电压 精度 0.1V
U16_T u16_mdu_put_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_MDU_PUT_VOL,0); //获取模块输出电压值 精度0.1V
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_INSUL_START); //对外状态跳转绝缘开始
if(u16_mdu_state == 1) //模块状态变为工作
{
s_real_data->e_charge_state = e_insulvol_check; //详细状态跳转
if((abs((int)s_real_data->u16_need_vol - u16_bus_vol) < (int)s_flow_data.u16_insul_putvol_range) || //接触器内侧采集电压 达到绝缘电压值
(abs((int)s_real_data->u16_need_vol - u16_mdu_put_vol) < (int)s_flow_data.u16_insul_putvol_range) || //模块上送输出电压 达到绝缘电压值
(abs((int)s_real_data->u16_need_vol - u16_batt_adc_vol) < (int)s_flow_data.u16_insul_putvol_range) ) //电池测采集电压 达到绝缘电压值
{
s_real_data->e_charge_state = e_insul_ing_ok; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_INSUL_RUNING); //状态跳转到启动前检查
v_flow_gun_insulation_data_ctrl(u8_gunNo,0); //闭合绝缘监测对地-- 绝缘监测前调用 -- 常规流程是闭合大地再启动解决
FLOWCTRL_LOG("INS V ok: %d(adc_in) %d(mdu) %d(adc_out)\n",u16_bus_vol,u16_mdu_put_vol,u16_batt_adc_vol);
}
else if(s_flow_data.u8_gb_en == 0 && //国标不使能 且超时时间为15秒
u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_INSULATION/2)
{
s_real_data->e_charge_state = e_insul_ing_ok; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_INSUL_RUNING); //状态跳转到启动前检查
v_flow_gun_insulation_data_ctrl(u8_gunNo,0); //闭合绝缘监测对地-- 绝缘监测前调用
FLOWCTRL_LOG("15s skip V chk: need=%d adc=%d mdu=%d\n",s_real_data->u16_need_vol,u16_bus_vol,u16_mdu_put_vol);
}
}
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_INSULATION *2) //30秒绝缘电压还未输出稳定 //测试主机启动太慢
{
if(u16_mdu_state == 1) //模块在工作 则是绝缘电压未检测到
v_flow_set_stop_charge(u8_gunNo, E_FAULT_14036, TIMER_NONE ); //停止流程 绝缘电压未输出到位
else
v_flow_set_stop_charge(u8_gunNo, E_FAULT_14020, TIMER_NONE ); //停止流程 模块一直未启动
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 绝缘监测中执行
* 调用绝缘监测执行函数-等待返回绝缘监测结果、30秒绝缘超时判断
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
static void v_flow_ctrl_insul_runing(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
S8_T s8_data = s8_flow_gun_insulation(u8_gunNo,&s_real_data->u32_insul_Rx,&s_real_data->u32_insul_Ry);
if(s8_data >= 0) //绝缘检测完成
{
s_real_data->e_charge_state = e_insul_mdu_stop; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_INSUL_OK); //状态跳转到绝缘检查完成
s_real_data->u8_insul_ret = (U8_T)s8_data;
FLOWCTRL_LOG("INS res=%d(0F,1OK,2WARN), R+=%d(0.1ohm), R-=%d(0.1ohm)\n",s8_data,s_real_data->u32_insul_Rx,s_real_data->u32_insul_Ry);
}
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_INSULATION) //30秒绝缘超时
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15019, TIMER_NONE ); //停止流程 绝缘检测失败 理论上不会走到这 赋值 15019 BSM 报文中连接器连接状态异
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 绝缘监测完成执行
* 检查模块停止 或者电压下降到标准范围内、执行泄放并检查成功结果、
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
static void v_flow_ctrl_insul_ok(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
U16_T u16_mdu_state = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_MDU_WORK,0); //获取模块运行状态 0空闲 1工作
U16_T u16_bus_vol = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_GUN_BUS_VOL,0); //充电枪接触器内侧电压值 精度 0.1V
U16_T u16_batt_adc_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_BATT_ADC_VOL,0); //电池外侧采集电压 精度 0.1V
U16_T u16_mdu_put_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_MDU_PUT_VOL,0); //获取模块输出电压值 精度0.1V
U16_T u16_bms_ver = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_GB_VER,0); //BMS 国标协议版本 0 2011版 1 2015版
S8_T s8_relief_res; //泄放结果
U8_T u8_vol_down_ok = 0; //电压下降成功标志
//设置需求电压电流为0
s_real_data->u16_need_vol = 0;
s_real_data->u16_need_cur = 0;
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_INSUL_OK); //对外状态跳转绝缘计算完成
//检查模块停止状态 并投切泄放
if(u16_mdu_state == 0 && //模块状态变为空闲
(u16_bus_vol < s_flow_data.u16_insul_before_vol || u16_mdu_put_vol < s_flow_data.u16_insul_before_vol)) //模块上送电压 或者 adc采样电压小于100V
{
s_real_data->e_charge_state = e_insul_relief; //详细状态跳转
s8_relief_res = s8_flow_volt_relief_do(u8_gunNo);
if(s8_relief_res == 1)
u8_vol_down_ok = 1; //进行下一步
else if(s8_relief_res == 0)
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13047, TIMER_NONE ); //停止流程 泄放失败
}
//绝缘检测结果检查
if(u8_vol_down_ok == 1)
{
//s_real_data->u8_insul_ret = 1; //测试 屏蔽绝缘
if(s_real_data->u8_insul_ret == 0) //绝缘检查失败
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13042, TIMER_NONE ); //停止流程 绝缘检测失败
}
else
{
if(s_real_data->u8_insul_ret == 2) //绝缘告警 告警标志置一
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_WARN, E_FAULT_13043, 1, s_real_data->u32_insul_Rx, s_real_data->u32_insul_Ry); //绝缘检查告警 拔枪恢复
s_real_data->e_charge_state = e_wiat_bms_pre; //详细状态跳转
v_flow_gun_insulation_data_ctrl(u8_gunNo,1); //控制断开绝缘检测对地-绝缘监测结束后执行
if(u16_bms_ver >= 1) //2015版国标 控制断开
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,0,0); //控制k1k2断开
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_WAIT_PRE_CHARGE); //状态跳转到等待预充
}
}
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_PCM_STATE) //15秒 模块未停止
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_14021, TIMER_NONE ); //停止流程 绝缘检测模块停止失败
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 等待预充执行
* 等待BMS状态 变为开始预充,跳转状态 70秒超时判断
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_ctrl_wait_pre_charge(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_INSUL_MDU_STOP); //对外状态跳转绝缘模块停止完成
if ((s_flow_data.u8_gun_type[u8_gunNo] == 0)) /* 欧标:不用等待预充 */
{
s_real_data->e_charge_state = e_wiat_batt_vol; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_PRE_CHARGE_RUNING); //状态跳转到 预充中;跳过预充前检查
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,1,1); //K1K2控制 控制k1k2闭合
}
else /* 国标 */
{
if(s_real_data->u8_bms_pre_flag == 1) //bms开始预充
{
s_real_data->e_charge_state = e_wiat_batt_vol; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_PRE_CHARGE_BEFORE); //状态跳转到等待预充
}
}
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_PRECHARGE+10) //60+10秒
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15012, TIMER_NONE ); //停止流程 等待BMS状态超时 理论上不会走到这 赋值15012 BSM 报文中单体动力蓄电池电压过高
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 预充前准备执行
* 判断电池测电压 是否输出到位,是否在充电桩输出范围内、判断电池车电压与BMS发送电压是否误差在5%以内、判断平台即插即充鉴权结果、60秒超时判断
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_ctrl_pre_charge_before(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
U16_T u16_bms_batt_vol = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_BMS_REAL_BATT_VOL,0); //BMS 当前电池电压值 精度 0.1V
U16_T u16_batt_adc_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_BATT_ADC_VOL,0); //电池外侧采集电压 精度 0.1V
U16_T u16_gun_max_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MAX_VOL,0); //充电枪最大数据电压值 精度 0.1V
U16_T u16_gun_min_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MIN_VOL,0); //充电枪最小数据电压值 精度 0.1V
U16_T u16_gun_min_cur = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MIN_CUR,0); //充电枪最小数据电流值 精度 0.1V
U16_T u16_bms_max_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_MAX_VOL,0); //BMS 最大充电电压值 精度 0.1V
U16_T u16_bms_ver = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_GB_VER,0); //BMS 国标协议版本 0 2011版 1 2015版
U8_T u8_vol_err = 0;
if(TEST_FLOW_NO_DCU == 1) u16_batt_adc_vol = u16_bms_batt_vol; //无DCU adc采样时,电池测电压值 直接使用BMS值 模拟测试
//电池测电压与标准对比
if((u16_bms_ver >= 1) && //非2011版国标 判断
(u16_batt_adc_vol > u16_bms_max_vol || //bms最大允许充电电压)
u16_batt_adc_vol > u16_gun_max_vol || //大于充电桩最大输出电压
u16_batt_adc_vol < u16_gun_min_vol )) //小于充电桩最小输出电压
{
if(s_real_data->u16_anti_shake_cnt > TIMER_30s) //持续30秒不符合,走停止流程
{
if(u16_batt_adc_vol > u16_bms_max_vol) //bms最大允许充电电压)
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15045, TIMER_NONE ); //停止流程
FLOWCTRL_LOG("15045= %d ,%d\n",u16_batt_adc_vol,u16_bms_max_vol);
}
else if(u16_batt_adc_vol > u16_gun_max_vol ) //大于充电桩最大输出电压
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_14037, TIMER_NONE ); //停止流程
FLOWCTRL_LOG("14037= %d ,%d\n",u16_batt_adc_vol,u16_gun_max_vol);
}
else if(u16_batt_adc_vol < u16_gun_min_vol ) //小于充电桩最小输出电压
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_14038, TIMER_NONE ); //停止流程
FLOWCTRL_LOG("14038= %d ,%d\n",u16_batt_adc_vol,u16_gun_min_vol);
}
}
u8_vol_err = 1;
}
else
{
s_real_data->u16_anti_shake_cnt = 0; //计时清零
u8_vol_err = 0;
}
//电池测电压 与bms车辆当前电池电压判定
if(u8_vol_err == 0 &&
((u16_bms_ver == 0) || //一级 国标不使能,或者
(u16_bms_batt_vol != 0 && //二级 bms电池测电压不为零,并且
((F32_T)abs(u16_bms_batt_vol - u16_batt_adc_vol)) /(F32_T)u16_bms_batt_vol < 0.05f))) //二级 直流输出接触器外侧电压与通信报文电池电压相差+、—5%
{
if((s_flow_data.u8_gb_en == 0) || s_real_data->u16_anti_shake_cnt2 > TIMER_1s) //1s
{
//GBT 34657-2017 DN2007/DN2008,需要测试5S内未准备就绪报BRO-0xAA超时,此时需发送CRO_0x00
if((s_flow_data.u8_gb_en == 0) || u32_safe_seconds_since(s_real_data->ulong_flow_timer) > 6)
{
s_real_data->e_charge_state = e_wiat_pre_mdu; //详细状态跳转
s_real_data->u16_need_vol = u16_batt_adc_vol; //电池测电压
s_real_data->u16_need_cur = u16_gun_min_cur; //最小电流
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_PRE_CHARGE_RUNING); //状态跳转到预充
FLOWCTRL_LOG("Prechk ok, prechg start: adc=%d(0.1V), bms=%d(0.1V)\n",u16_batt_adc_vol ,u16_bms_batt_vol);
}
}
}
else
{
s_real_data->u16_anti_shake_cnt2 = 0; //临时变量清零
}
//vin返回结果判断
if(s_real_data->e_start_reason == CtR_CMD_VIN_START) //如果是vin启动,判断鉴权失败
{
U8_T u8_vin_res = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BS_VIN_RES,0); //VIN 鉴权结果 0wu 1成功 2平台鉴权超时 3非法VIN 4车辆识别鉴权帧超时 5即插即充鉴权失败 6鉴权VIN与车辆VIN不一致
if(u8_vin_res >= 2) //鉴权失败
{
v_flow_vin_fail_stop(u8_gunNo,u8_vin_res); //vin鉴权失败执行
}
}
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_PRECHARGE) //60秒
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15035, TIMER_NONE ); //停止流程 接触器外侧电压
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 预充中执行
* 设置需求电压值、等待模块状态启动、判断预充电压输出是否达标、判断平台即插即充鉴权结果、60秒超时判断
*
* @param[in] u8_gunNo - 枪号 0-N
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_ctrl_pre_charge_runing(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
U16_T u16_mdu_state = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_MDU_WORK,0); //获取模块运行状态 0空闲 1工作
U16_T u16_bms_batt_vol = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_BMS_REAL_BATT_VOL,0); //BMS 当前电池电压值 精度 0.1V
U16_T u16_batt_adc_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_BATT_ADC_VOL,0); //电池外侧采集电压 精度 0.1V
U16_T u16_bus_vol = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_GUN_BUS_VOL,0); //充电枪接触器内侧电压值 精度 0.1V
U16_T u16_mdu_put_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_MDU_PUT_VOL,0); //获取模块输出电压值 精度0.1V
U16_T u16_gun_min_cur = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MIN_CUR,0); //充电枪最小数据电流值 精度 0.1V
U16_T u16_bms_ver = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_GB_VER,0); //BMS 国标协议版本 0 2011版 1 2015版
if ((s_flow_data.u8_gun_type[u8_gunNo] == 0)) /* 欧标:不用等待预充 */
{
U16_T u16_bms_need_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_NEED_VOL,0); //BMS 需求电压值 精度 0.1V
//设置预充电压
s_real_data->u16_need_vol = u16_bms_need_vol; //获取BCL需求电压
s_real_data->u16_need_cur = u16_gun_min_cur; //最小电流
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_PRE_START); //对外状态跳转开始预充
//等待模块状态变为工作
if(u16_mdu_state == 1)
{
s_real_data->e_charge_state = e_wiat_pre_vol; //详细状态跳转
if(abs(u16_bms_need_vol - u16_bus_vol) <= s_flow_data.u16_insul_putvol_range ||
abs(u16_bms_need_vol - u16_mdu_put_vol )<= s_flow_data.u16_insul_putvol_range)
{
s_real_data->e_charge_state = e_wiat_bms_change; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_PRE_CHARGE_OK); //状态跳转到预充完成
FLOWCTRL_LOG("EB preV ok[%d], V=%d,%d\n",u16_mdu_state,u16_batt_adc_vol,u16_bus_vol);
}
}
else
{
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_INSULATION) //15秒
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_14020, TIMER_NONE ); //停止流程 预充启动模块失败
}
}
}
else /* 国标 */
{
//设置预充电压
s_real_data->u16_need_vol = u16_bms_batt_vol; //获取电池当前电压 bms值
s_real_data->u16_need_cur = u16_gun_min_cur; //最小电流
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_PRE_START); //对外状态跳转开始预充
//等待模块状态变为工作
if(u16_mdu_state == 1)
{
s_real_data->e_charge_state = e_wiat_pre_vol; //详细状态跳转
if((u16_bms_ver == 0) || //2011版国标 直接通过
abs(u16_batt_adc_vol - u16_bus_vol) <= s_flow_data.u16_insul_putvol_range ||
abs(u16_batt_adc_vol - u16_mdu_put_vol )<= s_flow_data.u16_insul_putvol_range)
{
s_real_data->e_charge_state = e_wiat_bms_change; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_PRE_CHARGE_OK); //状态跳转到预充完成
FLOWCTRL_LOG("GB preV ok[%d], V=%d,%d\n",u16_mdu_state,u16_batt_adc_vol,u16_bus_vol);
}
}
else
{
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_INSULATION) //15秒
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_14020, TIMER_NONE ); //停止流程 预充启动模块失败
}
}
}
//vin返回结果判断
if(s_real_data->e_start_reason == CtR_CMD_VIN_START) //如果是vin启动,判断鉴权失败
{
U8_T u8_vin_res = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BS_VIN_RES,0); //VIN 鉴权结果 0wu 1成功 2平台鉴权超时 3非法VIN 4车辆识别鉴权帧超时 5即插即充鉴权失败 6鉴权VIN与车辆VIN不一致
if(u8_vin_res >= 2) //鉴权失败
{
v_flow_vin_fail_stop(u8_gunNo,u8_vin_res); //vin鉴权失败执行
}
}
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_PRECHARGE) //60秒
{
FLOWCTRL_LOG("Prechg TO: batt=%d, bus=%d\n",u16_batt_adc_vol,u16_bus_vol);
if(abs(u16_batt_adc_vol - s_real_data->u16_need_vol) > s_flow_data.u16_insul_putvol_range) //电池测电压不达标
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_15035, TIMER_NONE ); //停止流程 预充电压未启动到位
}
else //模块输出电压不达标
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13053, TIMER_NONE ); //停止流程 预充电压未启动到位
}
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 预充完成执行
* 判断VIN平台鉴权返回结果、等待BMS状态变为充电中、30秒超时判断
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_ctrl_pre_charge_ok(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
U8_T u8_vin_res_ok = 0;
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_PRE_OK); //对外状态跳转开始预充完成
//vin返回结果判断
if(s_real_data->e_start_reason == CtR_CMD_VIN_START) //如果是vin启动,判断鉴权失败
{
U8_T u8_vin_res = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BS_VIN_RES,0); //VIN 鉴权结果 0wu 1成功 2平台鉴权超时 3非法VIN 4车辆识别鉴权帧超时 5即插即充鉴权失败 6鉴权VIN与车辆VIN不一致
if(u8_vin_res >= 2) //鉴权失败
{
v_flow_vin_fail_stop(u8_gunNo,u8_vin_res); //vin鉴权失败执行
}
else if(u8_vin_res == 1)
{
u8_vin_res_ok = 1;
}
else //还未鉴权
{
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_VOLT)
{
FLOWCTRL_LOG("Prechg ok, VIN auth TO\n");
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13067, TIMER_NONE ); //停止流程 车辆失败鉴权超时
}
}
}
else
{
u8_vin_res_ok = 1;
}
//等待bms状态变为充电中
if(u8_vin_res_ok == 1 && s_real_data->u8_bms_charge_flag == 1)
{
s_real_data->e_charge_state = e_change; //详细状态跳转
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,1,1); //K1K2控制 控制k1k2闭合
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_CHARGE_RUNING); //状态跳转到充电中
FLOWCTRL_LOG("BMS ready, enter chg...\n");
}
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_INSULATION) //10秒
{
FLOWCTRL_LOG("13090 %d %d\n",u8_vin_res_ok,s_real_data->u8_bms_charge_flag);
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13090, TIMER_NONE ); //停止流程 等待BMS状态超时 理论上不会走到这
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 充电中执行
* 设置需求电压、需求电流值; 监听BMS暂停充电状态;周期打印实时充电数据
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_ctrl_charge_runing(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
U16_T u16_bms_need_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_NEED_VOL,0); //BMS 需求电压值 精度 0.1V
U16_T u16_bms_need_cur = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_NEED_CUR,0); //BMS 需求电流值 精度 0.1V
U16_T u16_meter_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_VOL,0); //电表采集电压 精度0.1V
U16_T u16_meter_cur = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_CUR,0); //电表采集电流 精度0.1V
//设置电压电流
s_real_data->u16_need_vol = u16_bms_need_vol; //获取bms需求电压 精度0.1V
s_real_data->u16_need_cur = u16_bms_need_cur; //获取bms需求电流 精度0.1A
v_flow_check_gun_power_limit(u8_gunNo,&s_real_data->u16_need_vol,&s_real_data->u16_need_cur); //充电枪限制功率检查
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_CHARGEING); //对外状态跳转充电中
v_flow_log_info_ctrl(u8_gunNo,2); //充电中 计算充电时间
v_flow_log_info_updata(u8_gunNo); //充电中,更新log中充电电量与充电金额
//监听bms停止充电状态
if(s_real_data->u8_bms_suspend_flag == 1)
{
s_real_data->e_charge_state = e_change_suspend; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_CHARGE_SUSPEND); //状态跳转到充电暂停
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,0,0); //K1K2控制 控制k1k2断开
FLOWCTRL_LOG("Chg suspend...\n");
}
//周期打印实时充电数据
if((s_flow_data.u16_timer_cnt % TIMER_30s) == 0) //30秒打印
{
FLOWCTRL_LOG("[%d]gun need vol= %d , need cur= %d \n",u8_gunNo,u16_bms_need_vol,u16_bms_need_cur);
FLOWCTRL_LOG("out vol= %d , out cur= %d \n",u16_meter_vol,u16_meter_cur);
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 充电暂停执行
* 设置需求电压、电流值 、 监听BMS充电暂停恢复、 周期打印、10分钟超时判定
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_ctrl_charge_suspend(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
U16_T u16_bms_need_vol = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_BMS_NEED_VOL,0); //BMS 需求电压值 精度 0.1V
U16_T u16_gun_min_cur = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MIN_CUR,0); //充电枪最小数据电流值 精度 0.1V
//设置需求值
s_real_data->u16_need_vol = u16_bms_need_vol; //获取bms需求电压
s_real_data->u16_need_cur = u16_gun_min_cur; //获取bms需求电流
v_flow_log_info_ctrl(u8_gunNo,2); //充电中 计算充电时间
//监听bms停止充电恢复
if(s_real_data->u8_bms_suspend_flag == 0)
{
s_real_data->e_charge_state = e_change; //详细状态跳转
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_CHARGE_RUNING); //状态跳转到充电中
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,1,1); //K1K2控制 控制k1k2闭合
FLOWCTRL_LOG("Chg resume...\n");
}
//周期打印实时充电数据
if((s_flow_data.u16_timer_cnt % TIMER_30s) == 0) //30秒打印
{
FLOWCTRL_LOG("Suspend t=%d\n",u32_safe_seconds_since(s_real_data->ulong_flow_timer));
}
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_CHANGE_STOPTIME) //50*10秒
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13068, TIMER_NONE ); //停止流程 充电暂停10分钟
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 充电中BMS通信超时 重连执行
* 设置需求值为0,赋值通讯中断告警, 对外状态跳转到通信超时、等待模块空闲且电流下降到标准值或10秒后,断开k1k2跳转等待预充状态、30秒超时判断
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_ctrl_bms_timeout(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
U16_T u16_mdu_state = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_MDU_WORK,0); //获取模块运行状态 0空闲 1工作
U16_T u16_meter_cur = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_CUR,0); //电表采集电流 精度0.1V
U16_T u16_gun_min_cur = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MIN_CUR,0); //充电枪最小数据电流值 精度 0.1V
//设置电压电流
s_real_data->u16_need_vol = 0;
s_real_data->u16_need_cur = 0;
//通讯中断告警
if(u16_flow_get_sys_data(u8_gunNo+1,E_FLOW_GET_DATA_FAULT_FLAG,E_FAULT_15000) == 0) //获取故障内容存在标志 0不存在 1存在;需要传入 故障代码参数)
{
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_WARN, E_FAULT_15000, 1, 0, 0);
}
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_BMS_OUTTIME); //对外状态跳转bms通讯超时
//等待模块状态变为空闲 并且电流降下或者到达10秒
if(u16_mdu_state== 0 &&
(u16_meter_cur <= u16_gun_min_cur ||
u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= NUM_10 ))
{
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_WAIT_PRE_CHARGE); //状态跳转到等待预充
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,0,0); //K1K2控制 控制k1k2断开
//通讯中断告警恢复
if(u16_flow_get_sys_data(u8_gunNo+1,E_FLOW_GET_DATA_FAULT_FLAG,E_FAULT_15000) == 1) //获取故障内容存在标志 0不存在 1存在;需要传入 故障代码参数)
{
v_flow_set_fault_data((E_FAULT_SITE)(u8_gunNo + 1), E_RES, E_FAULT_15000, 0, 0, 0);
}
}
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_INSULATION) //15秒
{
v_flow_set_stop_charge(u8_gunNo, E_FAULT_14021, TIMER_NONE ); //停止流程 重连停模块失败
FLOWCTRL_LOG("TO stop mdu[%d] cur[%d]",u16_mdu_state,u16_meter_cur);
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 充电停止执行
* 清空需求值,对外状态跳转为停止充电,异常停止时计数值清零立马断开k1k2继电器,等待模块输出空闲且电流下降到标准值,投泄放、跳转状态,或者15秒超时强制跳转状态
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_set_stop_charge_runing(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
U16_T u16_mdu_state = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_MDU_WORK,0); //获取模块运行状态 0空闲 1工作
U16_T u16_meter_cur = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_METER_CUR,0); //电表采集电流 精度0.1V
U16_T u16_gun_min_cur = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_MIN_CUR,0); //充电枪最小数据电流值 精度 0.1V
S8_T s8_relief_res;
U8_T u8_vol_down_ok = 0;
//设置电压电流
s_real_data->u16_need_vol = 0;
s_real_data->u16_need_cur = 0;
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_STOP); //对外状态跳转充电停止停止
//异常停止判断
if(s_ctrl_data->s16_fault_stop_cnt == 0) //异常停止时 故障计数赋计数值,累减至0后 断开k1k2接触器
{
s_ctrl_data->s16_fault_stop_cnt -- ;
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,0,0); //K1K2控制 控制k1k2断开 -- 故障停止、计时结束后立马控制k1k2断开
FLOWCTRL_LOG("Abn stop, K1K2 off\n");
}
//正常流程 - 等待模块输出停止后,断开k1k2 投泄放
if(u16_mdu_state == 0 && //模块状态为停止
u16_meter_cur <= u16_gun_min_cur) //输出电流降下
{
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,0,0); //K1K2控制 控制k1k2断开 --
s8_relief_res = s8_flow_volt_relief_do(u8_gunNo);
if(s8_relief_res == 1)
{
u8_vol_down_ok = 1; //进行下一步
FLOWCTRL_LOG("MDU stop, dischg ok\n");
}
else if(s8_relief_res == 0)
v_flow_set_stop_charge(u8_gunNo, E_FAULT_13047, TIMER_NONE ); //停止流程 泄放失败
}
//超时判断
if(u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_PCM_STATE) //15秒
{
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,0,0); //K1K2控制 控制k1k2断开 --
u8_vol_down_ok = 1; //进行下一步
}
//检查执行完成
if(u8_vol_down_ok == 1)
{
FLOWCTRL_LOG("Stop done\n");
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_STOP_CHARGE_OK); //状态跳转到停止充电完成
}
}
/**
* ************************************************************************
* @brief - 充电流程控制执行 充电停止完成执行
* 等待csd报文发送10帧以上后 断开辅源;断开所有控制开关 跳转到空闲状态
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-04
* ************************************************************************
*/
static void v_flow_set_stop_charge_ok(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
U16_T u16_bms_csd_send_cnt = u16_flow_get_sys_data(u8_gunNo, E_FLOW_GET_DATA_BMS_CAN_SEND_CNT,1); //BMS 报文发送次数 参数值 0代表cem 1代表csd
U8_T u8_ctrl_ok = 0;
if( (u16_bms_csd_send_cnt > 3 || //csd发送次数超过3条
u32_safe_seconds_since(s_real_data->ulong_flow_timer) >= FLOW_TIMEOUT_PCM_STATE)) //15秒
{
//辅源动作
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_AUXPOWER,0,0); //断辅源
v_flow_real_state_change(u8_gunNo,E_FLOW_REAL_STOP_OK); //对外状态跳转停止完成
u8_ctrl_ok = 1;
}
if(u8_ctrl_ok == 1) //接枪锁 等待拔枪--直接恢复至空闲状态,不把枪也能启动
{
//空闲时检查枪锁状态
v_flow_free_gunlock_check(u8_gunNo);
//拔枪前所有控制都断一下 、 以防万一
v_flow_gun_insulation_data_ctrl(u8_gunNo,1);
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_AUXPOWER,0,0); //断辅源
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_GUN_LOCK,0,0); //断枪锁
u16_flow_put_ctrl(u8_gunNo,E_FLOW_CTRL_DATA_K1K2,0,0); //断直流接触器
v_flow_gun_volt_relief_free(u8_gunNo ,1); //关闭gunNo枪泄放电路
FLOWCTRL_LOG("Back to idle, thx!\n");
v_flow_ctrl_state_change(u8_gunNo,E_FLOW_FREE); //状态跳转到空闲
s_ctrl_data->e_start_flag = CTR_CMD_NONE; //启动后清零
v_flow_log_info_ctrl(u8_gunNo,0); //充电订单控制
}
}
void v_flow_control(U8_T u8_gunNo)
{
S_FLOW_REAL_DATA *s_real_data = &s_flow_data.s_real_data[u8_gunNo]; //实时数据指针
S_FLOW_CTRL_DATA *s_ctrl_data = &s_flow_data.s_ctrl_data[u8_gunNo]; //充电控制数据
(void)s_ctrl_data;
v_flow_stop_fault_check(u8_gunNo); //停止故障检查
v_flow_bms_state_cheak(u8_gunNo); //BMS状态检查
v_flow_stop_cmd_check(u8_gunNo); //停止命令检查
switch (s_real_data->e_flow_state)
{
case E_FLOW_FREE : //空闲
{
v_flow_ctrl_free(u8_gunNo);
break;
}
case E_FLOW_START_CHECK : //启动前检查
{
v_flow_ctrl_start_check(u8_gunNo);
break;
}
case E_FLOW_START_CHECK_OK : //启动前检查完成
{
v_flow_ctrl_start_check_ok(u8_gunNo);
break;
}
case E_FLOW_INSUL_BEFORE : //绝缘检查前准备
{
v_flow_ctrl_insul_before(u8_gunNo);
break;
}
case E_FLOW_INSUL_RUNING : //绝缘检测中
{
v_flow_ctrl_insul_runing(u8_gunNo);
break;
}
case E_FLOW_INSUL_OK : //绝缘检测完成
{
v_flow_ctrl_insul_ok(u8_gunNo);
break;
}
case E_FLOW_WAIT_PRE_CHARGE : //等待预充
{
v_flow_ctrl_wait_pre_charge(u8_gunNo);
break;
}
case E_FLOW_PRE_CHARGE_BEFORE : //预充前检查
{
v_flow_ctrl_pre_charge_before(u8_gunNo);
break;
}
case E_FLOW_PRE_CHARGE_RUNING : //预充电中
{
v_flow_ctrl_pre_charge_runing(u8_gunNo);
break;
}
case E_FLOW_PRE_CHARGE_OK : //预充完成
{
v_flow_ctrl_pre_charge_ok(u8_gunNo);
break;
}
case E_FLOW_CHARGE_RUNING : //充电中
{
v_flow_ctrl_charge_runing(u8_gunNo);
break;
}
case E_FLOW_CHARGE_SUSPEND : //充电暂停
{
v_flow_ctrl_charge_suspend(u8_gunNo);
break;
}
case E_FLOW_BMS_TIMEOUT : //BMS通讯超时
{
v_flow_ctrl_bms_timeout(u8_gunNo);
break;
}
case E_FLOW_STOP_CHARGE : //停止充电
{
v_flow_set_stop_charge_runing(u8_gunNo);
break;
}
case E_FLOW_STOP_CHARGE_OK : //停止充电完成
{
v_flow_set_stop_charge_ok(u8_gunNo);
break;
}
default:
break;
}
}
#endif
/**
* ************************************************************************
* @brief - 流程控制任务 数据初始化
*
*
*
* @author jiankalka
* @date 2025-09-03
* ************************************************************************
*/
void v_flowctrl_data_init()
{
memset(&s_flow_data , 0 ,sizeof(S_FLOW_DATA));
s_flow_data.u8_gunCnt = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_GUN_CNT,0); //获取枪号
s_flow_data.u8_gb_en = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_GB_EN,0); //国标使能
memcpy(s_flow_data.u8_gun_type, g_t_share_data.t_sys_fix_cfg.u8_gun_type, GUN_MAX_CNT); //枪类型 0欧标 1国标
s_flow_data.u8_gunlock_num = 10; //空闲枪锁解锁次数
s_flow_data.u8_relief_time = 2; //泄放时间改 单位秒
// 初始化防抖/延时计时器起点,避免“首次进入判定即超时”
{
U8_T i;
U32_T now_s = get_current_seconds();
for(i = 0; i < GUN_MAX_CNT; i++)
{
s_flow_data.s_ctrl_data[i].s_over_time.u32_trickle_limit_time = now_s;
s_flow_data.s_ctrl_data[i].s_over_time.u32_dc_km_time = now_s;
s_flow_data.s_ctrl_data[i].s_over_time.u32_mdu_free_time = now_s;
s_flow_data.s_ctrl_data[i].s_over_time.u32_over_vol_time = now_s;
s_flow_data.s_ctrl_data[i].s_over_time.u32_under_vol_time = now_s;
s_flow_data.s_ctrl_data[i].s_over_time.u32_over_curr_time = now_s;
s_flow_data.s_ctrl_data[i].s_over_time.u32_over_needCur_time = now_s;
s_flow_data.s_ctrl_data[i].s_over_time.u32_over_needCur_max_time = now_s;
}
}
if(s_flow_data.u8_gb_en == 1) //国标使能
{
s_flow_data.u16_insul_before_vol = 600; //绝缘前外侧电压检测 精度 0.1V
s_flow_data.u16_insul_putvol_range = 100; //绝缘检测电压输出误差值 精度 0.1V
}
else
{
s_flow_data.u16_insul_before_vol = 1000; //绝缘前外侧电压检测 精度 0.1V
s_flow_data.u16_insul_putvol_range = 600; //绝缘检测电压输出误差值 精度 0.1V
}
}
void v_flowctrl_task(void *arg)
{
uint16_t sleep_time_ms;
uint32_t last_send_time;
uint32_t current_time;
uint8_t u8_gunNo;
(void)arg;
(void)FLOWCTRL_LOCK_INIT();
sleep_time_ms = FLOWCTRL_SLEEP_TIME_MS();
last_send_time = get_current_seconds();
v_flowctrl_data_init();
for (;;) {
FLOWCTRL_FEED_DOG();
current_time = get_current_seconds();
if ((TASK_RUN_PRINT_TIME != 0U) && (u32_safe_seconds_since(last_send_time) >= TASK_RUN_PRINT_TIME)) {
if (FLOWCTRL_LOCK_TAKE() == 1U) {
FLOWCTRL_LOG("flowctrl task is runing, sleep time is %ums", sleep_time_ms);
(void)FLOWCTRL_LOCK_GIVE();
}
last_send_time = current_time;
}
for (u8_gunNo = 0; u8_gunNo < s_flow_data.u8_gunCnt; u8_gunNo++)
{
s_flow_data.s_ctrl_data[u8_gunNo].u8_twoGun_flag = u16_flow_get_sys_data(u8_gunNo,E_FLOW_GET_DATA_GUN_TOW_CHR,0); //获取双枪同充标志
if(s_flow_data.s_ctrl_data[u8_gunNo].u8_twoGun_flag == 0) //单枪充电
{
v_flow_control(u8_gunNo); //充电流程控制
}
else
{
}
}
v_mdu_shw_control(sleep_time_ms); //模块开关控制
v_flow_ac_fan_ctrl(sleep_time_ms); //交流接触器和开关控制
v_flow_timer_add(sleep_time_ms); //任务 周期计数值 累加
mSleep(sleep_time_ms);
}
}