9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
1157 lines
47 KiB
C
1157 lines
47 KiB
C
#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;i<u8_mdu_num;i++)
|
||
{
|
||
if(s_mdu_data.s_mdu[i].s_state.e_state == E_MDU_STATE_NONE) //此处没模块
|
||
continue;
|
||
|
||
if(s_mdu_data.s_mdu[i].s_state.u8_GrpMode == 0) //固定分组
|
||
v_mdu_send_setGroupMode(i,2); //修改为动态分组
|
||
}
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief -模块分组情况检查,检查模块分组组号是否正确
|
||
*
|
||
*
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-07-03
|
||
* ************************************************************************
|
||
*/
|
||
void v_mdu_group_check()
|
||
{
|
||
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_ctrl->u8_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;j<s_mdu_data.u8_mdu_num;j++)
|
||
{
|
||
s_mdu_state = &s_mdu_data.s_mdu[j].s_state;
|
||
if(s_mdu_state->u8_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;j<s_mdu_data.u8_mdu_num;j++)
|
||
{
|
||
s_mdu_state = &s_mdu_data.s_mdu[j].s_state;
|
||
if(s_mdu_state->u8_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;i<u8_mdu_num;i++)
|
||
{
|
||
if(s_mdu_data.s_mdu[i].s_state.e_state == E_MDU_STATE_NONE) //此处没模块
|
||
continue;
|
||
|
||
v_mdu_send_getMduPara(i , type);
|
||
break;
|
||
}
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief -模块通信发送控制函数
|
||
*
|
||
*
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-07-03
|
||
* ************************************************************************
|
||
*/
|
||
void v_mdu_comm_send_ctrl(U16_T u16_sleepTime)
|
||
{
|
||
if(s_mdu_data.u16_timer % NUM_2000 == 0) //2秒
|
||
{
|
||
v_mdu_send_Heartbeat(); //心跳帧发送
|
||
|
||
v_mdu_group_mode_check(); //检查模块分组模块 不是动态分组,改为动态分组
|
||
|
||
#if( MDU_TEMP_READ_EN == 1)
|
||
v_mdu_temp_read(); //充电模块温度读取,广播读取,2S一次
|
||
#endif
|
||
}
|
||
|
||
if(s_mdu_data.u16_timer % NUM_250 == 0) //250ms
|
||
{
|
||
v_mdu_group_check(); //模块分组检查
|
||
|
||
v_mdu_remote_control_send(); //模块遥控发送
|
||
|
||
#if( MDU_PARA_READ_EN == 1) //模块参数读取使能
|
||
v_mdu_para_check(); //获取模块最大最小输出电压 电流参数
|
||
#endif
|
||
}
|
||
|
||
}
|
||
#endif
|
||
|
||
U16_T test_cnt = 0;
|
||
#if 1 //报文接收解析
|
||
void v_mdu_rx_unpack(CAN_DATA *rxMsg)
|
||
{
|
||
U8_T u8_cmd, u8_oriAddr,u8_desAddr, u8_boxid;
|
||
U16_T u16_data; //临时变量 使用时注意赋值
|
||
WordAlign temp; //临时变量 使用时注意赋值
|
||
S_MDU_STATE *s_mdu_state = NULL;
|
||
|
||
/* 抢连接/DI 状态:交给 STM 状态通信模块解析(ID 0x1801AABB) */
|
||
#if (GUN_LINK_COMM_EN)
|
||
if (u8_stm_gb_enable() && u8_stm_status_can_rx(rxMsg))
|
||
return;
|
||
#endif
|
||
|
||
if(u8_can_ID_unpack(rxMsg->ID, 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;i<u8_mdu_num;i++)
|
||
{
|
||
s_mdu_state = &s_mdu_data.s_mdu[i].s_state; //获取模块状态
|
||
|
||
if(u8_id == MODULE_ALL || //清空所有模块故障内容
|
||
u8_id == i)
|
||
{
|
||
s_mdu_state->e_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;i<u8_mdu_num;i++)
|
||
{
|
||
s_mdu_state = &s_mdu_data.s_mdu[i].s_state; //获取模块状态
|
||
|
||
if(s_mdu_state->e_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<u8_mdu_num;i++)
|
||
{
|
||
v_mdu_set_comm_fault_info(i,0); //故障恢复触发
|
||
}
|
||
v_mdu_set_comm_fault_info(MODULE_ALL,0); //故障恢复触发
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief - 国网三统一协议控制动作
|
||
*
|
||
*
|
||
*
|
||
* @author jiankalka
|
||
* @date 2025-11-12
|
||
* ************************************************************************
|
||
*/
|
||
static void v_mdu_comm_gw_action(U16_T u16_leep_time)
|
||
{
|
||
U16_T u16_runing_flag;
|
||
static U8_T u8_spican_init_flag = 0;
|
||
|
||
v_mdu_comm_recv_unpack(); //报文接收解包;
|
||
|
||
//获取模块任务运行标志 0模块任务不运行并清空模块数据 1模块任务运行-执行报文收发和超时判断
|
||
u16_runing_flag = u16_mdu_get_charge_need(0, E_MDU_GET_DATA_RUNING_FLAG);
|
||
if(u16_runing_flag == 1)
|
||
{
|
||
v_mdu_comm_send_ctrl(u16_leep_time); //报文发送控制
|
||
v_mdu_comm_outtime_cheak(u16_leep_time); //报文接收超时检查
|
||
if(u8_spican_init_flag == 0) //上电第一次运行到此处,且模块任务运行标志为1,说明模块任务启动了,但SPICAN未必初始化成功,此时强制初始化一次SPICAN,避免因SPICAN初始化失败导致的通信问题;后续如果SPICAN初始化成功了,这个标志就不会再被置0了
|
||
{
|
||
// CANSPI_HealthCheckAndRecover(1U);
|
||
u8_spican_init_flag = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
u8_spican_init_flag = 0; //模块任务不运行,SPICAN初始化标志复位,等待下次模块任务启动时再次强制初始化SPICAN
|
||
s_mdu_data.u32_runing_time = get_current_seconds();
|
||
v_mdu_clear_recv_data(MODULE_ALL); //清空所有模块接收数据
|
||
v_mdu_clear_outtime(); //清空所有模块故障告警
|
||
}
|
||
|
||
if(s_mdu_data.u16_timer < 0xFF00) //因为在
|
||
s_mdu_data.u16_timer += u16_leep_time; //计数周期累加
|
||
else
|
||
s_mdu_data.u16_timer = 0;
|
||
|
||
/* 辅源控制 CAN 帧:利用 s_mdu_data.u16_timer,每 1000ms 发送一次 */
|
||
#if (GUN_LINK_COMM_EN)
|
||
if (u8_stm_gb_enable() && (s_mdu_data.u16_timer % NUM_1000 == 0))
|
||
{
|
||
v_stm_status_can_send_aux_frame();
|
||
}
|
||
#endif
|
||
|
||
/* 周期性 SPI-CAN 健康检查:独立于模块通信超时运行 */
|
||
// if (s_mdu_data.u16_timer % NUM_1000 == 0)
|
||
// {
|
||
// (void)CANSPI_HealthCheckAndRecover(0U);
|
||
// }
|
||
}
|
||
|
||
void v_Mdu_Comm_task_init()
|
||
{
|
||
U8_T i;
|
||
memset(&s_mdu_data, 0 , sizeof(S_MDU_DATA)); //清空 模块结构体
|
||
|
||
s_mdu_data.u8_mdu_num = u16_mdu_get_charge_need(0,E_MDU_GET_DATA_MDU_NUM); //获取模块数量
|
||
s_mdu_data.u8_mdu_group_num = u16_mdu_get_charge_need(0,E_MDU_GET_DATA_GUN_NUM); //获取枪数量
|
||
s_mdu_data.u8_mdu_type = u16_mdu_get_charge_need(0,E_MDU_GET_DATA_MDU_TYPE); //模块类型 0 三统一 1优优绿能
|
||
|
||
#if( MDU_PARA_READ_EN == 1) //模块参数读取使能
|
||
s_mdu_data.u16_mduPara_MaxOutVol = 0xFF; //默认值为0xFF 便于后续参数获取识别
|
||
s_mdu_data.u16_mduPara_MaxOutCur = 0xFF; //默认值为0xFF 便于后续参数获取识别
|
||
s_mdu_data.u16_mduPara_MinOutVol = 0xFF; //默认值为0xFF 便于后续参数获取识别
|
||
s_mdu_data.u16_mduPara_MinOutCur = 0xFF; //默认值为0xFF 便于后续参数获取识别
|
||
#endif
|
||
|
||
for (i = 0; i < s_mdu_data.u8_mdu_num; i++) //初始化所有模块地址 从0x60开始
|
||
{
|
||
s_mdu_data.s_mdu[i].u8_mdu_addr = MODULE_MDU_FIRST_ADDR + i; //模块地址范围 0x20 ~ 0x9E,0x9F作为广播地址使用
|
||
s_mdu_data.s_mdu[i].s_state.u16_outtimecnt = 0xFFFF; //模块默认通信超时
|
||
}
|
||
|
||
}
|
||
/**
|
||
* ************************************************************************
|
||
* @brief -模块通信任务
|
||
*
|
||
* @param[in] p -线程参数
|
||
*
|
||
* @author jiankalka
|
||
*
|
||
* @date 2025-07-02
|
||
* ************************************************************************
|
||
*/
|
||
void v_Mdu_Comm_task(void *arg)
|
||
{
|
||
uint16_t sleep_time_ms;
|
||
uint32_t last_send_time;
|
||
uint32_t current_time;
|
||
|
||
(void)arg;
|
||
(void)MDUCOMM_LOCK_INIT();
|
||
sleep_time_ms = MDUCOMM_SLEEP_TIME_MS();
|
||
last_send_time = get_current_seconds();
|
||
|
||
v_Mdu_Comm_task_init();
|
||
|
||
for (;;) {
|
||
MDUCOMM_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 (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;
|
||
}
|
||
}
|