阅读量:0
文章目录
前言
关于CRC校验的基本理论、算法实现网上已经有很多介绍文章,本文不再赘述。只是记录在项目测试中真正开发CRC算法并进行测试的一些体会。
一、为什么CAN报文有CRC?
首先从CAN帧结构层面上看,在报文Data后紧跟着的是CRC场,通信收发双方通过约定的算法进行CRC计算来实现数据传输检错功能,以此降低误码率,保证数据传输的正确性和完整性。从应用层面来看车辆的车速档位、Usermode、Carmode等信息需要保证正确传输以达到数据安全。这也是为什么不是所有帧都需要做CRC校验。
二、怎么确定是否需要做CRC校验?
如下图,在DBC或者ARXML中当需要仿真发送的报文中包括checksum和Rollingcounter信号时,就需要进行CRC校验算法开发。这里有几个点需要注意:
- 仿真发送的报文才需要,接收报文不需要;
- checksum和Rollingcounter信号名不一定是唯一的,要注意识别。有的可能写CRC、RC等其他形式。当仿真发送报文没有任何作用时,就可以去看看是不是有CRC信号需要算法校验。
- CRC算法也是多样的,注意根据规范开发。核心数据包括:多项式、初始CRC值、最终异或值。重点是理解CRC算法逻辑,这样不论是在CANoe、TSMaster、Veristand中都可以进行开发。
三、CAPL代码实现CRC算法
上面提到,重点是理解CRC算法逻辑然后去有针对性的开发。下面以LIN的CRC为例,使用CAPL进行CRC demo代码的实现。可以根据实际开发需要进行调整。
/*@!Encoding:936*/ includes { } variables { byte i; linFrame *msg; int flag; byte index; byte crc_item; byte CRC_CheckSum; byte crcValue = 0x00; byte xorValue = 0x00; byte Frame_Data[7]; } void SimulationCRC(long MsgID,int CycleTime) { msg.id = 0x00; msg.msgChannel = 1; msg.dlc=8; msg.rtr = 0; //RTR在output发送帧时使用,为0将重新配置响应数据;为1向总线发送帧头,配合主模式使用 msg.byte(1) = i + 0x80; flag = 1; i++; if(i == 0xF) { i = 0x0; } //直接定义byte字节值;或者去定义报文信号 msg.byte(2) = 0x02; msg.byte(3) = 0x03; msg.byte(4) = 0x04; msg.byte(5) = 0x05; msg.byte(6) = 0xC6; msg.byte(7) = 0x07; Frame_Data[0] = msg.byte(1); Frame_Data[1] = msg.byte(2); Frame_Data[2] = msg.byte(3); Frame_Data[3] = msg.byte(4); Frame_Data[4] = msg.byte(5); Frame_Data[5] = msg.byte(6); Frame_Data[6] = msg.byte(7); if(flag == 1) { CRC_CheckSum = crc8Sumu(Frame_Data,7); flag = 0; } msg.byte(0) = CRC_CheckSum; output(msg); flag=1; } on linFrame * { if(this.id == 0x00) { SimulationCRC(0x00, 50); } } // ----------------------<crc8Sumu>------------------------- byte crc8Sumu(byte data[], int Datalen) { byte CRCInitValue = 0x01; byte CRCPolynomial = 0x02; byte CRCXORValue = 0x03; int i, j; byte Rtn; Rtn = CRCInitValue; for (i = 0; i < Datalen; i++) { Rtn ^= data[i]; //异或赋值 for (j = 0; j < 8; j++) { if (Rtn & 0x80) { Rtn = (Rtn << 1) ^ CRCPolynomial; //左移一位后 异或运算 } else { Rtn <<= 1; } } } Rtn ^= CRCXORValue; return Rtn; }