Crc校验在CAN报文中的实际应用介绍:
Crc在报文传输过程中的实际应用如下(在汽车中,Crc一般是对8个字节进行校验,目前我接触到的是这样):
ECU-A和ECU-B之间进行CAN报文的传输,双方规定ECU-A发出的0x123报文为64个字节,该报文中的Byte1-Byte7要进行Crc校验,校验结果放到Byte0中,Alivecounter为Byte7的低四位(范围为0-14)。其余的Byte8-Byte64不进行校验。校验范围如下图所示
因此,ECU-A往CAN总线发出这帧报文之前,要对每帧报文的Alivecounter按照0-14进行不断自增、循环。然后进行Crc校验并把校验结果存放到这帧报文的Byte0中,最后通过CAN总线发出这帧报文数据。
ECU-B接收到这帧报文后,由于Byte8-Byte64不在校验范围内,因此接收到这帧报文后这个范围内的数据可以直接使用。但Byte0-Byte7为校验范围,因此ECU-B按照双方规定好的Crc算法对Byte1-Byte7进行校验,校验结果跟接收到的Byte0进行对比,若对比结果一致,则使用这帧报文的Byte1-Byte7的数据,否则丢弃这些数据。
这就是Crc算法在CAN报文中的具体使用。
E2E和Crc的区别
接下来就是Autosar的E2E(End-to-End,可以理解为数据从一个ECU传到另一个ECU)。
刚开始接触的时候,我总没搞明白所谓的E2E和CRC到底有啥区别,因为在开发过程中,只关心两件事:Checksum计算是否正确、Counter的值是否按照要求进行递增并循环。
后来在不断的学习和深入开发的才知道:
Crc仅仅是一个校验算法
E2E是Autosar官方定义的标准,它包含了Crc算法、要求了Counter的值如何进行递增、并在Counter出错时会记录对应的错误状态等等。
讲完了上面这些东西,你应该对E2E有一个最简单的了解了。概况来说,其实就是校验。但Autosar标准定义的E2E并没有那么简单。下面,我用开发一帧接收报文的E2E功能慢慢来讲(发送的没啥讲的,就是发送前填充一下Checksum和Counter的值)。
需求:对接收到的长度为8个Byte的0x1AA报文开发E2E功能。
告诉你这个之后,还必须告诉你一些E2E的具体需求,没有这些你是无法开发的。(因为汽车上多个节点进行通讯,如果使用E2E功能的话,那么必须各个节点E2E需求保持一致,否则各个节点用的算法都不一样,这还校个啥。)
好了,E2E的具体需求释放给你了,如下:
算法:使用Autosar标准下的Profile01
Counter Offset(Bit):56
ChecksumOffset(Bit):0
Data ID Mode:DataID Both
Data ID:0x01AB
Max Delta Counter Init: 2
Sync Counter Init: 1
Max No New Or Repeatd Data: 14
我们一个一个来解释这些都是些什么东西,有什么用。
Counter Offset(Bit):56,ChecksumOffset(Bit):0。
对于这两个就很容易懂了,如下图,就是Checksum和Counter的位置在报文的什么地方
Data ID Mode
DataID的模式,共有四种模式可选:
E2E_P01_DATAID_BOTH
E2E_P01_DATAID_ALT
E2E_P01_DATAID_LOW
E2E_P01_DATAID_NIBBLE
那么,DataID是什么东西呢?
以E2E_P01_DATAID_BOTH为栗子。
首先,我们要知道,DATAID_BOTH,就是DataID为两个字节,且高字节叫做DataIDHigh,低字节为DataIDLow。
根据我们目前这个需求,DataID为0x01AB(即DataIDHigh = 0x01,DataIDLow=0xAB),E2E校验的范围为Byte1-Byte7(Byte0用来存计算结果Checksum的值)。
由于Byte1-Byte7共7个Byte,在校验的过程的中会把报文的Byte1-Byte7提取出来,放到一个新的数组里,新的数组长度为2+7=9(DataID长度+数据长度)。如数组的名字为Data[9]。则,Data[0] =DataIDLow(即0xAB),Data[1] =DataIDHigh(即0x01),Data[2]-Data[8]为报文的Byte1-Byte7。
最后把整理好的Data数据进行算法计算。
Max Delta Counter Init:
关于这个参数,官方解释如下:
简单来说就是说最大容忍Counter的间隔(,因为Counter是按1递增的,因此这参数即最大容忍丢失帧数)。正如它的例子说:如果MaxDeltaCounterInit配置为1,那么当在接收到上一帧的Counter为1的时候(下一帧若counter为2就不说了,因为Counter为2即没有丢帧),下一帧可以接收counter为3,但不能counter为4。因为1与3直接差了一帧(也就是丢失一帧了)。1与4直接已经差了2帧(也就是丢失两帧了),所以Counter为4不在容忍范围内了。
转换成直观的例子:
①如连续接收到的报文Counter分别为:1、3、4、5、6、7。那么Counter值为3时,虽然中间缺失了一帧(Counter值为2的帧),但在容忍范围内。
②如连续接收到的报文Counter分别为:1、8、9、10、11、12。那么Counter值为8时,中间缺失了不止一帧,因此不在容忍范围内。
Sync Counter Init:
官方解释如下:
关于这个参数,我们需要在后面讲E2E返回状态为E2E_P01STATUS_SYNC的时候才能反过来讲明白。
对于E2E参数,官方图形解释如下:
使用Vector工具配置报文E2E的各个栗子如下:
好了,其实讲到目前为止,你对这些参数应该还是明白的云里雾里。但要彻底明白这些参数是什么东西,有什么具体作用,需要知道接收到报文后进行E2E校验产出的东西——E2E状态
E2E状态:
接收到含E2E报文后,对E2E报文的检查结果就会有对应的E2E状态供应用层读取,应用层根据E2E状态决定接收到的数据是否使用,并根据E2E状态记录相关的故障,如Checksum校验错误故障等。
typedef enum { E2E_P01STATUS_OK = 0x00, E2E_P01STATUS_NONEWDATA = 0x1, E2E_P01STATUS_WRONGCRC = 0x2, E2E_P01STATUS_SYNC = 0x03, E2E_P01STATUS_INITIAL = 0x4, E2E_P01STATUS_REPEATED = 0x8, E2E_P01STATUS_OKSOMELOST = 0x20, E2E_P01STATUS_WRONGSEQUENCE = 0x40} E2E_P01CheckStatusType;
E2E_P01STATUS_WRONGCRC:
接收到的E2E报文Checksum验证失败。比如E2E算法、或DataID的值、或E2E校验的范围配置得跟需求不符合,各个节点计算没统一起来,都会导致Checksum验证失败。
E2E_P01STATUS_SYNC:
出现这个状态共有两种情况(假设MaxDeltaCounterInit配置为1,SyncCounterInit配置为2):
①初始化阶段。
初始化,即上电后从没有接收到该报文。假设现在上电后接收到如下连续报文Counter分别为:2、3、4、5、6。那么Counter为3、Counter为4的时候,就是同步阶段。E2E状态为:E2E_P01STATUS_SYNC。
②出现Counter值状态为E2E_P01STATUS_WRONGSEQUENCE之后。
即上一帧接收到Counter的值超过了MaxDeltaCounterInit。然后当前接收到Counter的值为正常。如接收到的连续报文的Counter值分别为:0、4、5、6、7、8。因此当Counter值为4时,E2E状态为E2E_P01STATUS_WRONGSEQUENCE。由于SyncCounterInit配置为2,E2E状态在Counter值为5、Counter值为6时,都为同步状态。E2E_P01STATUS_SYNC。
E2E_P01STATUS_INITIAL:
初始化阶段。即上电后就没接收到E2E报文。E2E就会持续保持初始化状态。
E2E_P01STATUS_REPEATED:
接收到的E2E报文Counter值重复。如接收到的连续报文的Counter值分别为:2、2、3、4、4、5。则,在接收到Counter值为第二个2时,E2E状态为E2E_P01STATUS_REPEATED。
E2E_P01STATUS_OKSOMELOST:
接收到的E2E报文连续两帧之间的Counter差值大于1(Counter差值为1时,即Counter正常,如:0、1、2、3、4),但小于MaxDeltaCounterInit。(简单来说,就是前后连续两帧报文的Counter值不是连续的,但在容忍范围内)。如MaxDeltaCounterInit配置为1,接收到的连续报文的Counter值分别为:0、2、4、5、6、7。则,在接收到Counter值位2时,E2E状态为E2E_P01STATUS_OKSOMELOST。
E2E_P01STATUS_WRONGSEQUENCE :
接收到的E2E报文连续两帧之间的Counter差值大于MaxDeltaCounterInit。如MaxDeltaCounterInit配置为1,接收到的连续报文的Counter值分别为:0、3、4、5、6、7。则,在接收到Counter值位3时,E2E状态为E2E_P01STATUS_WRONGSEQUENCE 。
E2E_P01STATUS_NONEWDATA:
一个报文周期内未接收到该E2E报文。
E2E_P01STATUS_OK:
接收到的E2E报文Checksum验证通过,且Counter验证正确。
另外还有下面的东西,应该不止。我下次再展开说(今晚太晚了,下次再修改):
DataIDNibbleOffset
官方定义如下
这个参数只有在DataID模式选择为“E2E_P01_DATAID_NIBBLE ”是会用到。目前我没用到,所以我也不知道这玩意干啥用的(看半天也没看懂-_-”’)….
MaxNoNewOrRepeatedData
当接收到重复数据次数小于该配置参数,则接收端不需要执行数据同步处理
Autosar官方标准文档有如下所示报文接收检查流程图(太复杂了,大家随便看看就好了):
以下代码运行即可得到以Autosar官方标准的E2E_Profil01计算的结果(发送)。其中:
Checksum位置为Byte0
Counter位置为Byte7的低四位(即Bit56)
DataID模式为DATAID_BOTH且DataID=0x00AD。
注:以下是报文发送的例子。因为是发送,所以是没有E2E的状态处理的。
代码如下:
main.c
#include #include "typedef_datatype.h"#include "E2E_Config.h"uint16 DataID = 0x00AD;//DataID_Low = 0xAD DataID_High = 0x00 uint8 Test_Data_Array[8] = { 0x00, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x73, 0x20 }; //Byte0-Byte7 Test DataE2E_P01ConfigType E2E_Profile01_Test_Config = {56,//CounterOffset0,//CRCOffset177,//DataID0,//DataIDNibbleOffsetE2E_P01_DATAID_BOTH,//DataIDMode64,//DataLength0,//MaxDeltaCounterInit0,//MaxNoNewOrRepeatedData0//SyncCounterInit};void main(void){for (uint8 counter = 0; counter < 15; counter++){Test_Data_Array[7] = (Test_Data_Array[7] & 0xF0) | counter;Test_Data_Array[0] = E2E_P01ComputeCRC(Test_Data_Array, &E2E_Profile01_Test_Config, 0xFF);for (uint8 i = 0; i < 8; i++){printf("%x ", Test_Data_Array[i]);}printf("\n");}}
E2E_Config.h
#ifndef E2E_Config_H_#define E2E_Config_H_#include #include "typedef_datatype.h"/* For CRC 8*/#define CRC8_START_VALUE 0xFFU#define CRC8_XOR 0xFFU/* CRC 8 Configuration * Possible values and the mode decides what method to be used */#define CRC_8_HARDWARE (0x01) /* Not supported */#define CRC_8_RUNTIME (0x02)#define CRC_8_TABLE (0x04) /* Default value */#define CRC_8_MODE CRC_8_RUNTIME /* E2E Profile01 */#define CRC8_POLYNOMIAL0x1DUtypedef enum {E2E_P01_DATAID_BOTH = 0x0,E2E_P01_DATAID_ALT = 0x1,E2E_P01_DATAID_LOW = 0x2,E2E_P01_DATAID_NIBBLE = 0x3} E2E_P01DataIDMode;typedef struct {uint16 CounterOffset;uint16 CRCOffset;uint16 DataID;uint16 DataIDNibbleOffset;E2E_P01DataIDMode DataIDMode;uint16 DataLength;uint8 MaxDeltaCounterInit;uint8 MaxNoNewOrRepeatedData;uint8 SyncCounterInit;} E2E_P01ConfigType;uint8 Crc_CalculateCRC8(const uint8* Crc_DataPtr, uint32 Crc_Length, uint8 Crc_StartValue8, boolean Crc_IsFirstCall);uint8 E2E_P01ComputeCRC(const uint8* Crc_DataPtr, const E2E_P01ConfigType* ConfigPtr, uint8 Counter);#endif
E2E.c
#include "E2E_Config.h"static uint8 CalculateCRC8(const uint8* message, uint32 nBytes, uint8 start, uint8 poly){uint8 remainder = start;uint8 bit;uint8 topbit = 0x80;/* Perform modulo-2 division, a byte at a time. */for (uint32 byte = 0; byte 0; bit--) {/* Try to divide the current data bit. */if ((remainder & topbit) != 0u) {remainder = (uint8)(remainder << 1) ^ poly;}else {remainder = (remainder <参考:AUTOSAR E2E 简介_Archieeeeee的博客-CSDN博客_autosar e2e