#include "mdu_comm/mdu_comm_task.h" #include "app_init/app_init.h" #if MDU_UULN_EN #include "mdu_comm/mdu_uuln_comm.h" #endif #include "mdu_comm/mdu_stm_status_comm.h" #include "PCM_comm.h" #include "app_init/task_lock.h" #include "mylog/mylog.h" #include "publicdata/publicdata.h" #include "wdt_task/wdt_task.h" #include "bsp_include.h" #include "flowctrl/flow_interface.h" #define MDUCOMM_TASK_ID (TASK_ID_MduComm) #define MDUCOMM_SLEEP_TIME_MS() (MY_GET_SLEEP_TIME(MDUCOMM_TASK_ID)) #define MDUCOMM_LOCK_INIT() (u8_task_lock_ctrl(MDUCOMM_TASK_ID, TASK_LOCK_OP_INIT)) #define MDUCOMM_LOCK_TAKE() (u8_task_lock_ctrl(MDUCOMM_TASK_ID, TASK_LOCK_OP_TAKE)) #define MDUCOMM_LOCK_GIVE() (u8_task_lock_ctrl(MDUCOMM_TASK_ID, TASK_LOCK_OP_GIVE)) #define MDUCOMM_FEED_DOG() (v_wdt_setFlag(MDUCOMM_TASK_ID)) #define MDUCOMM_LOG(fmt, ...) MYLOG_MSG(MDUCOMM_TASK_ID, (fmt), ##__VA_ARGS__) /****************************************************************************************** * 文件名称 : mdu_comm_task.c * 创建时间 : 2025-07-02 15:38:10 * 功能负责人 : jiankalka * 文件功能说明 : 本文件用于... * * @修改记录 * 修改时间 修改人 修改说明 * 2025-07-02 15:38:10 jiankalka 首次创建 *******************************************************************************************/ #define CAN_SEND_SLEEP (5) //报文发送睡眠时间 用于间隔报文发送 S_MDU_DATA s_mdu_data; #if 1 // /** * ************************************************************************ * @brief -CAN * @brief -模块任务CAN数据发送函数接口 * * @param[in] can_data -发送报文结构体指针 * * @author jiankalka * * @date 2025-07-02 * ************************************************************************ */ void v_MduCanMsg_send(CAN_DATA* can_data) { v_can_tx(MDU_CAN_ID, can_data); mSleep(CAN_SEND_SLEEP); s_mdu_data.u8_can_send_cnt++; #if MDU_CAN_PRINT_FLAG v_print_can_data(MDU_CAN_PRINT_FLAG,"mdu send", can_data); // 添加了消息前缀 #endif } /** * ************************************************************************ * @brief -模块任务CAN数据接收函数接口 * * @param[in] rx_can_data -接收CAN数据结构体指针,此为结构体数组 可返回多个can报文数据 * * @return U32_T -返回接收报文数量 * @author jiankalka * @date 2025-07-02 * ************************************************************************ */ U8_T u8_MduCanMsg_recv(CAN_DATA *rx_can_data) { U8_T ret = u8_can_rx(MDU_CAN_ID, rx_can_data); #if MDU_CAN_PRINT_FLAG U8_T k; // 使用U8_T而不是size_t以保持一致性 for (k = 0; k < ret; k++) { v_print_can_data(MDU_CAN_PRINT_FLAG,"mdu recv", &rx_can_data[k]); // 添加了消息前缀 } #endif return ret; } #endif #if 1 //报文组帧 /** * ************************************************************************ * @brief -组心跳帧 * * * * @author jiankalka * @date 2025-07-03 * ************************************************************************ */ void v_mdu_send_Heartbeat() { CAN_DATA can_data; memset(&can_data , 0 , sizeof(CAN_DATA)); can_data.ID = u32_get_can_ID(0x06,MODULE_CMD_HEARTBEAT,MODULE_BROADCAST_ADDR,MODULE_PILE_ADDR); //组帧ID can_data.Len = 8; v_MduCanMsg_send(&can_data); } /** * ************************************************************************ * @brief -设置模块为动态分组 * * @param[in] u8_id -设置模块地址序号 0-N * @param[in] type -设置信息 1固定分组,2动态分组 * * * @author jiankalka * @date 2025-07-03 * ************************************************************************ */ void v_mdu_send_setGroupMode(U8_T u8_id,U8_T type) { CAN_DATA can_data; U8_T u8_mdu_addr = s_mdu_data.s_mdu[u8_id].u8_mdu_addr; memset(&can_data , 0 , sizeof(CAN_DATA)); can_data.ID = u32_get_can_ID(0x06,MODULE_CMD_SETTING,u8_mdu_addr,MODULE_PILE_ADDR); //组帧ID can_data.Len = 8; can_data.Data[0] = 0x01; //第一帧报文序号 can_data.Data[1] = 0x02; //总报文数 can_data.Data[2] = 0x07; //报文长度=7 can_data.Data[3] = 0x00; can_data.Data[4] = 0x00; //接口标识 can_data.Data[5] = 0x04; //设备类型:4=充电模块 can_data.Data[6] = u8_mdu_addr; //设备通信地址 can_data.Data[7] = 0x0D; //定值序号:13=设置分组模式 v_MduCanMsg_send(&can_data); can_data.Data[0] = 0x02; //第二帧报文序号 can_data.Data[1] = 0x00; //定值序号 can_data.Data[2] = 0x00; //预留 can_data.Data[3] = type; //定值信息:1固定分组,2动态分组 can_data.Data[4] = 0x1A + type + u8_mdu_addr; //和校验 can_data.Data[5] = 0x00; can_data.Data[6] = 0x00; can_data.Data[7] = 0x00; v_MduCanMsg_send(&can_data); } /** * ************************************************************************ * @brief -广播读取模块温度 * * * * @author YZG * @date 2025-09-15 * ************************************************************************ */ void v_mdu_temp_read() { CAN_DATA can_data; memset(&can_data , 0 , sizeof(CAN_DATA)); can_data.ID = u32_get_can_ID(0x06,MODULE_CMD_TEMP,MODULE_BROADCAST_ADDR,MODULE_PILE_ADDR); //组帧ID can_data.Len = 8; v_MduCanMsg_send(&can_data); } void v_mdu_send_getMduPara(U8_T u8_id,U8_T type) { CAN_DATA can_data; U8_T u8_mdu_addr = s_mdu_data.s_mdu[u8_id].u8_mdu_addr; U8_T u8_data_id = 17+type; memset(&can_data , 0 , sizeof(CAN_DATA)); can_data.ID = u32_get_can_ID(0x06,MODULE_CMD_GETTING,u8_mdu_addr,MODULE_PILE_ADDR); //组帧ID can_data.Len = 8; can_data.Data[0] = 0x01; //第一帧报文序号 can_data.Data[1] = 0x02; //总报文数 can_data.Data[2] = 0x05; //报文长度=5 can_data.Data[3] = 0x00; can_data.Data[4] = 0x00; //接口标识 can_data.Data[5] = 0x04; //设备类型:4=充电模块 can_data.Data[6] = u8_mdu_addr; //设备通信地址 can_data.Data[7] = u8_data_id; //定值序号:17 最大电压 v_MduCanMsg_send(&can_data); can_data.Data[0] = 0x02; //第二帧报文序号 can_data.Data[1] = 0x00; //定值序号 can_data.Data[2] = 0x0B + u8_data_id + u8_mdu_addr; //和校验 can_data.Data[3] = 0x00; can_data.Data[4] = 0x00; can_data.Data[5] = 0x00; can_data.Data[6] = 0x00; can_data.Data[7] = 0x00; v_MduCanMsg_send(&can_data); } /** * ************************************************************************ * @brief -设置模块组号 * * @param[in] u8_id - 设置模块地址序号 0-N * @param[in] NewgrpID - 新设置模块组号 1-N (type == 1时有效) * @param[in] type - 设置类型 0取消设置,1设置组号 * * * @author jiankalka * @date 2025-07-18 * ************************************************************************ */ void v_mdu_send_setGroupId(U8_T u8_id, U8_T NewgrpID, U8_T type) //动态分组,设置组号 { CAN_DATA can_data; U8_T u8_mdu_addr = s_mdu_data.s_mdu[u8_id].u8_mdu_addr; memset(&can_data , 0 , sizeof(CAN_DATA)); can_data.ID = u32_get_can_ID(0x06,MODULE_CMD_GROUP_SET,u8_mdu_addr,MODULE_PILE_ADDR); //组帧ID can_data.Len = 8; if(type == 1) can_data.Data[0] = 0x30; //命令码,分组设置,间断地址 else can_data.Data[0] = 0x50; //命令码,分组撤销,间断地址 can_data.Data[1] = NewgrpID; //组号 can_data.Data[2] = 0x01; //地址数目 can_data.Data[3] = u8_mdu_addr; can_data.Data[4] = 0x00; can_data.Data[5] = 0x00; can_data.Data[6] = 0x00; can_data.Data[7] = 0x00; v_MduCanMsg_send(&can_data); } /** * ************************************************************************ * @brief - 模块发送遥控命令 * * @param[in] e_mode - 命令模式 SEND_MODE_UNICAST, ///< 单点发送:命令发送给特定目标设备 SEND_MODE_BROADCAST ///< 广播发送:命令发送给所有设备 * @param[in] u8_addr - 发送地址 如果是广播,则此地址为组号 1-N ;如果不是广播,则此地址为模块序号 * @param[in] e_kyType - 控制指令 MDU_YK_FASTBOOT=1, //快速开机(绝缘检测阶段使用) MDU_YK_STOP_SUSPEND, //停止充电(保留分组信息) MDU_YK_SOFTSTART, //软启开机(预启动阶段使用) MDU_YK_SHOWADDR, //显示地址(显示模块通信地址) MDU_YK_SETPARA, //参数修改 MDU_YK_STOP, //停止充电(自动清除分组信息) * @param[in] s_data - 遥控数据 包含两个接触器状态 和 需求电压、需求电流、电池电压 精度0.1;当为NULL时,全部数据默认为0 * * * @author jiankalka * @date 2025-07-03 * ************************************************************************ */ void v_mdu_send_RemoteCtlr(E_CommandSendMode e_mode, U8_T u8_addr, E_MDU_YK_TYPE e_kyType, S_MDU_RemoteCtlrData *s_data) { CAN_DATA can_data; WordAlign Temp; U_MDU_YK_DEVICE_STATUS status; U16_T u16_needVol,u16_needCur,u16_battVol; U8_T GrpID = (e_mode == SEND_MODE_BROADCAST)?u8_addr:s_mdu_data.s_mdu[u8_addr].s_state.u8_groupNo; //组号 如果是广播,则直接使用传递的组号;如果是单点,或者模块对应的组号 U8_T desAddr = (e_mode == SEND_MODE_BROADCAST)? MODULE_BROADCAST_ADDR:s_mdu_data.s_mdu[u8_addr].u8_mdu_addr; //目的地址 是广播还是组号 memset(&can_data , 0 , sizeof(CAN_DATA)); can_data.ID = u32_get_can_ID(0x06,MODULE_CMD_REMOTE_CONTROL,desAddr,MODULE_PILE_ADDR); //组帧ID can_data.Len = 8; if(s_data != NULL){ //不为空则赋值 //设置状态值 status.raw = s_data->u_dev_state.raw; //除遥控命令外 都初始化好了 status.bits.operationCommand = (U8_T)e_kyType; // Bit3~0: 遥控命令 u16_needVol = s_data->u16_needVol; u16_needCur = s_data->u16_oneMdu_needCur; u16_battVol = s_data->u16_battVol; #if( MDU_PARA_READ_EN == 1) //模块参数读取使能 if(u16_needVol > s_mdu_data.u16_mduPara_MaxOutVol && s_mdu_data.u16_mduPara_MaxOutVol != 0) u16_needVol = s_mdu_data.u16_mduPara_MaxOutVol; else if (u16_needVol < s_mdu_data.u16_mduPara_MinOutVol && s_mdu_data.u16_mduPara_MinOutVol != 0) u16_needVol = s_mdu_data.u16_mduPara_MinOutVol; if(u16_battVol > s_mdu_data.u16_mduPara_MaxOutVol && s_mdu_data.u16_mduPara_MaxOutVol != 0) u16_battVol = s_mdu_data.u16_mduPara_MaxOutVol; else if (u16_battVol < s_mdu_data.u16_mduPara_MinOutVol && s_mdu_data.u16_mduPara_MinOutVol != 0) u16_battVol = s_mdu_data.u16_mduPara_MinOutVol; if(u16_needCur > s_mdu_data.u16_mduPara_MaxOutCur && s_mdu_data.u16_mduPara_MaxOutCur != 0) u16_needCur = s_mdu_data.u16_mduPara_MaxOutCur; else if (u16_needCur < s_mdu_data.u16_mduPara_MinOutCur && s_mdu_data.u16_mduPara_MinOutCur != 0) u16_needCur = s_mdu_data.u16_mduPara_MinOutCur; #endif } else{ //为空则清零 status.raw = 0; status.bits.operationCommand = (U8_T)e_kyType; // Bit3~0: 遥控命令 u16_needVol = 0; u16_needCur = 0; u16_battVol = 0; } can_data.Data[0] = status.raw; can_data.Data[1] = GrpID; Temp.word = u16_needVol; can_data.Data[2] = Temp.byte.ucLow; //设定电压 can_data.Data[3] = Temp.byte.ucHi; Temp.word = u16_needCur*10; can_data.Data[4] = Temp.byte.ucLow; //需求电流 can_data.Data[5] = Temp.byte.ucHi; Temp.word = u16_battVol; can_data.Data[6] = Temp.byte.ucLow; //电池电压 can_data.Data[7] = Temp.byte.ucHi; v_MduCanMsg_send(&can_data); } #endif #if 1 //f发送相关 /** * ************************************************************************ * @brief -检查模块分组模式 如不是动态分组模块。则改为动态分组模式 * * * * @author jiankalka * @date 2025-07-03 * ************************************************************************ */ void v_mdu_group_mode_check() { U8_T i,u8_mdu_num = s_mdu_data.u8_mdu_num; //模块数量 for(i=0;iu8_mdu_in_pile == 0){ //清空模块归属 检查模块运行状态后清空 if(s_mdu_state->u8_groupNo != 0){ if(s_mdu_state->e_work_state == E_MDU_WORK) //模块工作中 发送停止充电命令 - v_mdu_send_RemoteCtlr(SEND_MODE_UNICAST,i, MDU_YK_STOP, NULL); //单播控制 控制模块停止(清除分组) else v_mdu_send_setGroupId(i,0,0); //模块未工作 清空分组 } } else if(s_mdu_state->u8_groupNo != s_mdu_ctrl->u8_mdu_in_pile ) //模块状态与设置分组不一致 则设置模块分组 { v_mdu_send_setGroupId(i,s_mdu_ctrl->u8_mdu_in_pile,1); } } } /** * ************************************************************************ * @brief -模块数据汇总 用于统计 模块在用数量、剩余可用数量、组内模块数量、模块组输出电压、输出电流等信息,获取模块的控制的数据 * * * * @author jiankalka * @date 2025-07-18 * * * * ************************************************************************ */ void v_mdu_data_summ() { U8_T i,u8_groupNo; S_MDU_GROUP_DATA *s_mdu_group = NULL; //模块组数据 U8_T u8_gunState[GUN_MAX_CNT]; for ( i = 0; i < s_mdu_data.u8_mdu_group_num; i++) //遍历所有模块组 获取数据 { s_mdu_group = &s_mdu_data.s_mdu_group[i]; //获取i模块组数据结构体 memset(s_mdu_group , 0 ,sizeof(S_MDU_GROUP_DATA)); //清空 s_mdu_group->u_yk_dev_state.bits.mainContactor = u16_mdu_get_charge_need(i, E_MDU_GET_DATA_MAIN_KY); //主回路接触器状态 - 组内模块 有一个继电器没闭合 就是断开的 s_mdu_group->u_yk_dev_state.bits.powerContactor =u16_mdu_get_charge_need(i, E_MDU_GET_DATA_POWER_KY); //功率回路接触器状 - 组内模块 有一个继电器没闭合 就是断开的 s_mdu_group->u16_needVol = u16_mdu_get_charge_need(i, E_MDU_GET_DATA_NEED_VOL); //需求电压 0.1V s_mdu_group->u16_oneMdu_needCur = u16_mdu_get_charge_need(i, E_MDU_GET_DATA_NEED_CUR_ONE); //需求电流 0.1A s_mdu_group->u16_battVol = u16_mdu_get_charge_need(i, E_MDU_GET_DATA_BAAT_VOL); //电池电压 0.1V if(s_mdu_group->u16_needVol > 5000) //500V 为高压 s_mdu_group->u_yk_dev_state.bits.voltageRange = 1; u8_gunState[i] = u16_mdu_get_charge_need(i, E_MDU_GET_DATA_GUN_CMD) ; //枪状态 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组) } //更新可用模块数量 在用模块数量信息 s_mdu_data.u8_mdu_usable_num = 0; s_mdu_data.u8_mdu_using_num = 0; for ( i = 0; i < s_mdu_data.u8_mdu_num; i++) //遍历所有模块 { //更新模块控制信息 s_mdu_data.s_mdu[i].s_ctrl.u8_mdu_in_pile = u16_mdu_get_charge_need(i,E_MDU_GET_DATA_IN_PILE_ID ); //模块对应开关闭合标志 s_mdu_data.s_mdu[i].s_ctrl.u8_swh_flag = s_mdu_data.s_mdu[i].s_ctrl.e_mdu_start_flag;//u16_mdu_get_charge_need(i,E_MDU_GET_DATA_SHW_ON_FLAG); //模块归属终端号 if(s_mdu_data.s_mdu[i].s_ctrl.u8_mdu_in_pile != 0) { U8_T u8_inGun = s_mdu_data.s_mdu[i].s_ctrl.u8_mdu_in_pile - 1; if(u8_gunState[u8_inGun] == 1 || u8_gunState[u8_inGun] == 3) //终端启动 则控制启动 s_mdu_data.s_mdu[i].s_ctrl.e_mdu_start_flag = (E_CMD)1; //模块启停状态 else s_mdu_data.s_mdu[i].s_ctrl.e_mdu_start_flag = (E_CMD)0; } if(s_mdu_data.s_mdu[i].s_state.e_state == E_MDU_STATE_NORMAL) //通信正常 且不是故障 { s_mdu_data.u8_mdu_usable_num ++; if(s_mdu_data.s_mdu[i].s_ctrl.u8_mdu_in_pile != 0) //模块已分配 s_mdu_data.u8_mdu_using_num ++; } //更新模块组运行模块数量、输出电压、输出电流等数据 u8_groupNo = s_mdu_data.s_mdu[i].s_state.u8_groupNo; //获取模块组号 if(u8_groupNo != 0 && u8_groupNo <= GUN_MAX_CNT) //模块组号不为0 且组号在枪数量范围内 { s_mdu_data.s_mdu_group[u8_groupNo-1].u8_on_group_num++; if(s_mdu_data.s_mdu[i].s_state.e_work_state == 1) //组内有一个模块工作 则状态为工作 s_mdu_data.s_mdu_group[u8_groupNo-1].u8_work_state = 1; if(s_mdu_data.s_mdu_group[u8_groupNo-1].u16_outVol < NUM_500 && //如果模块组输出电压未赋值 s_mdu_data.s_mdu[i].s_ctrl.u8_swh_flag == 1) //且 模块对应继电器回路已经闭合 则赋值模块组电压 { s_mdu_data.s_mdu_group[u8_groupNo-1].u16_outVol = s_mdu_data.s_mdu[i].s_state.u16_outVol; } s_mdu_data.s_mdu_group[u8_groupNo-1].u16_outCur += s_mdu_data.s_mdu[i].s_state.u16_outCur; //组内模块输出电流累加 } } } /** * ************************************************************************ * @brief - 检查组内模块运行状态 ;检查该组号下模块的启停情况,若有一模块未启动,则下发启动命令 * 当模块启动标志为1,模块运行状态为0或者 回路继电器闭合标志为0 则需要启动;当模块启动状态为0,模块运行状态为1时,则控制停止 * * @param[in] u8_group - 组号 * * @return S8_T - 0 没有模块需要控制 >0 该起没起的第一个模块号 <0 该停没停的第一个模块号;例如返回2,表示存在该起未起的模块,模块号为2;返回-2,表示存在该停未停的模块,模块号为2; * * @author jiankalka * @date 2025-07-07 * ************************************************************************ */ S8_T s8_mdu_check_grp_running(U8_T u8_group) { S8_T s8_res = 0; U8_T i; 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->u8_groupNo == u8_group) //如果模块归属该枪 { if(s_mdu_ctrl->e_mdu_start_flag ==1 && (s_mdu_state->e_work_state ==0 || s_mdu_ctrl->u8_swh_flag == 0)) //控起未起 模块启动标志为1,模块运行状态为0或者 回路继电器闭合标志为0 则需要启动 { s8_res = i+1; break; } else if(s_mdu_ctrl->e_mdu_start_flag ==0 &&s_mdu_state->e_work_state ==1) //控停未停 { s8_res = -i-1; break; } } } return s8_res; } /** * ************************************************************************ * @brief -模块遥控指令发送 周期发送遥控指令 250ms一个周期 * * * * @author jiankalka * @date 2025-07-03 * ************************************************************************ */ void v_mdu_remote_control_send() { U8_T gunNo,u8_gunState; S8_T s8_mduNo; S_MDU_RemoteCtlrData s_RemoteCtlrData; //遥控命令数据 包含两个接触器状态 和 需求电压、需求电流、电池电压 精度0.1 S_MDU_GROUP_DATA *s_mdu_group = NULL; //模块组数据 v_mdu_data_summ(); //模块和模块组信息更新 for (gunNo = 0; gunNo < s_mdu_data.u8_mdu_group_num; gunNo++) //变量所有模块组状态 /枪状态 { memset(&s_RemoteCtlrData, 0, sizeof(S_MDU_RemoteCtlrData)); s_mdu_group = &s_mdu_data.s_mdu_group[gunNo]; //获取i模块组数据结构体 if(s_mdu_group->u8_on_group_num == 0) //归属于本枪的模块数量为0 不发送遥控指令;模块组为0,模块未停止情况 在模块数据检查中处理 continue; s_RemoteCtlrData.u_dev_state.raw = s_mdu_group->u_yk_dev_state.raw; //设备状态 s_RemoteCtlrData.u16_needVol = s_mdu_group->u16_needVol; s_RemoteCtlrData.u16_battVol = s_mdu_group->u16_battVol; s_RemoteCtlrData.u16_oneMdu_needCur = s_mdu_group->u16_oneMdu_needCur; u8_gunState = u16_mdu_get_charge_need(gunNo, E_MDU_GET_DATA_GUN_CMD) ; //枪状态 0无 1快速启机 2快速启机停(不清空分组) 3软启开机 4充电停止(清空分组) #if 1 //双枪母联使用 直接按组控 switch (u8_gunState) { case 1: //枪状态 1快速启机 { //检测该组内模块启动状态 - 未启动 则控制启动,启动则修改参数 s8_mduNo = s8_mdu_check_grp_running(gunNo+1); if(s8_mduNo > 0) //检测该组内模块启动状态 - 未启动 则控制启动;都已经启动,发送参数修改 v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1,MDU_YK_FASTBOOT,&s_RemoteCtlrData); //快速启机 else v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1,MDU_YK_SETPARA,&s_RemoteCtlrData); //参数修改 } break; case 2: //枪状态 2快速启机停 { v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1, MDU_YK_STOP_SUSPEND, NULL); //广播命令, 快速启动停止、 } break; case 3: //枪状态 3软启开机 { //检测该组内模块启动状态 - 未启动 则控制启动,启动则修改参数 s8_mduNo = s8_mdu_check_grp_running(gunNo+1); if(s8_mduNo > 0) //检测该组内模块启动状态 - 未启动 则控制启动;都已经启动,发送参数修改 v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1,MDU_YK_SOFTSTART,&s_RemoteCtlrData); //快速启机 else v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1,MDU_YK_SETPARA,&s_RemoteCtlrData); //参数修改 } break; case 0: //枪状态 0无 case 4: //枪状态 4软停 { if(s_mdu_group->u16_outVol > NUM_500) //组内输出电压 大于5V 则发送停止命令;否则不执行 v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1, MDU_YK_STOP, NULL); //广播命令, 快速启动停止、 } break; } #endif #if 0 switch (u8_gunState) { case 1: //枪状态 1快速启机 { //检测该组内模块启动状态 - 未启动 则控制启动,启动则修改参数 s8_mduNo = s8_mdu_check_grp_running(gunNo+1); if(s8_mduNo > 0) //检测该组内模块启动状态 - 未启动 则控制启动;都已经启动,发送参数修改 v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1,MDU_YK_FASTBOOT,&s_RemoteCtlrData); //快速启机 else v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1,MDU_YK_SETPARA,&s_RemoteCtlrData); //参数修改 } break; case 2: //枪状态 2快速启机停 { v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1, MDU_YK_STOP_SUSPEND, NULL); //广播命令, 快速启动停止、 } break; case 3: //枪状态 3软启开机 s8_mduNo = s8_mdu_check_grp_running(gunNo+1); if(s8_mduNo > 0) //检测该组内模块启动状态 - 有该起没起的,控制启动;有该停没停的,控制停止;不需要操作的,发送参数修改广播 { //单点其余正常使用模块 参数修改 for(j=0;ju8_groupNo == gunNo+1 && //模块归属本枪 s_mdu_state->u16_outVol > NUM_500 && //模块输出电压大于5V j!=(-s8_mduNo-1)) //不为控制停止的模块 { v_mdu_send_RemoteCtlr(SEND_MODE_UNICAST,j,MDU_YK_SETPARA,&s_RemoteCtlrData); //参数修改 } } if(s_mdu_group->u16_outVol > NUM_500) //组内输出电压 大于50V 则使用组内输出电压控制模块启动;否则则按需求启动 { s_RemoteCtlrData.u16_needVol = s_mdu_group->u16_outVol; s_RemoteCtlrData.u16_battVol = s_mdu_group->u16_outVol; s_RemoteCtlrData.u16_oneMdu_needCur = NUM_5; } //单点控制启动的模块 启动 if(s_mdu_data.s_mdu[s8_mduNo-1].s_state.e_work_state == 0) v_mdu_send_RemoteCtlr(SEND_MODE_UNICAST,s8_mduNo-1,MDU_YK_SOFTSTART,&s_RemoteCtlrData); //软启开机 else v_mdu_send_RemoteCtlr(SEND_MODE_UNICAST,s8_mduNo-1,MDU_YK_SETPARA,&s_RemoteCtlrData); //软启开机 } else if(s8_mduNo < 0) { //单点控停的模块 停止 v_mdu_send_RemoteCtlr(SEND_MODE_UNICAST,-s8_mduNo-1,MDU_YK_STOP_SUSPEND,&s_RemoteCtlrData); //单点其余正常使用模块 参数修改 for(j=0;ju8_groupNo == gunNo+1 && //模块归属本枪 s_mdu_state->u16_outVol > NUM_500 && //模块输出电压大于5V j!=(-s8_mduNo-1)) //不为控制停止的模块 { v_mdu_send_RemoteCtlr(SEND_MODE_UNICAST,j,MDU_YK_SETPARA,&s_RemoteCtlrData); //参数修改 } } } else v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1,MDU_YK_SETPARA,&s_RemoteCtlrData); //参数修改 break; case 0: //枪状态 0无 case 4: //枪状态 4软停 { if(s_mdu_group->u16_outVol > NUM_500) //组内输出电压 大于5V 则发送停止命令;否则不执行 v_mdu_send_RemoteCtlr(SEND_MODE_BROADCAST,gunNo+1, MDU_YK_STOP, NULL); //广播命令, 快速启动停止、 } break; default: break; } #endif } } /** * ************************************************************************ * @brief -模块参数获取 - 自动查询第一个模块的 * * * * @author jiankalka * @date 2025-07-22 * ************************************************************************ */ void v_mdu_para_check() { U8_T i,type,u8_mdu_num = s_mdu_data.u8_mdu_num; //模块数量 if(s_mdu_data.u16_mduPara_MaxOutVol == 0xFF){ type = 0; } else if(s_mdu_data.u16_mduPara_MinOutVol == 0xFF){ type = 1; } else if(s_mdu_data.u16_mduPara_MaxOutCur == 0xFF){ type = 2; } else if(s_mdu_data.u16_mduPara_MinOutCur == 0xFF){ type = 3; } else return; for(i=0;iID, NULL , &u8_cmd, &u8_desAddr , &u8_oriAddr) == 0) //解析帧id return; if(u8_desAddr != MODULE_PILE_ADDR) //判断目的地址是否一致 return; u8_boxid = u8_oriAddr - MODULE_MDU_FIRST_ADDR ; //充电模块号; if(u8_boxid > s_mdu_data.u8_mdu_num || u8_boxid > MDU_MAX_NUM) //地址范围合法性判断 return; s_mdu_state = &s_mdu_data.s_mdu[u8_boxid].s_state; //获取模块状态 s_mdu_state->u16_outtimecnt = 0; //超时计数 清零 switch(u8_cmd) { case MODULE_CMD_HEARTBEAT_ACK: //0x41 心跳应答 广播心跳不应答 { return; } case MODULE_CMD_YXYC_20: //0x20 遥信遥测 0x20帧 { s_mdu_state->u8_GrpMode = ISBITSET(rxMsg->Data[0],3); //模块分组模式 0固定分组 1动态分组 if(ISBITSET(rxMsg->Data[0],4) || ISBITSET(rxMsg->Data[0],5)) //故障状态 或者告警状态置一 { if(s_mdu_state->e_state != E_MDU_STATE_NONE) s_mdu_state->e_state = E_MDU_STATE_FAULT; //故障状态 } else { if(s_mdu_state->e_state == E_MDU_STATE_FAULT) s_mdu_state->e_state = E_MDU_STATE_NONE; } if (ISBITSET(rxMsg->Data[0],7)) //工作状态,1待机,2工作 s_mdu_state->e_work_state = E_MDU_WORK; else s_mdu_state->e_work_state = E_MDU_IDLE; temp.byte.ucLow = rxMsg->Data[2]; temp.byte.ucHi = rxMsg->Data[3]; s_mdu_state->u16_outVol = temp.word; //直流输出电压 0.1V temp.byte.ucLow= rxMsg->Data[4]; temp.byte.ucHi = rxMsg->Data[5]; s_mdu_state->u16_outCur = temp.word/10; //直流输出电流 0.1A s_mdu_state->u8_groupNo = rxMsg->Data[6]; //组号 s_mdu_state->u_alarm_data.bit_mdu_alarm.b0_other = ISBITSET(rxMsg->Data[1],0); //其他故障,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); //交流输入故障 return; } case MODULE_CMD_YXYC_21: //0x21 遥信遥测 0x21帧 { return; } case MODULE_CMD_SETTING_ACK: //0x81 //定值设置应答 { return; } case MODULE_CMD_GETTING_ACK: //0x83 //定值查询应答 { #if( MDU_PARA_READ_EN == 1) //模块参数读取使能 // 01 02 08 00 00 04 60 11 ; 02 00 80 10 27 36 01 if(rxMsg->Data[0] == 1){ //首包 memset(&s_mdu_data.u8_recv_most_pack[0] , 0 , 20); //清空多包解析缓存区 memcpy(&s_mdu_data.u8_recv_most_pack[0] , &rxMsg->Data[1] , 7); //将数据包存入缓存区 } else if(rxMsg->Data[0] == 2){ memcpy(&s_mdu_data.u8_recv_most_pack[7] , &rxMsg->Data[1] , 7); //将数据包存入缓存区 if(s_mdu_data.u8_recv_most_pack[0] == 0x02 //报文总帧数 && s_mdu_data.u8_recv_most_pack[1] == 0x08 //报文数量 && s_mdu_data.u8_recv_most_pack[8] == 0x80) //解析成功标志 { if(u16_crc_checksum(&s_mdu_data.u8_recv_most_pack[0] , 11) == \ (s_mdu_data.u8_recv_most_pack[11] + (s_mdu_data.u8_recv_most_pack[12] <<8))) { u16_data = s_mdu_data.u8_recv_most_pack[9] + (s_mdu_data.u8_recv_most_pack[10] <<8); if(s_mdu_data.u8_recv_most_pack[6] == 17) //最大输出电压 0.1V { s_mdu_data.u16_mduPara_MaxOutVol = u16_data; } else if(s_mdu_data.u8_recv_most_pack[6] == 18) //最小输出电压 0.1V { s_mdu_data.u16_mduPara_MinOutVol = u16_data; } else if(s_mdu_data.u8_recv_most_pack[6] == 19) //最大输出电流 0.01A { s_mdu_data.u16_mduPara_MaxOutCur = u16_data / 10; } else if(s_mdu_data.u8_recv_most_pack[6] == 20) //最小输出电流 0.01A { s_mdu_data.u16_mduPara_MinOutCur = u16_data / 10; } } } } #endif return; } case MODULE_CMD_TEMP: //0xE6 模块温度查询解帧 { u16_data = GetU16Data(rxMsg->Data[1],rxMsg->Data[0]); s_mdu_state->s8_mdutemp_1 = (S8_T)(u16_data - MODULE_TEMP_OFFSET); //进风口温度,报文解析数据减去偏移量为模块温度 u16_data = GetU16Data(rxMsg->Data[3],rxMsg->Data[2]); s_mdu_state->s8_mduPara_2 = (S8_T)(u16_data - MODULE_TEMP_OFFSET); //模块PFC温度; return; } default: return; } } /** * ************************************************************************ * @brief -模块通信接收解包函数 * * * * @author jiankalka * @date 2025-07-03 * ************************************************************************ */ void v_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_mdu_rx_unpack(&rx_can_data[i]); test_cnt++; } } #endif /** * ************************************************************************ * @brief - 清空模块接收数据内容 * * @param[in] u8_id - 模块id 0-N ,当为0xFF时 清空所有模块接收数据--除去非接收数据 例如超时计数值\模块状态 * * * @author jiankalka * @date 2025-09-17 * ************************************************************************ */ void v_mdu_clear_recv_data(U8_T u8_id) { U8_T i,u8_mdu_num = s_mdu_data.u8_mdu_num; //模块数量 S_MDU_STATE *s_mdu_state = NULL; for(i=0;ie_work_state = E_MDU_IDLE; //模块工作状态 空闲、工作 s_mdu_state->u8_groupNo = 0; //模块组号 s_mdu_state->u8_GrpMode = 0; //分组模式:【遥测分组模式:0固定分组,1动态分组】 s_mdu_state->u16_outVol = 0; //输出电压 精度0.1 s_mdu_state->u16_outCur = 0; //输出电流 精度0.1 s_mdu_state->u_alarm_data.u8_mdu_alarm = 0; //故障告警数据 0x20 遥信遥测帧上送 //模块温度读取使能 #if( MDU_TEMP_READ_EN == 1) s_mdu_state->s8_mdutemp_1 = 0; //模块温度1 进风口温度 单位摄氏度 注意有正负号 范围是 -127 ~ 127 s_mdu_state->s8_mduPara_2 = 0; //模块温度2 模块PFC温度 单位摄氏度 注意有正负号 范围是 -127 ~ 127 #endif } } } /** * ************************************************************************ * @brief -模块控制 报文接收超时检查 * * * * @author jiankalka * @date 2025-07-03 * ************************************************************************ */ void v_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 { } 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); //故障恢复触发 } } static void v_mdu_clear_outtime() { U8_T i,u8_mdu_num = s_mdu_data.u8_mdu_num; //模块数量 for(i=0;i= TASK_RUN_PRINT_TIME)) { if (MDUCOMM_LOCK_TAKE() == 1U) { MDUCOMM_LOG("mdu comm task is runing, sleep time is %ums", sleep_time_ms); (void)MDUCOMM_LOCK_GIVE(); } last_send_time = current_time; } if(u16_flow_get_sys_data(0, E_FLOW_GET_DATA_PILE_TYPE, 0U) < 2) { if(s_mdu_data.u8_mdu_type == 0) { v_mdu_comm_gw_action(sleep_time_ms); //国网三统一协议控制 } else { #if MDU_UULN_EN v_mdu_comm_uuln_action(sleep_time_ms); //优优绿能协议 #endif } } else if(s_mdu_data.u8_mdu_type == 0x02) { v_pcm_comm_gw_action(sleep_time_ms); //PCM终端UDP通信协议处理函数(分桩角色) } //任务周期延时函数 报文发送时自动延时 if(s_mdu_data.u8_can_send_cnt*MDUCOMM_TASK_ID < sleep_time_ms) mSleep(sleep_time_ms - s_mdu_data.u8_can_send_cnt*MDUCOMM_TASK_ID); else mSleep(sleep_time_ms); s_mdu_data.u8_can_send_cnt = 0; } }