#ifndef PCCU_CAN_BMS_H #define PCCU_CAN_BMS_H #include namespace ccu { //============================================================================ // 锂电池 BCU-MBMS CAN 协议(docs/04KT38电池BCU-MBMS通信(CAN)定义.docx) // // 数据来源:pCanBridge 透传的 MOOS 消息 // 变量名 CAN_0x%08X = CAN ID(扩展帧),m_sVal = 二进制数据域, // m_dfVal2 = 原始帧信息字节。本模块只负责按报文 ID 解析数据域字段。 // // 【节点地址】一个 MBMS 下最多挂 54 个 BCU,CAN ID 中间的 XX(01h~36h) // 为 BCU 节点地址编号,其余位固定: // 0x10XX00YY BCU 主动上报消息(YY=功能码 00/01/02/03/06/10) // 0x10XX81FF MBMS 下发指令(继电器控制,经 MOOS CAN_TX_0x* 下行) // // 【下发指令 0x10XX81FF】数据域 8 字节(BYTE1~8 = byte0~7): // byte0 = 0x02(索引号) byte1 = 0x00(索引号) // byte2 = 总正继电器控制(1 闭合 / 0 断开) // byte3 = 总负继电器控制(1 闭合 / 0 断开) // byte4~7 = Reserve(填充 0xFF) // // 【上报报文】均为扩展帧,字段大端,BYTE1~8 对应数据域 byte0~7: // 0x10XX0000 (200ms) 累加电压 u16@0 ÷10 V // 回路电流 s16@2 ÷10-600 A(偏移 -600A,放电为正) // SOC u16@4 ÷10 % // 告警码 u8 @6(循环上报,协议未附码表,原样显示) // 自检状态 u8 @7 // 0x10XX0001 (200ms) 最高单体电压 u16@0 mV,编号 u8@2 // 最低单体电压 u16@3 mV,编号 u8@5 // 单体平均电压 u16@6 mV // 0x10XX0002 (1000ms) 最高单体温度 s8@0(偏移 -40℃),编号 u8@1 // 最低单体温度 s8@2(偏移 -40℃),编号 u8@3 // 单体平均温度 s8@4(偏移 -40℃,协议文档写"偏移0" // 有误:实测原始值减 40 后才落在最低~最高区间内) // 0x10XX0003 (200ms) 正极继电器状态 u8@0(1 闭合 / 0 断开) // 负极继电器状态 u8@1(1 闭合 / 0 断开) // 0x10XX0006 (200ms) 正极绝缘阻抗 u16@0 kΩ // 负极绝缘阻抗 u16@2 kΩ // 正负极端口电压 u16@4 ÷10 V // 正极继电器外侧电压 u16@6 ÷10 V // 0x10XX0010 (200ms) byte0~5 告警位(bit 定义见附录1, // kBcuAlarmTable,可经 bcuAlarmTexts() 取告警描述) // 0x10XX0004/0005 Reserve(调试预留,不解析) //============================================================================ // BCU 节点地址范围:01h~36h(1~54) static const int kBcuAddrMin = 0x01; static const int kBcuAddrMax = 0x36; static const int kBcuNodeCount = kBcuAddrMax - kBcuAddrMin + 1; // BCU 上报报文功能码(CAN ID 低字节 YY) enum BcuFunc : uint8_t { BCU_FUNC_BASE = 0x00, // 0x10XX0000 电压 / 电流 / SOC / 告警码 / 自检 BCU_FUNC_CELL_V = 0x01, // 0x10XX0001 单体电压 BCU_FUNC_CELL_T = 0x02, // 0x10XX0002 单体温度 BCU_FUNC_RELAY = 0x03, // 0x10XX0003 继电器状态 BCU_FUNC_ISU = 0x06, // 0x10XX0006 绝缘阻值 / 端口电压 BCU_FUNC_ALARM = 0x10, // 0x10XX0010 告警位(附录1) }; // 从 CAN ID 提取 BCU 节点地址(0x10XX00YY -> XX);非 BCU 报文格式返回 0 inline uint8_t bcuAddrOf(uint32_t canId) { if ((canId & 0xFF00FF00u) != 0x10000000u) return 0; uint8_t addr = static_cast((canId >> 16) & 0xFF); return (addr >= kBcuAddrMin && addr <= kBcuAddrMax) ? addr : 0; } // 从 CAN ID 提取功能码(0x10XX00YY -> YY) inline uint8_t bcuFuncOf(uint32_t canId) { return static_cast(canId & 0xFF); } //-------------------------------------------------------------------------- // BCU 断路器(总正/总负继电器)下行控制 //-------------------------------------------------------------------------- // BCU 节点继电器控制指令 CAN ID(0x10XX81FF,XX=节点地址 01h~36h) inline uint32_t bcuCtrlCanId(uint8_t addr) { return 0x10000000u | (static_cast(addr) << 16) | 0x81FFu; } // 编码继电器控制数据域(8 字节,经 MOOS CAN_TX_0x%08X 下发,pCanBridge 发送): // [0]=0x02 [1]=0x00 [2]=总正(1闭合/0断开) [3]=总负 [4..7]=0xFF // pos/neg 非 0 值均视为闭合(1)。 inline void buildBcuRelayCtrlData(int pos, int neg, uint8_t out[8]) { out[0] = 0x02; out[1] = 0x00; out[2] = pos ? 0x01 : 0x00; out[3] = neg ? 0x01 : 0x00; out[4] = 0xFF; out[5] = 0xFF; out[6] = 0xFF; out[7] = 0xFF; } // 是否为 BCU 主动上报报文 ID(0x10XX00YY,YY 为已定义功能码) inline bool isCanBcuId(uint32_t canId) { uint8_t addr = bcuAddrOf(canId); if (!addr) return false; switch (bcuFuncOf(canId)) { case BCU_FUNC_BASE: case BCU_FUNC_CELL_V: case BCU_FUNC_CELL_T: case BCU_FUNC_RELAY: case BCU_FUNC_ISU: case BCU_FUNC_ALARM: return true; default: return false; } } // 单个 BCU 节点最新状态(各报文字段按功能码部分更新,最终合成完整快照) struct BcuNodeStatus { // 0x10XX0000 基本信息 double totalVoltage = 0; // 累加电压 V double current = 0; // 回路电流 A(放电为正,偏移 -600A 已折算) double soc = 0; // SOC % int alarmCode = 0; // 告警码(原始值,协议未附码表) int selfCheck = 0; // 自检状态(原始值) // 0x10XX0001 单体电压 double maxCellVoltage = 0; // 最高单体电压 V int maxCellVoltageNo = 0; // 最高单体电压编号 double minCellVoltage = 0; // 最低单体电压 V int minCellVoltageNo = 0; // 最低单体电压编号 double avgCellVoltage = 0; // 单体平均电压 V // 0x10XX0002 单体温度 double maxCellTemp = 0; // 最高单体温度 ℃ int maxCellTempNo = 0; // 最高单体温度编号 double minCellTemp = 0; // 最低单体温度 ℃ int minCellTempNo = 0; // 最低单体温度编号 double avgCellTemp = 0; // 单体平均温度 ℃ // 0x10XX0003 继电器(1 闭合 / 0 断开) int posRelay = 0; int negRelay = 0; // 0x10XX0006 绝缘 / 端口电压 double posInsulationKohm = 0; // 正极绝缘阻抗 kΩ double negInsulationKohm = 0; // 负极绝缘阻抗 kΩ double portVoltage = 0; // 正负极端口电压 V double posRelayOuterVoltage = 0; // 正极继电器外侧电压 V // 0x10XX0010 告警位(附录1,byte0~5) uint8_t alarmBits[6] = {0, 0, 0, 0, 0, 0}; // 0x10XX0010 附加字节(协议未详列,原样保留) int alarmExtraByte6 = 0; int alarmExtraByte7 = 0; // 元数据 uint32_t rxMask = 0; // 收到过的功能码位图(bit = BcuFunc) double lastRxTime = 0; // 最近收到该节点任一报文的时刻(MOOSTime) bool valid = false; // 是否收到过该节点报文 }; // 解析一帧 CAN 数据域;命中 BCU 上报报文返回 true,nodeAddr 为节点地址(1~54), // 字段按功能码部分更新合并进 node。data/dlc 非法或非 BCU 报文返回 false。 bool decodeCanBcuFrame(uint32_t canId, const uint8_t* data, int dlc, uint8_t& nodeAddr, BcuNodeStatus& node); // 附录1:0x10XX0010 告警位定义表(byteIdx/bitIdx -> 告警描述),表尾以 byteIdx=0xFF 结束 struct BcuAlarmDesc { uint8_t byteIdx; uint8_t bitIdx; const char* text; }; extern const BcuAlarmDesc kBcuAlarmTable[]; // 收集节点当前置位的告警描述;返回条数(不超过 cap,texts 填描述指针) int bcuAlarmTexts(const BcuNodeStatus& node, const char* texts[], int cap); } // namespace ccu #endif // PCCU_CAN_BMS_H