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
+382
View File
@@ -0,0 +1,382 @@
#include "bms/bms_interface.h"
#include "publicdata/publicdata.h"
#include "app_rtc/app_rtc.h"
#include "flowctrl/flow_interface.h"
#include "meter_calculate/meter_calculate_impl.h"
#include "bms/bms_task.h"
extern S_BMS_DATA s_bms_data; //BMS数据
/**
* ************************************************************************
* @brief - 获取BMS流程控制状态
*
* @param[in] u8_gunNo - 抢号 0-1
*
* @return U8_T - 0无意义 1空闲 2开始握手 3绝缘完成,开始握手辨识 4预充完成,发送cro_aa 5充电停止 发送cst 6停止充电完成 停止发送CSD 7BMS通讯超时
*
* @author jiankalka
* @date 2025-08-21
* ************************************************************************
*/
static U8_T u8_bms_get_flow_status(U8_T u8_gunNo)
{
U8_T ret_state = 0;
E_FLOW_REAL_STATE flow_state;
flow_state = (E_FLOW_REAL_STATE)u16_flow_put_data(u8_gunNo , E_FLOW_PUT_DATA_GUN_REAL_STATE,0); //0空闲 1充电启动 2绝缘启动 3绝缘计算完成 4绝缘检测模块停止 5开始预充 6预充完成 7充电中 8BMS通讯超时 9充电停止 10充电停止完成
switch (flow_state)
{
case E_FLOW_REAL_FREE : //空闲
ret_state = 1; //空闲
break;
case E_FLOW_REAL_CHARGE_START : //充电启动
ret_state = 2; //开始握手
break;
case E_FLOW_REAL_INSUL_START : //绝缘启动
break;
case E_FLOW_REAL_INSUL_OK : //绝缘计算完成
break;
case E_FLOW_REAL_INSUL_MDU_STOP : //绝缘检测模块停止
if ((s_bms_data.u8_gun_type[u8_gunNo] == 0))
ret_state = 4; //欧标:发送cro_aa
else
ret_state = 3; //国标:绝缘完成,开始握手辨识
break;
case E_FLOW_REAL_PRE_START : //开始预充
break;
case E_FLOW_REAL_PRE_OK : //预充完成
ret_state = 4; //预充完成,发送cro_aa
break;
case E_FLOW_REAL_CHARGEING : //充电中
break;
case E_FLOW_REAL_BMS_OUTTIME : //BMS通讯超时
break;
case E_FLOW_REAL_STOP : //充电停止
ret_state = 5; //停止充电(充电模块退出运行可给其他充电端口使用)
break;
case E_FLOW_REAL_STOP_OK : //充电停止完成
ret_state = 6; //停止充电完成
break;
default:
ret_state = 0;
break;
}
return ret_state;
}
/**
* ************************************************************************
* @brief - BMS任务获取 系统参数
*
* @param[in] gunNo - 枪号 0-1 当获取数据不分枪号时,该值无意义
* @param[in] e_type -
* E_BMS_GET_PARA_GUN_CNT=0, //枪数量 返回值1-N
E_BMS_GET_PARA_GB_EN, //国标使能 返回值 0不使能 1使能
E_BMS_GET_PARA_SC_EN, //团标使能 返回值 0不使能 1使能
E_BMS_GET_PARA_MAX_VOL, //最大电压 精度 0.1
E_BMS_GET_PARA_MIN_VOL, //最小电压 精度 0.1
E_BMS_GET_PARA_MAX_CUR, //最大电流 精度 0.1
E_BMS_GET_PARA_MIN_CUR, //最小电流 精度 0.1
E_BMS_GET_GUN_OUT_VOL, //输出电压 精度0.1
E_BMS_GET_GUN_OUT_CUR, //输出电流 精度0.1
E_BMS_GET_GUN_CHR_TIME, //充电时长 单位min
E_BMS_GET_GUN_CHR_POWER, //充电电量 单位0.1 kWh
E_BMS_GET_GUN_FIOW_CTRL, //BMS充电状态 0无意义 1空闲 2开始握手 3绝缘完成,开始握手辨识 4预充完成,发送cro_aa 5充电停止 发送cst 6停止充电完成 停止发送CSD 7BMS通讯超时
E_BMS_GET_GUN_FLOW_RENEW, //获取重连标识
E_BMS_CLEAR_GUN_FLOW_RENEW, //清空重连标识
* @return U16_T -
*
* @author jiankalka
* @date 2025-08-13
* ************************************************************************
*/
U16_T u16_bms_get_sys_para(U8_T gunNo , E_BMS_GET_PARA_TYPE e_type)
{
U16_T u16_ret = 0;
switch (e_type)
{
case E_BMS_GET_PARA_GUN_CNT: //枪数量
u16_ret = g_t_share_data.t_sys_fix_cfg.u8_gunCnt;
break;
case E_BMS_GET_PARA_GB_EN: //国标使能
u16_ret = g_t_share_data.t_sys_fix_cfg.u_enable.bit_enable.bit_GBEnable;
break;
case E_BMS_GET_PARA_SC_EN: //团标使能
u16_ret = g_t_share_data.t_sys_fix_cfg.u_enable.bit_enable.bit_YeLenEn;
break;
case E_BMS_GET_PARA_MAX_VOL: //最大电压 精度 0.1
u16_ret = g_t_share_data.t_sys_fix_cfg.u16_max_volt;
break;
case E_BMS_GET_PARA_MIN_VOL: //最小电压 精度 0.1
u16_ret = g_t_share_data.t_sys_fix_cfg.u16_min_volt;
break;
case E_BMS_GET_PARA_MAX_CUR: //最大电流 精度 0.1
u16_ret = g_t_share_data.t_sys_fix_cfg.u16_max_cur;
break;
case E_BMS_GET_PARA_MIN_CUR: //最小电流 精度 0.1
u16_ret = 50;
break;
case E_BMS_GET_GUN_OUT_VOL: //输出电压 精度 0.1
u16_ret = (U16_T)(u64_get_meter_data(gunNo,0,E_METER_DATA_VOL)/1000);
break;
case E_BMS_GET_GUN_OUT_CUR: //输出电流 精度 0.1
u16_ret = (U16_T)(u64_get_meter_data(gunNo,0,E_METER_DATA_CUR)/1000);
break;
case E_BMS_GET_GUN_CHR_TIME: //充电时长 单位min
u16_ret = u32_meterlog_put_data(gunNo,E_METERLOG_PUT_LOG_INFO_CHAR_TIME,NULL,0); //获取充电时间
break;
case E_BMS_GET_GUN_CHR_POWER: //充电电量 单位0.1 kWh
u16_ret = (U16_T)u32_flow_put_data(gunNo,E_FLOW_PUT_DATA_USED_ENERGY) / NUM_100; //精度转换,由0.0001转换为0.1
break;
case E_BMS_GET_GUN_FIOW_CTRL: //BMS充电状态 0无意义 1空闲 2开始握手 3绝缘完成,开始握手辨识 4预充完成,发送cro_aa 5充电停止 发送cst 6停止充电完成 停止发送CSD 7BMS通讯超时
u16_ret = u8_bms_get_flow_status(gunNo);
break;
case E_BMS_GET_GUN_FLOW_RENEW: //获取重连标识
u16_ret = u16_flow_put_data(gunNo ,E_FLOW_PUT_DATA_GUN_RECONN_FLAG,0); //输出bms重连开始标志 参数:0获取 1清空
break;
case E_BMS_CLEAR_GUN_FLOW_RENEW: //清空重连标识
u16_ret = u16_flow_put_data(gunNo ,E_FLOW_PUT_DATA_GUN_RECONN_FLAG,1); //输出bms重连开始标志 参数:0获取 1清空
break;
default:
break;
}
return u16_ret;
}
U16_T u16_bms_put_data(U8_T gunNo , E_BMS_PUT_DATA_TYPE e_type,U8_T u8_dataPara)
{
U16_T u16_ret = 0;
S_BMS_RT_DATA *pt_bms = &s_bms_data.s_bms_rt_data[gunNo];
switch (e_type)
{
case E_BMS_PUT_DATA_BMS_GB_VER : //BMS 国标协议版本 0 2011版 1 2015版
{
u16_ret = pt_bms->e_bms_standard;
break;
}
case E_BMS_PUT_DATA_BMS_STATE : //BMS 获取BMS状态 0无 1握手完成 2握手失败 3开始预充 4开始充电 5禁止充电 6停止充电 7报文接收超时
{
u16_ret = pt_bms->e_real_state;
break;
}
case E_BMS_PUT_DATA_BMS_MAX_VOL : //BMS 最大充电电压值 精度 0.1V
{
#if CAN_PLC_FLAG //欧标 CAN转PLC使能
if ((s_bms_data.u8_gun_type[gunNo] == 0))
{
u16_ret = (U16_T)(pt_bms->t_bcp_data.f32_batt_charge_max_volt*10);
if(u16_ret < (U16_T)(pt_bms->t_bcl_data.f32_batt_charge_max_volt*10))
u16_ret = (U16_T)(pt_bms->t_bcl_data.f32_batt_charge_max_volt*10);
}
else
#endif
u16_ret = (U16_T)(pt_bms->t_bhm_data.f32_max_charge_volt*10);
break;
}
case E_BMS_PUT_DATA_BMS_MAX_CUR : //BMS 最大充电电流值 精度 0.1V
{
u16_ret = (U16_T)(pt_bms->t_bcp_data.f32_batt_charge_max_curr*10);
break;
}
case E_BMS_PUT_DATA_BMS_REAL_BATT_VOL : //BMS 当前电池电压值 精度 0.1V
{
u16_ret = (U16_T)(pt_bms->t_bcp_data.f32_batt_volt*10);
break;
}
case E_BMS_PUT_DATA_BMS_NEED_VOL : //BMS 需求电压值 精度 0.1V
{
u16_ret = (U16_T)(pt_bms->t_bcl_data.f32_batt_need_volt *10);
break;
}
case E_BMS_PUT_DATA_BMS_NEED_CUR : //BMS 需求电流值 精度 0.1A
{
u16_ret = (U16_T)(pt_bms->t_bcl_data.f32_batt_need_curr *10);
break;
}
case E_BMS_PUT_DATA_BMS_CAN_SEND_CNT : //BMS 报文发送次数 参数值 0代表cem 1代表csd
{
if(u8_dataPara == 0)
u16_ret = pt_bms->u8_cem_send_cnt;
else
u16_ret = pt_bms->u8_csd_send_cnt;
break;
}
case E_BMS_PUT_DATA_BMS_STOP_RES : //BMS 停止原因 详看E_FAULT_INFO枚举内容 BMS部分
{
u16_ret = pt_bms->e_stop_info;
break;
}
case E_BMS_PUT_DATA_BMS_RECONN_FLAG : //BMS 重连标志 0不重连 1重连
{
u16_ret = pt_bms->u8_reconn_flag;
break;
}
case E_BMS_PUT_DATA_GUN_SOC: //BMS SOC %
{
u16_ret = pt_bms->t_bcs_data.u8_batt_soc;
break;
}
case E_BMS_PUT_DATA_GUN_ONE_BATT_MAX_TEMP: //单体电池最大温度 -50度
{
u16_ret = pt_bms->t_bsm_data.s16_batt_max_temp;
break;
}
case E_BMS_PUT_DATA_GUN_ONE_BATT_MAX_VOL: //单体电池最大电压 0.1V
{
u16_ret = (U16_T)(pt_bms->t_bcs_data.f32_cell_max_volt * 10);
break;
}
case E_BMS_PUT_DATA_GUN_BATT_TYPE: //电池类型 01H,铅酸电池;02H:镍氢电池;03H:磷酸铁锂电池;04H:锰酸锂电池;05H:钴酸锂电池;
{
u16_ret = pt_bms->t_brm_data.u8_batt_type;
break;
}
case E_BMS_PUT_DATA_GUN_BATT_RATED_C10: //整车动力蓄电池系统额定容量,数据范围0~1000A.h,精度0.1
{
u16_ret = (U16_T)(pt_bms->t_brm_data.f32_batt_rated_c10*10);
break;
}
default:
break;
}
return u16_ret;
}
void v_bms_get_rt_time(Comm_Time *time)
{
GetCurrentTime(time);
}
/****************************************************
*函数名称: v_get_cst(U8_T gunNo,U8_T *u8_data)
*功能说明: 获取cst停止原因
*参数说明:
* 输入参数:
* 输出参数: void
*最后修改时间: 20230602
*修改内容: 20230602 第一次创建子函数
****************************************************/
U8_T u8_bms_get_cst(U8_T gunNo,U8_T *u8_data)
{
BMS_CST_DATA_U cst_data;
E_FAULT_INFO e_stop_res = (E_FAULT_INFO)u16_flow_get_sys_data(gunNo, E_FLOW_GET_DATA_GUN_STOP_REASON_0, 0);
memset(&cst_data , 0 ,sizeof(BMS_CST_DATA_U));
if(e_stop_res == E_NORMAL_1001 || e_stop_res == E_NORMAL_1002)
cst_data.CST_TMO_FLAG.MAN_MADE_STOP = 1;
else if(e_stop_res == E_NORMAL_1003 || e_stop_res == E_NORMAL_1004)
cst_data.CST_TMO_FLAG.PILE_NORMAL_STOP = 1;
else if(e_stop_res == E_FAULT_13017 )
{
cst_data.CST_TMO_FLAG.FAULT_STOP = 1;
cst_data.CST_TMO_FLAG.EMERGENCY_STOP = 1;
}
else if(e_stop_res == E_FAULT_13016 || /* 充电中导引/连接类 */
e_stop_res == E_FAULT_13015 ||
e_stop_res == E_FAULT_15019)
{
cst_data.CST_TMO_FLAG.FAULT_STOP = 1;
cst_data.CST_TMO_FLAG.PILE_CONNET_FAULT = 1;
}
else if(e_stop_res == E_FAULT_15037 || /* 输出超车辆最高允许充电电压 D0.4504 等 */
e_stop_res == E_FAULT_13048 ||
e_stop_res == E_FAULT_15039 ||
e_stop_res == E_FAULT_15045)
{
cst_data.CST_TMO_FLAG.FAULT_STOP = 1;
cst_data.CST_TMO_FLAG.OVER_VOLT = 1;
}
else if(s_bms_data.s_bms_rt_data[gunNo].t_cst_data.CST_TMO_FLAG.BMS_STOP) //BMS主动中止
cst_data.CST_TMO_FLAG.BMS_STOP = 1;
else
{
cst_data.CST_TMO_FLAG.FAULT_STOP = 1;
cst_data.CST_TMO_FLAG.OTHER = 1;
}
cst_data.CST_TMO_FLAG.reserve1 = 0x0F;
cst_data.CST_TMO_FLAG.reserve = 0x0F;
memcpy(u8_data,&cst_data,sizeof(BMS_CST_DATA_U));
return 1;
//logMsg("fault_info= %x , %x %x %x %x\n",fault_info,u8_data[0],u8_data[1],u8_data[2],u8_data[3]);
}
/****************************************************
*函数名称: v_bms_get_pile_nun()
*功能说明: 获取获取充电桩桩编号
*参数说明:
* 输入参数:U8_T *pilenum
* 输出参数:
****************************************************/
void v_bms_get_pile_nun(U8_T *pilenum)
{
U8_T len = strlen((char *)g_t_share_data.t_sys_fix_cfg.s_net_cfg.u8_platA_pileNum);
memset(pilenum,0,len+1);
memcpy(pilenum,g_t_share_data.t_sys_fix_cfg.s_net_cfg.u8_platA_pileNum,len);
}
/**
* ************************************************************************
* @brief - 对外提供VIN信息获取接口函数
*
* @param[in] u8_gunNo - 抢号 0-N
* @param[in] u8_vin - 获取数据数组
* @param[in] u8_len - 数组长度
*
*
* @author jiankalka
* @date 2025-09-15
* ************************************************************************
*/
void v_bms_put_vin_str(U8_T u8_gunNo,U8_T *u8_vin,U8_T u8_len)
{
if(u8_vin == NULL ) return;
if(u8_gunNo >= 2) return;
memset(u8_vin , 0 ,u8_len);
strncpy((char *)u8_vin , (char *)s_bms_data.s_bms_rt_data[u8_gunNo].t_brm_data.u8_car_vin ,u8_len);
}
#if CAN_PLC_FLAG //欧标 CAN转PLC使能
U8_T u8_test_gunLink[GUN_MAX_CNT];
/**
* ************************************************************************
* @brief - can 转PLC 获取枪连接状态
*
* @param[in] gunNo - 枪号 0-1
*
* @return U8_T - 抢连接状态 0未连接 1已连接
*
* @author jiankalka
* @date 2025-11-14
* ************************************************************************
*/
U8_T u8_bms_get_gunLink(U8_T gunNo)
{
U8_T u8_gunLink;
u8_gunLink = s_bms_data.u8_gun_linkState[gunNo];
//u8_gunLink = u8_test_gunLink[gunNo];
return u8_gunLink;
}
#endif
+368
View File
@@ -0,0 +1,368 @@
#ifndef BMS_INTERFACE_H
#define BMS_INTERFACE_H
#ifdef __cplusplus /*C++编译环境下兼容C语言*/
extern "C" {
#endif
/*------ Exported includes(头文件) ----------------------*/
#include "main.h"
/*------ Exported macro(宏定义) -------------------------*/
/*------ Exported struct(结构体定义) --------------------*/
//BMS接收数据类型 0bhm 1brm 2bcp 3bro 4bcs 5bcl 6bsm 7bmv 8bmt 9bst 10bsd 11bem
typedef enum
{
E_BMS_TYPE_BHM = 0,
E_BMS_TYPE_BRM,
E_BMS_TYPE_BCP,
E_BMS_TYPE_BRO,
E_BMS_TYPE_BCS,
E_BMS_TYPE_BCL,
E_BMS_TYPE_BSM,
E_BMS_TYPE_BMV,
E_BMS_TYPE_BMT,
E_BMS_TYPE_BST,
E_BMS_TYPE_BSD,
E_BMS_TYPE_BEM,
BMS_RECV_TYPE_NUM,//BMS接收数据类型数量
}E_BSM_CAR_DATA_TYPE;
//BMS_BHM报文数据结构体
typedef struct
{
F32_T f32_max_charge_volt; //最高允许充电总电压
#if CAN_PLC_FLAG //欧标 CAN转PLC使能
U8_T u8_CR_Plc_Aagvalue; // 信号衰减值
U8_T u8_CR_Plc_CpStatus; // CP状态 0:12v未插枪;1:9v已插枪;2:9v占空比状态;3:6v占空比准备充电状态
U8_T u8_CR_Plc_CommStart; // 通信启动 0:通信未启动;1:启动PLC通信
U8_T u8_SECC_ver[10]; //SECC固件版本编译日期-年月日
#endif
}BMS_BHM_DATA_T;
//BMS_BRM报文数据结构体
typedef struct
{
//握手辨识BRM
U32_T u32_bms_version; //BMS通信协议版本,例如版本V1.0,表示为0x000100
U8_T u8_batt_type; //电池类型,01H,铅酸电池;02H:镍氢电池;03H:磷酸铁锂电池;04H:锰酸锂电池;05H:钴酸锂电池;
//06H:三元材料电池;07H:聚合物锂离子电池;08H;钛酸锂电池;FFH:其他电池
F32_T f32_batt_rated_c10; //整车动力蓄电池系统额定容量,数据范围0~1000A.h,精度0.1
F32_T f32_batt_rated_volt; //整车动力蓄电池系统额定总电压,数据范围0~750V,精度0.1
U8_T u8_batt_vender[4]; //电池生产厂商,标准ASCII
U32_T u32_batt_serial; //电池组序号
U8_T u8_batt_make[4]; //电池生产年月日
U32_T u32_batt_charge_times; //BMS电池组充电次数
U8_T u8_batt_belong; //电池产权标识
U8_T u8_Bms_edition; //充电机通信协议版本号 5A 2015+团标协议 FF 国标协议
U8_T u8_car_vin[18]; //车辆识别码VIN
U8_T u8_bms_soft_version[8]; //BMS软件版本号
}BMS_BRM_DATA_T;
//BMS_BCP报文数据结构体
typedef struct
{
F32_T f32_cell_charge_max_volt; //单体动力蓄电池最高允许充电电压,数据范围0~24V,精度0.01
F32_T f32_batt_charge_max_curr; //最高允许充电电流,数据范围0~400A,精度0.1
F32_T f32_batt_rated_enery; //动力蓄电池标称总能量,数据范围0~1000kW.h,精度0.1
F32_T f32_batt_charge_max_volt; //最高允许充电总电压,数据范围0~750V,精度0.1,此变量用于判断电压超出最高允许充电电压
S16_T s16_batt_allow_max_temp; //最高允许动力蓄电池温度,数据范围-50度~200度
F32_T f32_batt_start_soc; //整车动力蓄电池荷电状态(SOC),数据范围0~100%,精度0.1,这个SOC是充电开始时的SOC
F32_T f32_batt_volt; //整车动力蓄当前电池总电压,数据范围0~750V,精度0.1
#if CAN_PLC_FLAG //欧标 CAN转PLC使能
U8_T u8_CR_Plc_EvTransferType; //电动车传输协议能量类型 默认0x03,支持的能量传输类型
#endif
}BMS_BCP_DATA_T;
//BMS_BSD报文数据结构体
typedef struct
{
U8_T u8_batt_end_soc; //BMS终止荷电状态SOC
F32_T f32_cell_batt_min_volt; //BMS动力蓄电池单体最低电压
F32_T f32_cell_batt_max_volt; //BMS动力蓄电池单体最高电压
U8_T u8_batt_min_temp; //BMS动力蓄电池最低温度
U8_T u8_batt_max_temp; //BMS动力蓄电池最高温度
#if CAN_PLC_FLAG //欧标 CAN转PLC使能
U8_T u8_CF_Plc_WeldDetectionReq; //粘连检测要求 0:无焊接检测1:焊接检测请求(发送CSD当前充电枪电压)
#endif
}BMS_BSD_DATA_T;
//BMS_BCL报文数据结构体
typedef struct
{
F32_T f32_batt_need_volt; //电压需求,数据范围0~750V,精度0.1
F32_T f32_batt_need_curr; //电流需求,数据范围0~400V,精度0.1
U8_T u8_charge_mode; //充电模式,0x01:恒压充电;0x02:恒流充电
#if CAN_PLC_FLAG //欧标 CAN转PLC使能
F32_T f32_batt_charge_max_volt; //欧标车辆充电中最高允许电压在BCL中
U8_T u8_preCharge; //预充电状态 1:预充电状态: 0:无预充电状态
#endif
}BMS_BCL_DATA_T;
//BMS_BCS报文数据结构体
typedef struct
{
F32_T f32_charge_volt; //充电电压测量值,数据范围0~750V,精度0.1
F32_T f32_charge_curr; //充电电流测量值,数据范围0~400A,精度0.1
F32_T f32_cell_max_volt; //最高单体动力蓄电池电压,数据范围0~24V,精度0.01
U8_T u8_cell_max_volt[2];
U8_T u8_cell_max_volt_group_num; //最高单体动力蓄电池电压所在组号,范围1~16
U8_T u8_batt_soc; //当前荷电状态,数据范围0~100%
U16_T u16_remain_charge_time; //估算剩余充电时间,数据范围0~600min
}BMS_BCS_DATA_T;
//BMS_BMV报文数据结构体
typedef struct
{
// 1-12位:单体动力蓄电池电压,数据分辨率:0.01 V/位,0 V偏移量;数据范围:0~24 V;
// 13-16位:电池分组号,数据分辨率:1/位,0偏移量;数据范围:0~15。
union
{
U16_T u16_data;
struct
{
U16_T bit_cell_volt:12; //单体电压
U16_T bit_cell_group_numt:4; //单体电池组号
}s_bit;
}u_data[NUM_256];
}BMS_BMV_DATA_T;
//BMS_BMT报文数据结构体
typedef struct
{
U8_T u8_batt_temp[NUM_128]; //动力蓄电池温度,数据范围-50度~200度 原始数据存储
}BMS_BMT_DATA_T;
//BMS_BSM报文数据结构体
typedef struct
{
U8_T u8_cell_max_volt_id; //最高单体动力蓄电池电压所在编号,数据范围1~256
S16_T s16_batt_max_temp; //最高动力蓄电池温度,数据范围-50度~200度
U8_T u8_max_temp_id; //最高温度检测点编号,数据范围1~128
S16_T s16_batt_min_temp; //最低动力蓄电池温度,数据范围-50度~200度
U8_T u8_min_temp_id; //最低温度检测点编号,数据范围1~128
U16_T u16_batt_state; //电池状态
//bit0:单体动力蓄电池电压过高
//bit1:单体动力蓄电池电压过低
//bit2:整车动力蓄电池荷电状态SOC过高
//bit3:整车动力蓄电池荷电状态SOC过低
//bit4:动力蓄电池充电过流
//bit5:动力蓄电池温度过高
//bit6:动力蓄电池绝缘状态不正常
//bit7:动力蓄电池组输出连接器连接状态不正常
//bit8:充电允许,0:禁止,1:允许
}BMS_BSM_DATA_T;
//BMS_BEM报文数据联合体
typedef union
{
#if CAN_PLC_FLAG //欧标 CAN转PLC使能
U8_T u8_bem_data[8];
struct
{
U8_T RECV_CRM_00_TMO:2; //接收CRM=00超时
U8_T RECV_CRM_AA_TMO:2; //接收CRM=AA超时
U8_T reserve1:4; //保留1
U8_T RECV_CML_TMO:2; //接收CML超时
U8_T RECV_CRO_AA_TMO:2; //接收CRO=AA超时
U8_T reserve2:4; //保留2
U8_T RECV_CCS_TMO:2; //接收CCS超时
U8_T RECV_CST_TMO:2; //接收CTS超时
U8_T reserve3:4; //保留3
U8_T RECV_CSD_TMO:2; //接收CSD超时
U8_T reserve4:6; //保留3
U8_T Message_Sequence:8; //通信流程消息序列
U8_T CR_Plc_ErrorCodeII:8; //错误代码II 见附录
U8_T CR_Plc_ErrorCode:8; //错误代码 见附录
U8_T ErrorCode_CPorPP_state:3; //CP或PP状态的错误代码 见附录
U8_T CR_PLc_EvErrCode:4; //EV车辆发送的错误代码 见附录
U8_T reserve5:1; //预留位
}BEM_TMO_FLAG;
#else
U8_T u8_bem_data[4];
struct
{
U8_T RECV_CRM_00_TMO:2; //接收CRM=00超时
U8_T RECV_CRM_AA_TMO:2; //接收CRM=AA超时
U8_T reserve1:4; //保留1
U8_T RECV_CML_TMO:2; //接收CML超时
U8_T RECV_CRO_AA_TMO:2; //接收CRO=AA超时
U8_T reserve2:4; //保留2
U8_T RECV_CCS_TMO:2; //接收CCS超时
U8_T RECV_CST_TMO:2; //接收CTS超时
U8_T reserve3:4; //保留3
U8_T RECV_CSD_TMO:2; //接收CSD超时
U8_T reserve4:6; //保留3
}BEM_TMO_FLAG;
#endif
}BMS_BEM_DATA_U;
//BMS_CEM报文数据联合体
typedef union
{
U8_T u8_cem_data[4];
struct
{
U8_T RECV_BRM_TMO:2; //接收RRM超时
U8_T reserve1:6; //保留1
U8_T RECV_BCP_TMO:2; //接收BCP超时
U8_T RECV_BRO_AA_TMO:2; //接收BRO=AA超时
U8_T reserve2:4; //保留2
U8_T RECV_BCS_TMO:2; //接收BCS超时
U8_T RECV_BCL_TMO:2; //接收BCL超时
U8_T RECV_BST_TMO:2; //接收BTS超时
U8_T reserve3:2; //保留3
U8_T RECV_BSD_TMO:2; //接收BSD超时
U8_T reserve4:6; //保留3
}CEM_TMO_FLAG;
}BMS_CEM_DATA_U;
//BMS_BST报文数据联合体
typedef union
{
#if CAN_PLC_FLAG //欧标 CAN转PLC使能
U8_T u8_bst_data[8];
struct
{
U8_T ACHIEVE_AIM_SOC:2; //达到目标SOC
U8_T ACHIEVE_VOLT:2; //接收总电压设定值
U8_T ACHIEVE_CELL_VOLT:2; //达到单体电压设定值
U8_T CHARGER_STOP:2; //充电机主动终止
U8_T INSU_FAULT:2; //绝缘故障
U8_T DC_OUT_OVER_TEMP:2; //输出连接器过温故障
U8_T BMS_OVER_TEMP:2; //BMS元件、输出连接器过温故障
U8_T CONNECT_FAULT:2; //充电连接器故障
U8_T BATT_OVER_TEMP:2; //电池组温度过高故障
U8_T HV_RELAYS_FAULT:2; //高压继电器故障
U8_T CONN_CHECK_TWO_FAULT:2; //检测点2电压检测故障
U8_T OTHER_FAULT:2; //其它故障
U8_T OVER_CURR:2; //电流过大
U8_T OVER_VOLT:2; //电压过大
U8_T reserve:2; //预留位
U8_T CF_Plc_FullChgComplete:1; //车充电是否完成 0:未满1:完全充电完成
U8_T CF_Plc_ChgFinished:1; //桩充电状态 0:充电,1:充电停止请求
U8_T Message_Sequence:8; //通信流程消息序列
U8_T CR_Plc_ErrorCodeII:8; //错误代码II 见附录
U8_T CR_Plc_ErrorCode:8; //错误代码 见附录
U8_T ErrorCode_CPorPP_state:3; //CP或PP状态的错误代码 见附录
U8_T CR_PLc_EvErrCode:4; //EV车辆发送的错误代码 见附录
U8_T reserve2:1; //预留位
}BST_TMO_FLAG;
#else
U8_T u8_bst_data[4];
struct
{
U8_T ACHIEVE_AIM_SOC:2; //达到目标SOC
U8_T ACHIEVE_VOLT:2; //接收总电压设定值
U8_T ACHIEVE_CELL_VOLT:2; //达到单体电压设定值
U8_T CHARGER_STOP:2; //充电机主动终止
U8_T INSU_FAULT:2; //绝缘故障
U8_T DC_OUT_OVER_TEMP:2; //输出连接器过温故障
U8_T BMS_OVER_TEMP:2; //BMS元件、输出连接器过温故障
U8_T CONNECT_FAULT:2; //充电连接器故障
U8_T BATT_OVER_TEMP:2; //电池组温度过高故障
U8_T HV_RELAYS_FAULT:2; //高压继电器故障
U8_T CONN_CHECK_TWO_FAULT:2; //检测点2电压检测故障
U8_T OTHER_FAULT:2; //其它故障
U8_T OVER_CURR:2; //电流过大
U8_T OVER_VOLT:2; //电压过大
U8_T reserve:4; //预留位
}BST_TMO_FLAG;
#endif
}BMS_BST_DATA_U;
//BMS_CST报文数据联合体
typedef union
{
U8_T u8_cst_data[4];
struct
{
U8_T PILE_NORMAL_STOP:2; //达到充电机设定的条件中止
U8_T MAN_MADE_STOP:2; //人工中止
U8_T FAULT_STOP:2; //故障中止
U8_T BMS_STOP:2; //BMS主动中止
U8_T PILE_TEMP_OVER:2; //充电机过温故障
U8_T PILE_CONNET_FAULT:2; //充电连接器故障
U8_T PILE_TEMP_CVER2:2; //充电机内部过温故障
U8_T NOT_NEOUGH_ENERGY:2; //所需电量不能传送
U8_T EMERGENCY_STOP:2; //充电机急停故障
U8_T OTHER:2; //其他故障
U8_T reserve:4; //预留位
U8_T OVER_CURR:2; //电流过大
U8_T OVER_VOLT:2; //电压过大
U8_T reserve1:4; //预留位
}CST_TMO_FLAG;
}BMS_CST_DATA_U;
typedef enum
{
E_BMS_GET_PARA_GUN_CNT=0, //枪数量
E_BMS_GET_PARA_GB_EN, //国标使能
E_BMS_GET_PARA_SC_EN, //团标使能
E_BMS_GET_PARA_MAX_VOL, //最大电压 精度0.1
E_BMS_GET_PARA_MIN_VOL, //最小电压 精度0.1
E_BMS_GET_PARA_MAX_CUR, //最大电流 精度0.1
E_BMS_GET_PARA_MIN_CUR, //最小电流 精度0.1
E_BMS_GET_GUN_OUT_VOL, //输出电压 精度0.1
E_BMS_GET_GUN_OUT_CUR, //输出电流 精度0.1
E_BMS_GET_GUN_CHR_TIME, //充电时长 单位min
E_BMS_GET_GUN_CHR_POWER, //充电电量 单位0.1 kWh
E_BMS_GET_GUN_FIOW_CTRL, //BMS充电状态 0无意义 1空闲 2开始握手 3绝缘完成,开始握手辨识 4预充完成,发送cro_aa 5充电停止 发送cst 6停止充电完成 停止发送CSD 7BMS通讯超时
E_BMS_GET_GUN_FLOW_RENEW, //获取重连标识
E_BMS_CLEAR_GUN_FLOW_RENEW, //清空重连标识
}E_BMS_GET_PARA_TYPE;
typedef enum
{
E_BMS_PUT_DATA_BMS_GB_VER =0, //BMS 国标协议版本 0 2011版 1 2015版
E_BMS_PUT_DATA_BMS_STATE, //BMS 获取BMS状态 0无 1握手完成 2握手失败 3开始预充 4开始充电 5禁止充电 6停止充电 7报文接收超时
E_BMS_PUT_DATA_BMS_MAX_VOL, //BMS 最大充电电压值 精度 0.1V
E_BMS_PUT_DATA_BMS_MAX_CUR, //BMS 最大充电电流值 精度 0.1A
E_BMS_PUT_DATA_BMS_REAL_BATT_VOL, //BMS 当前电池电压值 精度 0.1V
E_BMS_PUT_DATA_BMS_NEED_VOL, //BMS 需求电压值 精度 0.1V
E_BMS_PUT_DATA_BMS_NEED_CUR, //BMS 需求电流值 精度 0.1A
E_BMS_PUT_DATA_BMS_CAN_SEND_CNT, //BMS 报文发送次数 参数值 0代表cem 1代表csd
E_BMS_PUT_DATA_BMS_STOP_RES, //BMS 停止原因 详看E_FAULT_INFO枚举内容 BMS部分
E_BMS_PUT_DATA_BMS_RECONN_FLAG, //BMS 重连标志 0不重连 1重连
E_BMS_PUT_DATA_GUN_SOC, //BMS SOC %
E_BMS_PUT_DATA_GUN_ONE_BATT_MAX_TEMP, //单体电池最大温度 度
E_BMS_PUT_DATA_GUN_ONE_BATT_MAX_VOL, //单体电池最大电压 0.1V
E_BMS_PUT_DATA_GUN_BATT_TYPE, //电池类型 01H,铅酸电池;02H:镍氢电池;03H:磷酸铁锂电池;04H:锰酸锂电池;05H:钴酸锂电池;
E_BMS_PUT_DATA_GUN_BATT_RATED_C10, //整车动力蓄电池系统额定容量,数据范围0~1000A.h,精度0.1
}E_BMS_PUT_DATA_TYPE;
/*------ Exported variables(变量定义) -------------------*/
/*------ Exported function prototypes (函数声明) -------*/
void v_bms_add_timer(void);
void v_delay_set_tymer_val(void);
U16_T u16_bms_get_sys_para(U8_T gunNo , E_BMS_GET_PARA_TYPE e_type);
U16_T u16_bms_put_data(U8_T gunNo , E_BMS_PUT_DATA_TYPE e_type,U8_T u8_dataPara);
void v_bms_put_vin_str(U8_T u8_gunNo,U8_T *u8_vin,U8_T u8_len);
void v_bms_get_rt_time(Comm_Time *time);
U8_T u8_bms_get_cst(U8_T gunNo,U8_T *u8_data);
void v_bms_get_pile_nun(U8_T *pilenum);
#if CAN_PLC_FLAG //欧标 CAN转PLC使能
U8_T u8_bms_get_gunLink(U8_T gunNo); //can 转PLC 获取枪连接状态
#endif
#ifdef __cplusplus
}
#endif
#endif /* BMS_INTERFACE_H */
+2681
View File
File diff suppressed because it is too large Load Diff
+247
View File
@@ -0,0 +1,247 @@
#ifndef BMS_TASK_H
#define BMS_TASK_H
#ifdef __cplusplus /*C++¼C*/
extern "C" {
#endif
/*------ Exported includes(ͷļ) ----------------------*/
#include "main.h"
#include "bms/bms_interface.h"
#include "bms/sae1939.h"
/*------ Exported macro() -------------------------*/
// BMS֡
#define GB_BMS_ADDR 0xF4
#define GB_CHARGER_ADDR 0x56
#define GB_BMS_PGN_CHM 0x002600
#define GB_BMS_PGN_BHM 0x002700
#define GB_BMS_PGN_CRM 0x000100
#define GB_BMS_PGN_BRM 0x000200
#define GB_BMS_PGN_BCP 0x000600
#define GB_BMS_PGN_CTS 0x000700
#define GB_BMS_PGN_CML 0x000800
#define GB_BMS_PGN_BRO 0x000900
#define GB_BMS_PGN_CRO 0x000A00
#define GB_BMS_PGN_BCL 0x001000
#define GB_BMS_PGN_BCS 0x001100
#define GB_BMS_PGN_CCS 0x001200
#define GB_BMS_PGN_BSM 0x001300
#define GB_BMS_PGN_BMV 0x001500
#define GB_BMS_PGN_BMT 0x001600
#define GB_BMS_PGN_BSP 0x001700
#define GB_BMS_PGN_BST 0x001900
#define GB_BMS_PGN_CST 0x001A00
#define GB_BMS_PGN_BSD 0x001C00
#define GB_BMS_PGN_CSD 0x001D00
#define GB_BMS_PGN_BEM 0x001E00
#define GB_BMS_PGN_CEM 0x001F00
#define GB_BRM_TIMEOUT_FLAG 0x01 //bit0:BRMijʱ
#define GB_BCP_TIMEOUT_FLAG 0x02 //bit1:BCPijʱ
#define GB_BRO_TIMEOUT_FLAG 0x04 //bit2:BROijʱ
#define GB_BCS_TIMEOUT_FLAG 0x08 //bit3:BCSijʱ
#define GB_BCL_TIMEOUT_FLAG 0x10 //bit4:BCLijʱ
#define GB_BST_TIMEOUT_FLAG 0x20 //bit5:BSTijʱ
#define GB_BSD_TIMEOUT_FLAG 0x40 //bit6:BSDijʱ
//ʱʱ -- ʱʹã
#define BMS_TIM_10MS (1*1)
#define BMS_TIM_50MS (5*1+1)
#define BMS_TIM_250MS (29*1)
#define BMS_TIM_500MS (50*1)
#define BMS_TIM_1S ((100+11+29)*1) //͵һcem Ҫ250ms
#define BMS_TIM_5S ((500+22+135)*1)
#define BMS_TIM_10S ((1000+12+250)*1)
#define BMS_TIM_60S ((6000+12+1498)*1)
/*------ Exported struct() --------------------*/
//BMSڶʱ־
typedef struct
{
U8_T cnt50ms; //50ms
U8_T cnt250ms; //250ms
U8_T cnt500ms; //500ms
U16_T u16_global_timerCnt; //ʱʱ,ʱ,ʱ£յĿ0
U16_T u16_bcl_timerCnt; //׶ͬʱж֡Ľӳʱʱbsmʹglobal
U16_T u16_bro_timerCnt; //׶Σglobal¼bro_aa60sʱøñ¼bro5볬ʱ
}T_BMS_TIM;
typedef enum
{
cnt50ms = 0,
cnt250ms,
cnt500ms,
cnt_global,
cnt_bcl, //BSD״̬
cnt_bro_aa,
}E_BMS_TIM;
typedef enum
{
GB_BMS_STOP=0, //ֹͣ
GB_BMS_HANDSHAKE_TX_CHM, //׶ΣͳCHMȴճBHM
//GB_BMS_HANDSHAKE_RX_BHM_OK, //׶ΣͳCHMѽճֳɹBHMϵͳԵȴʼֱʶCRM
GB_BMS_HANDSHAKE_TX_CRM_00, //ֱʶ׶ΣCRM_00ȴBMSͳʶBRM
GB_BMS_HANDSHAKE_TX_CRM_AA, //ֱʶ׶ΣյBMSͳʶBRMCRM_AAȴյسBCP
GB_BMS_CFG_TX_CTS_CML, //ý׶ΣյسBCPCTSCMLȴBMSɳ׼BRO
GB_BMS_CFG_RX_BRO_AA, //ý׶ΣյسBRO_00CTSCMLȴBMSɳ׼BRO_AA
GB_BMS_CFG_TX_CRO_00, //ý׶ΣBMSɳ׼BRO_AAͳ׼ɱCRO_00ȴCRO-AA
GB_BMS_CFG_TX_CRO_AA, //ý׶ΣBMSɳ׼BROͳ׼ɱCRO_AAȴյܳ״̬BCS/سBCL
//GB_BMS_CHARGE_RX_BCL, //׶Σյܳ״̬BCSȴյسBCL
GB_BMS_CHARGE_STAGE, //׶ΣCCSѽձBCSBCLBST/BSM(Ƿ쳣)/BMV/BMT/BSP(ѡ)
GB_BMS_CHARGE_TX_CST, //׶ΣͳֹCSTȴBMSֹBSTBMSͳƱBSD
GB_BMS_FINISH_RX_BSD, //׶ΣյBSDͳֹCSD
//GB_BMS_FINISH_RX_BSD_OK, //׶ΣյBSD
//GB_BMS_FINISH_TX_CSD, //׶ΣͳͳƱCSD
GB_BMS_TX_CEM, //ʹ
}GB_BMS_STATE_E;
/* BMS״̬ */
typedef enum
{
BMS_STATE_NONE=0, //ͨţBMSͳƱݲ
BMS_STATE_HANDSHAKE_START_OK, //
BMS_STATE_HANDSHAKE_FAIL, //ʧ
BMS_STATE_PRECHARGE, //Ԥ
BMS_STATE_CHARGING, //
BMS_STATE_BSM_FORBID, //УBSMʾֹ
BMS_STATE_STOP, //ֹͣУCST
BMS_STATE_TIMEOUT, //ijʱ(CEM/BEM)
BMS_STATE_ERR, //ݴ
}BMS_STATE_E;
typedef enum
{
E_BMS_STOP_NULL =0,
E_BMS_STOP_1000 = 1000,
E_BMS_STOP_1001 = 1001,
E_BMS_STOP_1011 = 1011,
E_BMS_STOP_15000 = 15000,
E_BMS_STOP_15001,
E_BMS_STOP_15002,
E_BMS_STOP_15003,
E_BMS_STOP_15004,
E_BMS_STOP_15005,
E_BMS_STOP_15006,
E_BMS_STOP_15007,
E_BMS_STOP_15008,
E_BMS_STOP_15009,
E_BMS_STOP_15010,
E_BMS_STOP_15011,
E_BMS_STOP_15012,
E_BMS_STOP_15013,
E_BMS_STOP_15014,
E_BMS_STOP_15015,
E_BMS_STOP_15016,
E_BMS_STOP_15017,
E_BMS_STOP_15018,
E_BMS_STOP_15019,
E_BMS_STOP_15020,
E_BMS_STOP_15021,
E_BMS_STOP_15022,
E_BMS_STOP_15023,
E_BMS_STOP_15024,
E_BMS_STOP_15025,
E_BMS_STOP_15026,
E_BMS_STOP_15027,
E_BMS_STOP_15028,
E_BMS_STOP_15029,
E_BMS_STOP_15030,
E_BMS_STOP_15031,
}E_BMS_STOP_INFO;
//BMSЭ
typedef enum
{
BMS_2011=0, //2011BMSЭ
BMS_2015, //2015BMSЭ
BMS_2023, //2023BMSЭ
BMS_PLC, //CANתPLC
}BMS_STANDARD_E;
/* BMSʵʱ */
typedef struct
{
GB_BMS_STATE_E e_state; //BMS״̬
BMS_STATE_E e_real_state; // bmsʵʱ״̬ //BMS״̬
E_BMS_STOP_INFO e_stop_info; //bmsֹͣԭ
BMS_STANDARD_E e_bms_standard; //BMS汾Э 2011 2015
U8_T u8_reconn_flag; //ǣϣ1ʼ
U8_T u8_cst_send_cnt; //cstʹ
U8_T u8_csd_send_cnt; //csdʹ
U8_T u8_cem_send_cnt; //cemʹ
U8_T u8_bms_rx_flag[BMS_RECV_TYPE_NUM]; //bmsѽձʶ01 //0bhm 1brm 2bcp 3bro 4bcs 5bcl 6bsm 7bmv 8bmt 9bst 10bsd 11bem
U16_T u16_timeout_flag; //ձijʱ CEM
U16_T u16_stoptimeflag ; //SC1ֹͣͱ־
//=============================BMSʵ==============================
BMS_BHM_DATA_T t_bhm_data;
BMS_BRM_DATA_T t_brm_data;
BMS_BCP_DATA_T t_bcp_data;
BMS_BSD_DATA_T t_bsd_data;
BMS_BCL_DATA_T t_bcl_data;
BMS_BCS_DATA_T t_bcs_data;
BMS_BSM_DATA_T t_bsm_data;
BMS_BMV_DATA_T t_bmv_data; //δʹ
BMS_BMT_DATA_T t_bmt_data; //δʹ
BMS_BEM_DATA_U t_bem_data;
BMS_CEM_DATA_U t_cem_data;
BMS_BST_DATA_U t_bst_data;
BMS_CST_DATA_U t_cst_data;
}S_BMS_RT_DATA;
typedef struct
{
CAN_DATA_T pt_msg; //ձĴ洢
DLL_DATA_T pt_dll; //SAE̿
}S_GB_BMS_CAN;
typedef struct
{
U8_T u8_gunCnt; //ǹ
U8_T u8_gb_enable; //ʹ
U8_T u8_gun_type[GUN_MAX_CNT]; //ǹ 1
#if CAN_PLC_FLAG //ŷ CANתPLCʹ
U8_T u8_gun_linkState[GUN_MAX_CNT]; //ӱ־ 0δǹ 1Ѳǹ
#endif
T_BMS_TIM t_bms_tim[GUN_MAX_CNT]; //bmsڶʱ־
S_GB_BMS_CAN s_gb_bms_can[GUN_MAX_CNT]; //BMS CANͽսӿ
S_BMS_RT_DATA s_bms_rt_data[GUN_MAX_CNT]; //BMSʵʱ
}S_BMS_DATA;
/*------ Exported variables() -------------------*/
/*------ Exported function prototypes -------*/
void v_bms_task(void *arg);
#ifdef __cplusplus
}
#endif
#endif /* BMS_TASK_H */
+46
View File
@@ -0,0 +1,46 @@
# bms 模块说明
> 路径:`app/bms/`
> 返回主说明:[README](../../README.md)
## 1. 模块职责
- 负责 BMS 通信报文收发与协议状态机处理;
- 管理 BMS 充电阶段控制、超时处理与异常状态;
- 提供与流程控制模块对接的 BMS 数据接口。
## 2. 关键文件
- `bms_task.c/h`
- `bms_interface.c/h`
- `sae1939.c/h`
## 3. 功能说明
- 周期接收/发送 BMS 报文并更新运行状态;
- 维护关键定时器(超时、等待、状态切换计时);
- 将 BMS 结果映射为流程层可用的控制/状态数据。
## 4. 调度与对外接口
该模块由 FreeRTOS 任务 `BmsComm` 周期运行(单位:ms),周期来自 `app/app_init/app_init.c`
- `BmsComm``5ms`(任务入口:`v_bms_task(void *arg)`
对外接口(来自 `bms_task.h / bms_interface.h`,列出主要用法入口):
- `uint16_t u16_bms_get_sys_para(U8_T gunNo, E_BMS_GET_PARA_TYPE e_type)`:读取 BMS 系统参数
- `uint16_t u16_bms_put_data(U8_T gunNo, E_BMS_PUT_DATA_TYPE e_type, U8_T u8_dataPara)`:设置/上报 BMS 数据(按 e_type 不同)
- `void v_bms_put_vin_str(U8_T u8_gunNo, U8_T *u8_vin, U8_T u8_len)`:写入 VIN 字符串
- `void v_bms_get_rt_time(Comm_Time *time)`:读取 BMS/系统时间(取决于实现)
- `U8_T u8_bms_get_cst(U8_T gunNo, U8_T *u8_data)`:读取充电阶段/状态相关值
- `void v_bms_get_pile_nun(U8_T *pilenum)`:读取桩侧枚举/数量(命名以代码为准)
## 5. 维护建议
- 修改报文处理流程时需同步校验超时逻辑;
- 与流程控制交互字段应保持枚举/状态码一致。
## 6. 关联文档
- 主索引:[README](../../README.md)
+417
View File
@@ -0,0 +1,417 @@
#include "bms/sae1939.h"
/*
缩写 全称 翻译
DLL data link layer 数据链路层
*/
#define TIMEOUT_T1 750 //750ms
#define TIMEOUT_T2 1250 //1250ms
#define TIMEOUT_T3 1250 //1250ms
#define TIMEOUT_T4 1050 //1050ms
#define TP_CM_PGN 0x00EC00 //CM-多包传输的连接管理
#define TP_DT_PGN 0x00EB00 //DT-多包数据传输
#define TP_CM_RTS 16 //RTS-请求发送
#define TP_CM_CTS 17 //CTS-允许发送
#define TP_CM_ENDOFMSGACK 19 //结束应答
#define TP_CM_ABORT 255 //放弃连接
static U16_T u16_timer_count = 0; //定时其计数值
/**
* ************************************************************************
* @brief - 用于上层清除底层的多包状态
*
* @param[in] pt_dll_data - 1393层数据
*
*
* @author jiankalka
* @date 2025-08-12
* ************************************************************************
*/
void v_sae1393_clear_multi_pacet(DLL_DATA_T *pt_dll_data)
{
pt_dll_data->e_msg_state = NONE;
}
/**
* ************************************************************************
* @brief - SAE1393层发送函数,单包报文直接发送,多包报文此函数只传送RTS,多包传输处理在u32_sae1393_rx内进行
* 注:27930中 不存在多包发送,此处仅考虑发送单包数据
* @param[in] pt_dll_data - 1393层数据
* @param[in] pt_can_data - 要送的报文
*
* @return U32_T - 0:发送成功,1:发送失败
*
* @author jiankalka
* @date 2025-08-12
* ************************************************************************
*/
U32_T u32_sae1393_tx(DLL_DATA_T *pt_dll_data, CAN_DATA_T *pt_can_data)
{
CAN_DATA t_msg;
U32_T i;
U8_T SendCmd = ((pt_can_data->u32_pgn & 0x0000FF00) >> 8);
memset(&t_msg, 0, sizeof(CAN_DATA));
if (pt_can_data->u16_len <= 8)
{
//单包发送
t_msg.ID = u32_get_can_ID(pt_can_data->u8_pri,SendCmd,pt_can_data->u8_dest_addr,pt_can_data->u8_src_addr); //组帧ID
t_msg.Len = pt_can_data->u16_len;
for (i=0; i<t_msg.Len; i++)
t_msg.Data[i] = pt_can_data->u8_data[i];
return pt_dll_data->u32_can_tx(&t_msg); //这样定义有助于多个can口复用
}
return 1;
}
void v_delay_set_tymer_val(void)
{
u16_timer_count ++;
}
U32_T u32_delay_get_timer_val()
{
return u16_timer_count;
}
//计算时间间隔(单位:ms) (b+MAX-a)%MAX
U32_T u32_delay_time_elapse(U32_T tim3_cnt_start, U32_T tim3_cnt_end)
{
if(tim3_cnt_end >= tim3_cnt_start)
return (tim3_cnt_end-tim3_cnt_start)*10;
else
return (65535-tim3_cnt_end+tim3_cnt_start-1)*10;
}
/**
* ************************************************************************
* @brief - SAE1393层接收函数,接收到多包请求后 发送cts应答报文
*
* @param[in] ExtId - 帧ID
* @param[in] Pgn - 多包帧pgn
* @param[in] pack_num - 包总数
* @param[in] pack_cnt - 请求包数
* @param[in] t_tx_msg - 组帧报文内容
*
*
* @author jiankalka
* @date 2025-08-13
* ************************************************************************
*/
void v_sae1939_cts_send(U32_T ExtId,U32_T Pgn, U8_T pack_num , U8_T pack_cnt, CAN_DATA *t_tx_msg)
{
t_tx_msg->ID = (ExtId & 0xFFFF0000);
t_tx_msg->ID |= ((ExtId & 0xFF00) >> 8 ); //帧ID目标地址 源地址转换
t_tx_msg->ID |= ((ExtId & 0x00FF) << 8 );
t_tx_msg->ID = (t_tx_msg->ID & 0xFF00FFFF)|(TP_CM_PGN << 8); //将帧ID PGN赋值为0xEC
t_tx_msg->Len = 8;
t_tx_msg->Data[0] = TP_CM_CTS;
t_tx_msg->Data[1] = pack_num;
t_tx_msg->Data[2] = pack_cnt;
t_tx_msg->Data[3] = 0xFF;
t_tx_msg->Data[4] = 0xFF;
t_tx_msg->Data[5] = ((Pgn >> 16) & 0xFF);
t_tx_msg->Data[6] = ((Pgn >> 8 ) & 0xFF);
t_tx_msg->Data[7] = ((Pgn ) & 0xFF);
}
/**
* ************************************************************************
* @brief - sae1939 放弃连接发送
*
* @param[in] ExtID - 帧ID
* @param[in] Pgn - 多包帧报文对应 PGN
* @param[in] t_tx_msg - 发送can数据组包
*
*
* @author jiankalka
* @date 2025-08-13
* ************************************************************************
*/
void v_sae1939_abort_send(U32_T ExtID, U32_T Pgn, CAN_DATA *t_tx_msg)
{
t_tx_msg->ID = (ExtID & 0xFFFF0000);
t_tx_msg->ID |= ((ExtID & 0xFF00) >> 8 ); //帧ID目标地址 源地址转换
t_tx_msg->ID |= ((ExtID & 0x00FF) << 8 );
t_tx_msg->Len = 8;
t_tx_msg->Data[0] = TP_CM_ABORT;
t_tx_msg->Data[1] = 0xFF;
t_tx_msg->Data[2] = 0xFF;
t_tx_msg->Data[3] = 0xFF;
t_tx_msg->Data[4] = 0xFF;
t_tx_msg->Data[5] = ((Pgn >> 16) & 0xFF);
t_tx_msg->Data[6] = ((Pgn >> 8 ) & 0xFF);
t_tx_msg->Data[7] = ((Pgn ) & 0xFF);
}
/*************************************************************
函数名称: v_sae1939_EndofMsgACK_send
函数功能: SAE1393层接收函数,放弃连接函数
输入参数: pt_dll_data 接收报文
输出参数: t_tx_msg 发送报文
返回值 void
**************************************************************/
/**
* ************************************************************************
* @brief - 多包完成接收 发送结束应答帧
*
* @param[in] pt_dll_data - sae1939 控制数据
* @param[in] t_tx_msg - 发送组包CAN数据
*
*
* @author jiankalka
* @date 2025-08-13
* ************************************************************************
*/
void v_sae1939_EndofMsgACK_send(DLL_DATA_T *pt_dll_data, CAN_DATA *t_tx_msg)
{
t_tx_msg->ID = ((U32_T)(pt_dll_data->u8_pri & 0x07) << 26);
t_tx_msg->ID |= ((TP_CM_PGN & 0x0000FF00) << 8);
t_tx_msg->ID |= ((pt_dll_data->u8_dest_addr & 0xFF) );
t_tx_msg->ID |= ((pt_dll_data->u8_src_addr & 0x00FF) << 8 );
t_tx_msg->Len = 8;
t_tx_msg->Data[0] = TP_CM_ENDOFMSGACK;
t_tx_msg->Data[1] = (U8_T)(pt_dll_data->u16_len);
t_tx_msg->Data[2] = (U8_T)(pt_dll_data->u16_len>>8);
t_tx_msg->Data[3] = (pt_dll_data->u16_len+6)/7;
t_tx_msg->Data[4] = 0xFF;
t_tx_msg->Data[5] = (U8_T)(pt_dll_data->u32_pgn);
t_tx_msg->Data[6] = (U8_T)(pt_dll_data->u32_pgn>>8);
t_tx_msg->Data[7] = (U8_T)(pt_dll_data->u32_pgn>>16);
}
/*************************************************************
函数名称: u32_sae1393_rx
函数功能: SAE1393层接收函数,此函数需要在BMS处理层主循环内调用,
处理报文的接收和多包报文的发送,也处理1393层的超时事件
输入参数: pt_dll_data -- 1393层数据, rxMsg -- 待解析的报文
输出参数: pt_can_data -- 保存接收到的完整报文
返回值 0:接收成功,pt_can_data指向的报文可用;1:接收失败,pt_can_data指向的报文不可用
**************************************************************/
/**
* ************************************************************************
* @brief - SAE1393层接收函数,此函数需要在BMS处理层主循环内调用,处理报文的接收和多包报文的发送,也处理1393层的超时事件
*
* @param[in] pt_dll_data - 1393层控制数据
* @param[in] pt_can_data - CAN解析存储数据
* @param[in] t_rx_msg - 接收CAN数据-原报文数据
*
* @return U32_T - 1说明接收完整帧 0未接收完整帧
*
* @author jiankalka
* @date 2025-08-13
* ************************************************************************
*/
U32_T u32_sae1393_rx(DLL_DATA_T *pt_dll_data, CAN_DATA_T *pt_can_data, CAN_DATA t_rx_msg)
{
CAN_DATA t_tx_msg;
U32_T u32_ret = 0;
U32_T i, u32_pgn,u32_data;
S32_T j;
U8_T u8_src_addr, u8_dest_addr, u8_pri, u8_r_dp, u8_data_len;
u8_pri = ((t_rx_msg.ID & 0x1C000000) >> 26); //优先级
u8_r_dp = ((t_rx_msg.ID & 0x03000000) >> 24); //0
u32_pgn = ((t_rx_msg.ID & 0x00FF0000) >> 8); //pgn - 是分辨多包使用,而不是bms数据内的bgn
u8_src_addr = t_rx_msg.ID & 0xFF; //源地址
u8_dest_addr = ((t_rx_msg.ID & 0x0000FF00) >> 8); //目标
u8_data_len = t_rx_msg.Len; //数据长度
(void)u8_r_dp;
if (u32_pgn == TP_CM_PGN) //接收帧为多包连接管理帧
{
if(u8_data_len != 8) //管理帧帧长度都为8
return u32_ret;
switch(t_rx_msg.Data[0])
{
case TP_CM_RTS: //接收到对方发送的请求发送报文,回复CTS(允许发送)
if ((pt_dll_data->e_msg_state == NONE) || //一级 状态为空闲时,直接接收
(((pt_dll_data->e_msg_state == RX_WAIT_DATA_T2) || (pt_dll_data->e_msg_state == RX_WAIT_DATA_T1)) && //一级 接收状态下 重复接收相同帧
(pt_dll_data->u32_pgn == ((t_rx_msg.Data[7]<<16) | (t_rx_msg.Data[6]<<8) | t_rx_msg.Data[5])) && //二级 接受帧pgn与正在接受的数据相同
(pt_dll_data->u8_src_addr == u8_src_addr) && (pt_dll_data->u8_dest_addr == u8_dest_addr))) //二级 接收帧 目标地址和发送地址相同
{
//回复CTS
u32_data = (U32_T)((t_rx_msg.Data[7]<<16) | (t_rx_msg.Data[6]<<8) | t_rx_msg.Data[5]);
v_sae1939_cts_send(t_rx_msg.ID ,u32_data, t_rx_msg.Data[3],1, &t_tx_msg);
if (pt_dll_data->u32_can_tx(&t_tx_msg) == 0) //发送成功
{
pt_dll_data->e_msg_state = RX_WAIT_DATA_T2;
pt_dll_data->u32_time = u32_delay_get_timer_val();
pt_dll_data->u32_pgn = (t_rx_msg.Data[7]<<16) | (t_rx_msg.Data[6]<<8) | t_rx_msg.Data[5]; //记录接收多包报文的pgn,有多个多包时也先收此pgn
pt_dll_data->u8_src_addr = u8_src_addr;
pt_dll_data->u8_dest_addr = u8_dest_addr;
pt_dll_data->u8_pri = u8_pri;
pt_dll_data->u16_len = ((U16_T)(t_rx_msg.Data[2])<<8) | t_rx_msg.Data[1];
pt_dll_data->u8_packet_cnt = t_rx_msg.Data[3];
pt_dll_data->u8_retry = 0;
//等待接收数据,将缓存区置0xFF
for (i=0; i<SAE1939_MULTI_PACKET_MAX_NUM; i++)
{
memset(pt_dll_data->t_packet[i].u8_data, 0xFF, 7);
pt_dll_data->t_packet[i].u8_flag = 0;
}
}
}
else //放弃连接
{
//回复Abort
u32_data = (U32_T)((t_rx_msg.Data[7]<<16) | (t_rx_msg.Data[6]<<8) | t_rx_msg.Data[5]);
v_sae1939_abort_send(t_rx_msg.ID , u32_data, &t_tx_msg);
pt_dll_data->u32_can_tx(&t_tx_msg);
pt_dll_data->e_msg_state = NONE;
}
break;
case TP_CM_ABORT: //结束应答
if ((pt_dll_data->e_msg_state == RX_WAIT_DATA_T2) ||
(pt_dll_data->e_msg_state == RX_WAIT_DATA_T1))
{
if ((u8_src_addr == pt_dll_data->u8_src_addr) &&
(pt_dll_data->u8_dest_addr == u8_dest_addr) &&
(pt_dll_data->u32_pgn == ((t_rx_msg.Data[7]<<16) | (t_rx_msg.Data[6]<<8) | t_rx_msg.Data[5])))
{
pt_dll_data->e_msg_state = NONE;
}
}
break;
default:
break;
}
}
else if (u32_pgn == TP_DT_PGN) //接收多包数据帧
{
if ((t_rx_msg.Len == 8) && //长度为8
(pt_dll_data->u8_src_addr == u8_src_addr) && (pt_dll_data->u8_dest_addr == u8_dest_addr) && //接收报文目标、发送地址与报存的一致
((pt_dll_data->e_msg_state == RX_WAIT_DATA_T2) || (pt_dll_data->e_msg_state == RX_WAIT_DATA_T1)) && //正在接收多包数据状态下
(t_rx_msg.Data[0] != 0)) //包序号不为0
{
pt_dll_data->e_msg_state = RX_WAIT_DATA_T1;
pt_dll_data->u32_time = u32_delay_get_timer_val();
pt_dll_data->t_packet[t_rx_msg.Data[0]-1].u8_flag = 1;
memcpy(pt_dll_data->t_packet[t_rx_msg.Data[0]-1].u8_data, &(t_rx_msg.Data[1]), 7);
for (i=0; i<pt_dll_data->u8_packet_cnt; i++) //找到未接收的包,即下一个要求上送的包
{
if (pt_dll_data->t_packet[i].u8_flag == 0)
break;
}
//多包数据接收完成
if (i >= pt_dll_data->u8_packet_cnt)
{
pt_dll_data->e_msg_state = NONE;
u32_ret = 1;
pt_can_data->u32_pgn = pt_dll_data->u32_pgn;
pt_can_data->u8_src_addr = u8_src_addr;
pt_can_data->u8_dest_addr = u8_dest_addr;
pt_can_data->u8_pri = u8_pri;
pt_can_data->u16_len = pt_dll_data->u16_len;
if (pt_can_data->u16_len > (SAE1939_MULTI_PACKET_MAX_NUM*7))
pt_can_data->u16_len = (SAE1939_MULTI_PACKET_MAX_NUM*7);
for (i=0; i<pt_can_data->u16_len; i++)
pt_can_data->u8_data[i] = pt_dll_data->t_packet[i/7].u8_data[i%7];
//发送EndofMsgACK
v_sae1939_EndofMsgACK_send(pt_dll_data,&t_tx_msg);
pt_dll_data->u32_can_tx(&t_tx_msg);
}
else if (pt_dll_data->t_packet[pt_dll_data->u8_packet_cnt-1].u8_flag == 1) //有包未接收,但是最后一包接收了,说明有丢包的 则重新申请丢的包
{
pt_dll_data->e_msg_state = RX_WAIT_DATA_T2;
pt_dll_data->u32_time = u32_delay_get_timer_val();
for (j=pt_dll_data->u8_packet_cnt-1; j>=0; j--)
{
if (pt_dll_data->t_packet[j].u8_flag == 0)
break;
}
//回复CTS
u32_data = pt_dll_data->u32_pgn;
t_rx_msg.ID = (t_rx_msg.ID & 0xFF00FFFF)|(TP_CM_PGN << 8); //将帧ID PGN赋值为0xEC
v_sae1939_cts_send(t_rx_msg.ID ,u32_data, j-i+1,i+1, &t_tx_msg);
pt_dll_data->u32_can_tx(&t_tx_msg);
}
}
}
else //单包数据
{
u32_ret = 1; //返回解析成功
pt_can_data->u32_pgn = u32_pgn;
pt_can_data->u8_src_addr = u8_src_addr;
pt_can_data->u8_dest_addr = u8_dest_addr;
pt_can_data->u8_pri = u8_pri;
pt_can_data->u16_len = t_rx_msg.Len;
for (i=0; i<t_rx_msg.Len; i++)
pt_can_data->u8_data[i] = t_rx_msg.Data[i];
}
#if 1
//超时处理
switch (pt_dll_data->e_msg_state)
{
case RX_WAIT_DATA_T2:
if (u32_delay_time_elapse(pt_dll_data->u32_time, u32_delay_get_timer_val()) > TIMEOUT_T2)
{
//回复Abort
u32_data = ((U32_T)(pt_dll_data->u8_pri & 0x07) << 26);
u32_data |= ((TP_CM_PGN & 0x0000FF00) << 8);
u32_data |= ((U32_T)(pt_dll_data->u8_src_addr) <<8 );
u32_data |= pt_dll_data->u8_dest_addr;
v_sae1939_abort_send(u32_data , pt_dll_data->u32_pgn, &t_tx_msg);
pt_dll_data->u32_can_tx(&t_tx_msg);
pt_dll_data->e_msg_state = NONE;
}
break;
case RX_WAIT_DATA_T1:
if (u32_delay_time_elapse(pt_dll_data->u32_time, u32_delay_get_timer_val()) > TIMEOUT_T1)
{
//回复Abort
u32_data = ((U32_T)(pt_dll_data->u8_pri & 0x07) << 26);
u32_data |= ((TP_CM_PGN & 0x0000FF00) << 8);
u32_data |= ((U32_T)(pt_dll_data->u8_src_addr) <<8 );
u32_data |= pt_dll_data->u8_dest_addr;
v_sae1939_abort_send(u32_data , pt_dll_data->u32_pgn, &t_tx_msg);
pt_dll_data->u32_can_tx(&t_tx_msg);
pt_dll_data->e_msg_state = NONE;
}
break;
default:
break;
}
#endif
return u32_ret;
}
+81
View File
@@ -0,0 +1,81 @@
#ifndef SAE1939_H
#define SAE1939_H
#ifdef __cplusplus /*C++编译环境下兼容C语言*/
extern "C" {
#endif
/*------ Exported includes(头文件) ----------------------*/
#include "main.h"
#include "bsp_include.h"
/*------ Exported macro(宏定义) -------------------------*/
#define SAE1939_MULTI_PACKET_MAX_NUM 80 //80*7 -- bmv需要512字节
typedef U32_T (*U32_CAN_RX)(CAN_DATA *s_canData);
typedef U32_T (*U32_CAN_TX)(CAN_DATA *s_canData);
/*------ Exported struct(结构体定义) --------------------*/
typedef struct
{
U32_T u32_pgn; //参数组编号
U8_T u8_src_addr; //源地址
U8_T u8_dest_addr; //目标地址
U8_T u8_pri; //优先级
U16_T u16_len; //长度,不能大于SAE1939_MULTI_PACKET_MAX_NUM*7
U8_T u8_data[SAE1939_MULTI_PACKET_MAX_NUM*7]; //数据
}CAN_DATA_T;
typedef enum
{
NONE=0, //无多包发送和接收
// //作为多包发送方使用
// TX_WAIT_CTS_T3, //己发送RTS,等待接收CTS,超时T3=1250ms
// TX_WAIT_CTS_T4, //等待接收保持连接CTS,超时T4=1050ms
//作为多包接收方使用
RX_WAIT_DATA_T2, //己发送CTS,等待接收数据,超时T2=1250ms
RX_WAIT_DATA_T1, //接收数据阶段,等待接收下一个数据包,超时T1=750ms
}MULTI_MSG_STATE_E;
//此数据结构在BMS通信开始化进行初始化,初始化完成后BMS层不能再修改此结构
typedef struct
{
MULTI_MSG_STATE_E e_msg_state; //多包解析流程状态
U8_T u8_packet_cnt; //包数量
U8_T u8_src_addr; //源地址
U8_T u8_dest_addr; //目标地址
U8_T u8_pri; //优先级
U8_T u8_retry; //重试次数
U16_T u16_len; //长度,不能大于 80*7
U32_T u32_pgn; //参数组编号
U32_T u32_time; //用于多包数据处理的计时
struct
{
U8_T u8_data[7]; //数据
U8_T u8_flag; //标记,0:未接收或未发送,1:己接收或己发送
}t_packet[SAE1939_MULTI_PACKET_MAX_NUM];
U32_CAN_TX u32_can_tx; //驱动层发送函数
U32_CAN_RX u32_can_rx; //驱动层接收函数 - 从缓冲区里读,不只接收一帧
}DLL_DATA_T;
/*------ Exported variables(变量定义) -------------------*/
/*------ Exported function prototypes (函数声明) -------*/
void v_sae1393_clear_multi_pacet(DLL_DATA_T *pt_dll_data);
U32_T u32_sae1393_tx(DLL_DATA_T *pt_dll_data, CAN_DATA_T *pt_can_data);
U32_T u32_sae1393_rx(DLL_DATA_T *pt_dll_data, CAN_DATA_T *pt_can_data, CAN_DATA t_rx_msg);
#ifdef __cplusplus
}
#endif
#endif /* SAE1939_H */