CAPL实现CRC8 SAE-J1850校验的CAN报文发送脚本求助
CAPL实现带CRC8 SAE-J1850校验、报文计数器的32位CAN报文发送脚本
以下脚本适配CANoe/CANalyzer环境,可直接加载到CAPL节点运行,完全匹配你给出的CRC参数:多项式x^8+x^4+x^3+x^2+1(对应十六进制值0x1D)、初始值0xFF,支持32位业务数据打包、计数器滚动、CRC自动计算,输出符合CAN总线发送规范。
报文数据场默认布局(DLC=6)
校验范围覆盖业务数据+计数器,共5字节,校验值存在最后1字节
- Byte0~Byte3:32位有效业务数据
- Byte4:滚动报文计数器
- Byte5:CRC8 SAE-J1850校验值
完整CAPL代码
variables { // 按需修改目标ECU的CAN报文ID const long c_TxMsgId = 0x123; // 按需修改周期发送间隔,单位ms const int c_TxPeriod = 100; // 报文滚动计数器全局变量 byte g_msgCounter = 0; // 32位业务数据缓存,可在任意事件逻辑中更新该值 dword g_payloadData = 0x00; // CAN发送报文对象 message c_TxMsgId g_TxMsg; // 周期发送定时器 msTimer t_txTimer; } /** * @brief CRC8 SAE-J1850计算函数 * @param data 待校验数据数组 * @param len 待校验数据长度 * @return 计算得到的8位CRC结果 */ byte CalcCRC8_SAEJ1850(byte data[], int len) { byte crc = 0xFF; // 匹配指定初始值 const byte poly = 0x1D; // 匹配指定多项式 int i, j; for(i = 0; i < len; i++) { crc ^= data[i]; for(j = 0; j < 8; j++) { crc = (crc & 0x80) ? ((crc << 1) ^ poly) : (crc << 1); } } // 标准SAE-J1850要求最终结果异或0xFF,若ECU校验失败可注释该行测试 crc ^= 0xFF; return crc; } /** * @brief 定时器触发的报文打包发送逻辑 */ on timer t_txTimer { byte txBuf[6]; byte crcResult; // 填充32位有效载荷,默认小端序,大端序可调整字节赋值顺序 txBuf[0] = (byte)(g_payloadData & 0xFF); txBuf[1] = (byte)((g_payloadData >> 8) & 0xFF); txBuf[2] = (byte)((g_payloadData >> 16) & 0xFF); txBuf[3] = (byte)((g_payloadData >> 24) & 0xFF); // 填充计数器,自增后byte类型溢出自动回0 txBuf[4] = g_msgCounter; g_msgCounter++; // 计算前5字节的CRC值并填充 crcResult = CalcCRC8_SAEJ1850(txBuf, 5); txBuf[5] = crcResult; // 配置报文DLC、装载数据并发送 g_TxMsg.dlc = 6; for(int idx = 0; idx < 6; idx++) { g_TxMsg.byte(idx) = txBuf[idx]; } output(g_TxMsg); // 重启定时器维持周期发送 setTimer(t_txTimer, c_TxPeriod); } /** * @brief 节点启动初始化 */ on start { g_msgCounter = 0; // 可自定义32位载荷初始值 g_payloadData = 0x12345678; // 启动首次发送定时 setTimer(t_txTimer, c_TxPeriod); }
使用调整说明
- 若协议要求计数器仅在0~15范围滚动,可在
g_msgCounter++;后新增一行g_msgCounter &= 0x0F;即可。 - 若ECU采用大端序解析32位数据,只需要把txBuf[0]~txBuf[3]的赋值顺序倒序排列即可。
- 不需要周期发送时,可以把报文打包发送的逻辑抽成独立自定义函数,在按键触发、信号变化触发、诊断响应触发等对应事件中调用即可。
- 若使用CAN FD报文,只需要在报文对象定义时增加CAN FD属性、调整DLC为对应CAN FD长度值,CRC计算逻辑不需要修改。
- CRC校验不通过时优先检查两个点:一是最终异或值是否和ECU端一致,可尝试注释
crc ^= 0xFF;测试;二是校验范围是否覆盖了正确的字节,部分协议会把CRC本身也纳入校验范围,可调整CalcCRC8_SAEJ1850的长度参数测试。
内容的提问来源于stack exchange,提问作者TechGeek
相关产品推荐
相关产品推荐

