#include "mdu_comm/mdu_uuln_comm.h" #if MDU_UULN_EN #include "mdu_comm/mdu_interface.h" #include "mdu_comm/mdu_comm_task.h" #include "mdu_comm/mdu_stm_status_comm.h" #include "bsp_include.h" extern S_MDU_DATA s_mdu_data; /* 本协议使用优优绿能自定义协议,此协议与常规的CAN协议内容理解不一样 现做以下说明: ID 域报文格式定义如下: | 28:25 | 24:21 | 20:14 | 13:9 | 8:0 | |----------------|---------------------------|---------------------------|-------------------|-----------------------| | Protocol | MonitorAddress | ModuleAddress | ProductionDay | SerialNumberLowPart | | (协议号) | (监控地址) | (模块地址) | (生产日期) | (序列号低位) | |----------------|---------------------------|---------------------------|-------------------|-----------------------| | 0x01 | Monitor - (0x01~0x0F) | Module - (0x01~0x7F) | 1~31 (可选) | 0 (可选) | | | BroadCast - 0 | BroadCast - 0 | | | 详细内容说明详见协议文档,或者下方变量定义 U_UULN_CAN_ID_TYPE。 DATA 域规定内容如下: 字节0 : 字节 0 数据由两部分组成,高 4 位为组地址,低 4 位为信息类型; 变量定义为 U_UULN_DATA1_TYPE 字节1 : 命令信息类型。表示数据信息对应的命令类型。 变量定义为 E_UULN_CMD_TYPE 字节2 : 预留 字节3 : 预留 字节4 - 7 : 数据部分 详看协议文档 控制流程关键点(与厂家技术人员沟通所得): 1、正常充电,根据电池电压来设置模块高低压模式,然后设置需求电压,需求电流,开机 2、500v是切换点,如果跨过500v,先关机,切换高低压模式,然后设置电压电流开机 3、绝缘检测是根据绝缘电压先设定模块高低压模式,然后设置电压开机 */ #if 1 //发送组帧 /** * ************************************************************************ * @brief - 读取所有模块的状态标志位 * * @param[in] u8_grp_on - 读取组号 0为广播 1-2 * @param[in] e_cmd_type - 读取数据类型 详看枚举 E_UULN_CMD_TYPE * * send 2200000, 22 08 00 00 00 00 00 00 * recv 2209c2e, 23 08 00 00 00 00 00 00 * recv 2205c1c, 23 08 00 00 00 00 00 00 * * @author jiankalka * @date 2025-11-13 * ************************************************************************ */ static void v_uuln_send_read_all_data(U8_T u8_grp_on , E_UULN_CMD_TYPE e_cmd_type) { CAN_DATA can_data; U_UULN_CAN_ID_TYPE u_ID; U_UULN_DATA1_TYPE u_Data1; memset(&can_data , 0 , sizeof(CAN_DATA)); //帧ID赋值 u_ID.u32_ID = 0; u_ID.bit.Protocol = D_MDU_UULN_VER ; // 协议号 0x01 表示整流模块与监控之间的通讯协议号 u_ID.bit.MonitorAddress = 1 ; // 监控地址 地址设定在 0x01~0x0F,默认 0x01 0x00:代表广播通信 u_ID.bit.ModuleAddres = 0 ; // 整流模块地址 为整流模块地址,地址确定在 0x01-0x7F。 0x00:代表广播通信 u_ID.bit.ProductionDay = 0 ; // 产品生产日期(01-31)。 u_ID.bit.SerialNumberLowPart = 0 ; // 产品序列号低位(默认填 0)。 //DATA1 赋值 包括组地址和信息类型 u_Data1.u8_data = 0; u_Data1.bit.GroupAddress = u8_grp_on; // 0 广播 u_Data1.bit.MessageType = E_MAG_TYPE_READ_DATA; // 0x02 读模块信息 //组帧 CAN can_data.ID = u_ID.u32_ID; //组帧ID can_data.Len = 8; //组帧DATA can_data.Data[0] = u_Data1.u8_data; can_data.Data[1] = e_cmd_type ; //读取数据命令码 v_MduCanMsg_send(&can_data); } /** * ************************************************************************ * @brief - 模块参数设置 * * @param[in] u8_grp_on - 设置组号 1/2 不能设置0广播,控制分组控 * @param[in] e_cmd_type - 数据命令码 * @param[in] u32_data - 数据内容 注意精度转换 其中 电压电流精度为0.0001 * * * @author jiankalka * @date 2025-11-13 * ************************************************************************ */ static void v_uuln_send_set_all_data(U8_T u8_grp_on , E_UULN_CMD_TYPE e_cmd_type , U32_T u32_data) { CAN_DATA can_data; U_UULN_CAN_ID_TYPE u_ID; U_UULN_DATA1_TYPE u_Data1; if(u8_grp_on == 0) //组号为0 不做处理 return; memset(&can_data , 0 , sizeof(CAN_DATA)); //帧ID赋值 u_ID.u32_ID = 0; u_ID.bit.Protocol = D_MDU_UULN_VER ; // 协议号 0x01 表示整流模块与监控之间的通讯协议号 u_ID.bit.MonitorAddress = 1 ; // 监控地址 地址设定在 0x01~0x0F,默认 0x01 0x00:代表广播通信 u_ID.bit.ModuleAddres = 0 ; // 整流模块地址 为整流模块地址,地址确定在 0x01-0x7F。 0x00:代表广播通信 u_ID.bit.ProductionDay = 0 ; // 产品生产日期(01-31)。 u_ID.bit.SerialNumberLowPart = 0 ; // 产品序列号低位(默认填 0)。 //DATA1 赋值 包括组地址和信息类型 u_Data1.u8_data = 0; u_Data1.bit.GroupAddress = u8_grp_on; // 0 广播 u_Data1.bit.MessageType = E_MAG_TYPE_SET_PARA; // 0x00 设置模块参数 //组帧 CAN can_data.ID = u_ID.u32_ID; //组帧ID can_data.Len = 8; //组帧DATA can_data.Data[0] = u_Data1.u8_data; can_data.Data[1] = e_cmd_type ; //读取数据命令码 can_data.Data[2] = 0; can_data.Data[3] = 0; can_data.Data[4] = GetHigh24Bits(u32_data); //赋值数据 can_data.Data[5] = GetHigh16Bits(u32_data); can_data.Data[6] = GetHigh8Bits(u32_data); can_data.Data[7] = u32_data&0xFF; v_MduCanMsg_send(&can_data); } /** * ************************************************************************ * @brief - 单个模块参数设置 * * @param[in] u8_addr - 设置模块号 1-N 不能设置0广播 * @param[in] e_cmd_type - 数据命令码 * @param[in] u32_data - 数据内容 注意精度转换 其中 电压电流精度为0.0001 * * * @author jiankalka * @date 2025-11-13 * ************************************************************************ */ static void v_uuln_send_set_one_data(U8_T u8_addr , E_UULN_CMD_TYPE e_cmd_type , U32_T u32_data) { CAN_DATA can_data; U_UULN_CAN_ID_TYPE u_ID; U_UULN_DATA1_TYPE u_Data1; S_MDU_STATE *s_mdu_state = NULL; //模块状态 if(u8_addr == 0 || u8_addr > MDU_MAX_NUM) //模块号为0 或超过最大数量 不做处理 return; s_mdu_state = &s_mdu_data.s_mdu[u8_addr-1].s_state; //i号模块 状态数据结构体 memset(&can_data , 0 , sizeof(CAN_DATA)); //帧ID赋值 u_ID.u32_ID = 0; u_ID.bit.Protocol = D_MDU_UULN_VER ; // 协议号 0x01 表示整流模块与监控之间的通讯协议号 u_ID.bit.MonitorAddress = 1 ; // 监控地址 地址设定在 0x01~0x0F,默认 0x01 0x00:代表广播通信 u_ID.bit.ModuleAddres = u8_addr ; // 整流模块地址 为整流模块地址,地址确定在 0x01-0x7F。 0x00:代表广播通信 u_ID.bit.ProductionDay = 0 ; // 产品生产日期(01-31)。 u_ID.bit.SerialNumberLowPart = 0 ; // 产品序列号低位(默认填 0)。 //DATA1 赋值 包括组地址和信息类型 u_Data1.u8_data = 0; u_Data1.bit.GroupAddress = s_mdu_state->u8_groupNo; // 模块组号 u_Data1.bit.MessageType = E_MAG_TYPE_SET_PARA; // 0x00 设置模块参数 //组帧 CAN can_data.ID = u_ID.u32_ID; //组帧ID can_data.Len = 8; //组帧DATA can_data.Data[0] = u_Data1.u8_data; can_data.Data[1] = e_cmd_type ; //读取数据命令码 can_data.Data[2] = 0; can_data.Data[3] = 0; can_data.Data[4] = GetHigh24Bits(u32_data); //赋值数据 can_data.Data[5] = GetHigh16Bits(u32_data); can_data.Data[6] = GetHigh8Bits(u32_data); can_data.Data[7] = u32_data&0xFF; v_MduCanMsg_send(&can_data); } /** * ************************************************************************ * @brief - 设置模块1的组地址 * * @param[in] u8_addr - * @param[in] u8_grp_on - * * * @author jiankalka * @date 2025-11-12 * ************************************************************************ */ static void v_uuln_send_set_grp_no(U8_T u8_addr , U8_T u8_grp_on) { CAN_DATA can_data; U_UULN_CAN_ID_TYPE u_ID; U_UULN_DATA1_TYPE u_Data1; if(u8_addr >= MDU_MAX_NUM) return; memset(&can_data , 0 , sizeof(CAN_DATA)); //帧ID赋值 u_ID.u32_ID = 0; u_ID.bit.Protocol = D_MDU_UULN_VER ; // 协议号 0x01 表示整流模块与监控之间的通讯协议号 u_ID.bit.MonitorAddress = 1 ; // 监控地址 地址设定在 0x01~0x0F,默认 0x01 0x00:代表广播通信 u_ID.bit.ModuleAddres = u8_addr ; // 整流模块地址 为整流模块地址,地址确定在 0x01-0x7F。 0x00:代表广播通信 u_ID.bit.ProductionDay = 0 ; // 产品生产日期(01-31)。 u_ID.bit.SerialNumberLowPart = 0 ; // 产品序列号低位(默认填 0)。 //DATA1 赋值 包括组地址和信息类型 u_Data1.u8_data = 0; u_Data1.bit.GroupAddress = 0; // 0 广播 u_Data1.bit.MessageType = E_MAG_TYPE_SET_PARA; // 0x00 设置模块参数 //组帧 CAN can_data.ID = u_ID.u32_ID; //组帧ID can_data.Len = 8; //组帧DATA can_data.Data[0] = u_Data1.u8_data; can_data.Data[1] = E_GROUP_ADDRESS ; // 0x59 组地址 R/W Y can_data.Data[7] = u8_grp_on; //设置组号 v_MduCanMsg_send(&can_data); } #endif #if 1 //发送 /** * ************************************************************************ * @brief - 设置模块高低压状态 * * @param[in] u8_grp_on - 组号 1/2 0无意义 * @param[in] u8_flag - (1:1000V 2:500V ) * * @return U8_T - 是否执行切换步骤 1是 0否 * 执行切换步骤,包含控制模块停机、设置高低压状态等操作 执行时不许再控制模块启动 * * @author jiankalka * @date 2025-11-13 * ************************************************************************ */ static U8_T u8_uuln_set_grp_mdu_hlvol(U8_T u8_grp_on , E_TrueHiLo_Status e_flag) { U8_T i,u8_ret = 0; S_MDU_STATE *s_mdu_state = NULL; //模块状态 if(u8_grp_on == 0) return 0; //组号为0 无意义 for (i = 0; i < s_mdu_data.u8_mdu_num; i++) //遍历所有模块 检查模块状态和分组情况 { s_mdu_state = &s_mdu_data.s_mdu[i].s_state; //i号模块 状态数据结构体 if(s_mdu_state->e_state != E_MDU_STATE_NORMAL || //模块正常 且组号一致 s_mdu_state->u8_groupNo != u8_grp_on) continue; if(e_flag != s_mdu_state->e_TrueHiLo_Status) //状态不一致 则设置状态 { u8_ret = 1; if(s_mdu_state->e_work_state == E_MDU_WORK) //停模块 { v_uuln_send_set_one_data(i+1,E_DCDC_MODULE_POWER_CONTROL,1); // 0x04 DCDC模块开关机 W N 模块开关机(0 开机,1 关机) #if MDU_CAN_PRINT_FLAG printf("mdu[%d](0-N) set hl vol state ,ctrl mdu off\r\n",i); #endif } else { v_uuln_send_set_one_data(i+1,E_MODULE_HIGH_LOW_VOLTAGE_MODE,e_flag); // 0x5F 模块高低压模式 W Y (1:1000V 2:500V ) #if MDU_CAN_PRINT_FLAG printf("mdu[%d](0-N) set hl vol state [%d] -> [%d]\r\n",i,s_mdu_state->e_TrueHiLo_Status,e_flag ); #endif } } } return u8_ret; } /** * ************************************************************************ * @brief - 充电模块启停控制 包含需求电压电流下发和启停控制等 内部包含模块高低压状态切换功能 * * * * @author jiankalka * @date 2025-11-13 * ************************************************************************ */ static void v_uuln_mdu_set_ctrl() { /* 周期发送 */ U8_T gunNo,u8_flag,u8_gunState; S_MDU_GROUP_DATA *s_mdu_group = NULL; //模块组数据 for (gunNo = 0; gunNo < s_mdu_data.u8_mdu_group_num; gunNo++) //遍历模块组数量 { s_mdu_group = &s_mdu_data.s_mdu_group[gunNo]; //获取i模块组数据结构体 //模块 高低压状态检查 500V if(s_mdu_group->u16_needVol != 0) //需求电压为0时 无意义 不用做检查 { if(s_mdu_group->u16_needVol > 5000) //需求电压大于500V 则设置为高压状态 { //返回值1 则代表存在设置过程 其中包含停机操作 因此不必执行下方的控制命令 if(u8_uuln_set_grp_mdu_hlvol(gunNo+1 , E_TrueHiLo_H)) //设置模块高低压状态 1000V { continue; } } else //需求电压小于500V 则设置为底压状态 { //返回值1 则代表存在设置过程 其中包含停机操作 因此不必执行下方的控制命令 if(u8_uuln_set_grp_mdu_hlvol(gunNo+1 , E_TrueHiLo_L)) //设置模块高低压状态 500V { continue; } } } #if( MDU_PARA_READ_EN == 1) //模块参数读取使能 if(s_mdu_data.u16_mduPara_MaxOutVol != 0 && s_mdu_group->u16_needVol > s_mdu_data.u16_mduPara_MaxOutVol) s_mdu_group->u16_needVol = s_mdu_data.u16_mduPara_MaxOutVol; else if(s_mdu_group->u16_needVol < s_mdu_data.u16_mduPara_MinOutVol) s_mdu_group->u16_needVol = s_mdu_data.u16_mduPara_MinOutVol; if(s_mdu_data.u16_mduPara_MaxOutCur != 0 && s_mdu_group->u16_oneMdu_needCur > s_mdu_data.u16_mduPara_MaxOutCur) s_mdu_group->u16_oneMdu_needCur = s_mdu_data.u16_mduPara_MaxOutCur; else if(s_mdu_group->u16_oneMdu_needCur < s_mdu_data.u16_mduPara_MinOutCur) s_mdu_group->u16_oneMdu_needCur = s_mdu_data.u16_mduPara_MinOutCur; #endif v_uuln_send_set_all_data(gunNo+1,E_MODULE_VOLTAGE_SETPOINT,s_mdu_group->u16_needVol*100); // 0x02 模块输出电压设定值 R/W N 数据精度 0.0001V mV v_uuln_send_set_all_data(gunNo+1,E_MODULE_CURRENT_LIMIT_SETPOINT,s_mdu_group->u16_oneMdu_needCur *100); // 0x03 模块输出限流点设定值 R/W N 数据精度 0.0001V mV u8_gunState = u16_mdu_get_charge_need(gunNo, E_MDU_GET_DATA_GUN_CMD) ; //枪状态 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组) /*0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组) */ if(u8_gunState == 0x01 || u8_gunState== 0x03) { u8_flag = 0; //开机 } else { u8_flag = 1; //关机 } v_uuln_send_set_all_data(gunNo+1,E_DCDC_MODULE_POWER_CONTROL,u8_flag); // 0x04 DCDC模块开关机 W N DCDC 模块开关机(0 开机,1 关机) } } /** * ************************************************************************ * @brief - 模块组号设置检查 设置模块数量除以2 前半部分设置组号为1 后半部分设置组号为2 * * * * @author jiankalka * @date 2025-11-12 * ************************************************************************ */ static void v_uuln_mdu_grp_cheak() { U8_T i,u8_mdu_grp; S_MDU_CTRL *s_mdu_ctrl = NULL; //模块控制 S_MDU_STATE *s_mdu_state = NULL; //模块状态 for ( i = 0; i < s_mdu_data.u8_mdu_num; i++) //遍历所有模块 { s_mdu_ctrl = &s_mdu_data.s_mdu[i].s_ctrl; //i号模块 控制数据结构体 s_mdu_state = &s_mdu_data.s_mdu[i].s_state; //i号模块 状态数据结构体 if(s_mdu_state->e_state == E_MDU_STATE_NONE) continue; // if(i < ((s_mdu_data.u8_mdu_num+1) / 2)) // 前半部分为1枪 后半部分为2枪 模块数量为奇数时,1枪多一个 // u8_mdu_grp = 1; // else // u8_mdu_grp = 2; u8_mdu_grp = s_mdu_ctrl->u8_mdu_in_pile; if(s_mdu_state->u8_groupNo != u8_mdu_grp) //模块组号不正确 设置模块组号 { v_uuln_send_set_grp_no(i+1,u8_mdu_grp); } } } /** * ************************************************************************ * @brief -模块通信发送控制函数 * * * * @author jiankalka * @date 2025-07-03 * ************************************************************************ */ static void v_uuln_mdu_comm_send_ctrl(U16_T u16_sleepTime) { if(s_mdu_data.u16_timer % NUM_250 == 0) //250ms { v_mdu_data_summ(); //模块组信息更新 v_uuln_mdu_set_ctrl(); //模块设置控制 } if(s_mdu_data.u16_timer % NUM_1000 == 0) //1秒 { v_uuln_send_read_all_data(0,E_MODULE_STATUS_FLAGS); //读取所有模块的状态标志位 组1 组2 } else if(s_mdu_data.u16_timer % NUM_1000 == u16_sleepTime) //1秒 与上一帧间隔 一个周期 { v_uuln_send_read_all_data(0,E_MODULE_OUTPUT_VOLTAGE); //0x00 模块输出电压 R N } else if(s_mdu_data.u16_timer % NUM_1000 == u16_sleepTime*2) //1秒 与上一帧间隔 一个周期 { v_uuln_send_read_all_data(0,E_MODULE_OUTPUT_CURRENT); //0x00 0x01 模块输出电流 R N if(s_mdu_data.u16_mduPara_MaxOutVol == 0xFF || s_mdu_data.u16_mduPara_MaxOutCur == 0xFF) v_uuln_send_read_all_data(0,E_MODULE_CURRENT_AND_CAPABILITY); // 0x72 读取模块输出电流和输出电流能力 R N 单位:0.1A(高十六位:模块的实际输出电流,低十六位:实际的电流能力) } else if(s_mdu_data.u16_timer % NUM_1000 == u16_sleepTime*3) //1秒 与上一帧间隔 一个周期 { v_uuln_send_read_all_data(0,E_MODULE_HIGH_LOW_VOLTAGE_STATUS); // 0x60 读取模块高低压模式状态 R N } else if(s_mdu_data.u16_timer % NUM_1000 == u16_sleepTime*4) //1秒 与上一帧间隔 一个周期 { v_uuln_send_read_all_data(0,E_INLET_AIR_TEMPERATURE); // 0x1E 进风口温度 R N } if(s_mdu_data.u16_timer % NUM_5000 == 0) //5秒 { v_uuln_mdu_grp_cheak(); //模块组号设置检查 } } #endif #if 1 //接收 static void v_uuln_mdu_rx_unpack(CAN_DATA *rxMsg) { U_UULN_CAN_ID_TYPE u_ID; E_UULN_CMD_TYPE e_cmd_type; U_UULN_DATA1_TYPE u_Data1; U8_T u8_addr; U32_T u32_recv_data; S_MDU_STATE *s_mdu_state = NULL; u_ID.u32_ID = rxMsg->ID; //获取ID u8_addr = u_ID.bit.ModuleAddres-1; //模块地址 e_cmd_type = rxMsg->Data[1]; //数据类型 u_Data1.u8_data = rxMsg->Data[0]; //信息类型 和 组地址 /* 抢连接/DI 状态:交给 STM 状态通信模块解析(ID 0x1801AABB) */ #if (GUN_LINK_COMM_EN) if (u8_stm_gb_enable() && u8_stm_status_can_rx(rxMsg)) return; #endif if(u_ID.bit.Protocol != D_MDU_UULN_VER) //协议号 不一致 return; if(u_Data1.bit.MessageType != E_MAG_TYPE_SET_ACK && u_Data1.bit.MessageType != E_MAG_TYPE_READ_ACK )//信息类型 不正确 return; if(u8_addr >= MDU_MAX_NUM) return; #if MDU_CAN_PRINT_FLAG printf("mdu[%d](0-N) cmd is [%d]\r\n",u8_addr,e_cmd_type ); #endif s_mdu_state = &s_mdu_data.s_mdu[u8_addr].s_state; //获取模块状态 s_mdu_state->u16_outtimecnt = 0; //超时计数 清零 //获取4-7字节数据内容 转换为整形 u32_recv_data = (rxMsg->Data[4] << 24) | (rxMsg->Data[5] << 16) | (rxMsg->Data[6] << 8) | rxMsg->Data[7]; switch (e_cmd_type) { case E_MODULE_STATUS_FLAGS : // 0x08 模块状态标志位 R N { U_UULN_MDU_STATUS u_state; #if MDU_CAN_PRINT_FLAG printf("mdu[%d](0-N) grp is [%d],work state is [%d]\r\n",u8_addr,u_Data1.bit.GroupAddress,1-u_state.bit.DcdcNotRun ); #endif u_state.all = u32_recv_data; s_mdu_state->u8_GrpMode = 1; //默认都是动态分组 模块分组模式 0固定分组 1动态分组 s_mdu_state->u8_groupNo = u_Data1.bit.GroupAddress; //组号 if (u_state.bit.DcdcNotRun == 0) //工作状态,1待机,2工作 s_mdu_state->e_work_state = E_MDU_WORK; else s_mdu_state->e_work_state = E_MDU_IDLE; // 故障判断:如果存在任何故障点位或预留点位非零则判为故障,否则正常 if (u_state.all & FAULT_MASK) { // 存在故障,进行故障处理 if(s_mdu_state->e_state != E_MDU_STATE_NONE) s_mdu_state->e_state = E_MDU_STATE_FAULT; //故障状态 s_mdu_state->u_alarm_data.bit_mdu_alarm.b0_other = 1; //其他故障,0正常,1故障 // s_mdu_state->u_alarm_data.bit_mdu_alarm.b1_relief = ISBITSET(rxMsg->Data[1],1); //泄放故障 // s_mdu_state->u_alarm_data.bit_mdu_alarm.b2_fan = ISBITSET(rxMsg->Data[1],2); //风扇故障 // s_mdu_state->u_alarm_data.bit_mdu_alarm.b3_DC_short = ISBITSET(rxMsg->Data[1],3); //直流输出短路 // s_mdu_state->u_alarm_data.bit_mdu_alarm.b4_overTemp = ISBITSET(rxMsg->Data[1],4); //过温 // s_mdu_state->u_alarm_data.bit_mdu_alarm.b5_DC_UV = ISBITSET(rxMsg->Data[1],5); //直流输出欠压 // s_mdu_state->u_alarm_data.bit_mdu_alarm.b6_DC_OV = ISBITSET(rxMsg->Data[1],6); //直流输出过压 // s_mdu_state->u_alarm_data.bit_mdu_alarm.b7_AC_IN = ISBITSET(rxMsg->Data[1],7); //交流输入故障 } else { if(s_mdu_state->e_state == E_MDU_STATE_FAULT) s_mdu_state->e_state = E_MDU_STATE_NONE; s_mdu_state->u_alarm_data.u8_mdu_alarm = 0; } s_mdu_state->u_uuln_state.all = u_state.all; break; } case E_GROUP_ADDRESS : // 0x59 组地址 R/W Y { break; } case E_MODULE_OUTPUT_VOLTAGE: // 0x00 模块输出电压 R N { //模块输出电压 mV s_mdu_state->u16_outVol = u32_recv_data / 100; //直流输出电压 0.1V #if MDU_CAN_PRINT_FLAG printf("mdu[%d](0-N) grp is [%d],put vol is [%d](0.1V)\r\n",u8_addr,u_Data1.bit.GroupAddress,s_mdu_state->u16_outVol ); #endif break; } case E_MODULE_OUTPUT_CURRENT: // 0x01 模块输出电流 R N { //模块输出电流 mA s_mdu_state->u16_outCur = u32_recv_data/100; //直流输出电流 0.1A #if MDU_CAN_PRINT_FLAG printf("mdu[%d] grp is [%d],put cur is [%d](0.1A)\r\n",u8_addr,u_Data1.bit.GroupAddress,s_mdu_state->u16_outCur ); #endif break; } case E_MODULE_HIGH_LOW_VOLTAGE_STATUS: // 0x60 读取模块高低压模式状态 R N { //读取模块实际的高低压档位状态(1:1000V2:500V ) s_mdu_state->e_TrueHiLo_Status = (E_TrueHiLo_Status)u32_recv_data; //高低压状态读取 1: 1000V 2: 500V #if MDU_CAN_PRINT_FLAG printf("mdu[%d](0-N) grp is [%d],高低压模式状态 is [%d](1:1000V 2:500V)\r\n",u8_addr,u_Data1.bit.GroupAddress,s_mdu_state->e_TrueHiLo_Status ); #endif } case E_INLET_AIR_TEMPERATURE: // 0x1E 进风口温度 R N 毫度 { s_mdu_state->s8_mdutemp_1 = u32_recv_data / 1000; //毫度 #if MDU_CAN_PRINT_FLAG printf("mdu[%d](0-N) grp is [%d], in fan temp is [%d](1:1000V 2:500V)\r\n",u8_addr,u_Data1.bit.GroupAddress,s_mdu_state->s8_mdutemp_1 ); #endif break; } case E_MODULE_CURRENT_AND_CAPABILITY: // 0x72 读取模块输出电流和输出电流能力 R N 单位:0.1A(高十六位:模块的实际输出电流,低十六位:实际的电流能力) { //模块输出电流 mA s_mdu_state->u16_outCur = ((u32_recv_data >> 16)&0xFFFF); //直流输出电流 0.1A if(s_mdu_data.u16_mduPara_MaxOutCur == 0xFF) //未赋值 则赋值模块最大输出电流值 { s_mdu_data.u16_mduPara_MaxOutVol = 1000*10; //默认1000V s_mdu_data.u16_mduPara_MinOutVol = 0; s_mdu_data.u16_mduPara_MaxOutCur = (u32_recv_data & 0xFFFF)/10; s_mdu_data.u16_mduPara_MinOutCur = 0; } #if MDU_CAN_PRINT_FLAG printf("mdu[%d] grp is [%d],put cur is [%d][%d](0.1A)\r\n",u8_addr,u_Data1.bit.GroupAddress,s_mdu_state->u16_outCur ,s_mdu_data.u16_mduPara_MaxOutCur); #endif break; } default: break; } } /** * ************************************************************************ * @brief -模块通信接收解包函数 * * * * @author jiankalka * @date 2025-07-03 * ************************************************************************ */ static void v_uuln_mdu_comm_recv_unpack() { U8_T i, canRcvCnt = 0; //接收can报文数目 CAN_DATA rx_can_data[CAN_RECV_BUF_SIZE] = {0}; canRcvCnt= u8_MduCanMsg_recv(&rx_can_data[0]); //DEBUG_LOG("fdcan1 recv num = %d\n",ret); for (i = 0; i < canRcvCnt; i++) { v_uuln_mdu_rx_unpack(&rx_can_data[i]); } } #endif #if 1 //通信超时 /** * ************************************************************************ * @brief -模块控制 报文接收超时检查 * * * * @author jiankalka * @date 2025-07-03 * ************************************************************************ */ static void v_uuln_mdu_comm_outtime_cheak(U16_T u16_sleepTime) { U8_T i,u8_mdu_num = s_mdu_data.u8_mdu_num; //模块数量 U8_T u8_mdu_comm_err_num = 0; //通信超时模块数量 S_MDU_STATE *s_mdu_state = NULL; for(i=0;ie_state == E_MDU_STATE_NONE) //模块未通信 判断通信 { u8_mdu_comm_err_num ++; if(s_mdu_state->u16_outtimecnt < 10*NUM_1000) //10秒超时 { s_mdu_state->e_state = E_MDU_STATE_NORMAL; //通信正常 Mdu_Comm_LOG("(%d)号充电模块通讯正常\n",i); } v_mdu_set_comm_fault_info(i,1); //故障动作触发 } else{ //模块已通信 判断超时 s_mdu_state->u16_outtimecnt += u16_sleepTime; //超时计数递增 if(s_mdu_state->u16_outtimecnt > 20*NUM_1000) //10秒超时 { s_mdu_state->e_state = E_MDU_STATE_NONE; v_mdu_clear_recv_data(i); Mdu_Comm_LOG("(%d)号充电模块通讯超时\n",i); } else if(s_mdu_state->e_state == E_MDU_STATE_NORMAL && s_mdu_state->u16_outtimecnt > 10*NUM_1000 && s_mdu_state->u16_outtimecnt < 20*NUM_1000) { /* 10s无报文:按需可强制重初始化,这里默认强制 */ uint8_t act = CANSPI_HealthCheckAndRecover(1U); if (act == 0U) { printf("time=%d, 模块(%d) 10s无报文,但总线/控制器自检正常,暂不复位\r\n", get_current_seconds(), i); } s_mdu_state->u16_outtimecnt = 0; } else { } v_mdu_set_comm_fault_info(i,0); //故障恢复触发 } } if(u8_mdu_comm_err_num == u8_mdu_num) //所有模块通信故障 { v_mdu_set_comm_fault_info(MODULE_ALL,1); //故障恢复触发 } else { v_mdu_set_comm_fault_info(MODULE_ALL,0); //故障恢复触发 } } /** * ************************************************************************ * @brief - 枪未连接 充电模块通信超时恢复 * * * * @author jiankalka * @date 2025-11-20 * ************************************************************************ */ static void v_uuln_mdu_gun_no_link_outtime_claer() { U8_T i,u8_mdu_num = s_mdu_data.u8_mdu_num; //模块数量 v_mdu_set_comm_fault_info(MODULE_ALL,0); //故障恢复触发 for(i=0;i