CAN通信基础:CRC校验在CAN通信中的应用
1 CRC算法基础
1.1 简介
CRC(循环冗余校验,Cyclic Redundancy Check)是一种常用的、基于多项式除法的校验方法,用于检测数据传输或存储过程中的错误。
基本原理
- CRC算法将数据视为多项式,并将数据多项式除以一个收发双方约定的多项式(称为生成多项式),计算得到的余数就是CRC校验值;
- 生成的余数(CRC校验值)会被附加至原始数据后面,随原始数据一同发送或存储;
- 当数据被接收时,接收方会使用相同的生成多项式对数据进行CRC计算。如果计算出的CRC值与接收到的CRC值相匹配,那么数据被认为是正确的;如果不匹配,数据在传输或存储过程中可能发生了错误。
算法参数
通常,CRC算法需要明确如下参数:
- 生成多项式:决定了CRC算法的特性,不同的多项式会产生不同的CRC算法。
- 初始值:CRC计算开始前寄存器的初始值。
- 输入数据反转:部分CRC算法在处理数据前会反转数据的位顺序。
- 输出数据反转:部分CRC算法在输出CRC值前会反转CRC值的位顺序。
- 最终XOR值:CRC计算完成后,与CRC寄存器的最终值进行XOR操作的值。
优势和应用
- CRC校验能够检测出所有奇数个错误和几乎所有的偶数个错误,以及所有长度小于或等于生成多项式次数的突发错误。
- CRC校验的计算效率高,适合硬件和软件实现。
- CRC校验广泛应用于通信领域,用于确保数据的完整性和准确性。在CAN协议中,数据链路层使用CRC-15校验CAN帧的准确性;应用层也常常在重要报文中添加Checksum信号(基于CRC-8)校验CAN数据的准确性。
1.2 CRC的生成多项式
首先,对CRC校验中生成多项式进行介绍。
CRC算法的多项式可以通过二进制序列表示。如某CRC-8算法的二进制表示为1 0001 1101,最低位(右1位)是第0比特,其多项式
P
(
x
)
=
x
8
+
x
4
+
x
3
+
x
2
+
1
P(x)=x^8+x^4+x^3+x^2+1
P(x)=x8+x4+x3+x2+1 与二进制序列一一对应。由于CRC-8生成多项式最高位阶指数默认是8,则最高位通常不表示,则上述CRC-8生成多项式常用十六进制1Dh表示。
1.3 CRC运算示例和多项式除法(模2除法)
CRC校验方法使用多项式除法(模2除法) 进行计算,下面以具体实例说明模2除法如何计算CRC校验值。
现有数据FFh(1111 1111)使用CRC-8 1Dh进行校验。其计算CRC校验码的过程如下:
- CRC-8 1Dh算法的生成多项式为 P ( x ) = x 8 + x 4 + x 3 + x 2 + 1 P(x)=x^8+x^4+x^3+x^2+1 P(x)=x8+x4+x3+x2+1 ,其对应的二进制序列为100011101;
- 在原始数据FFh(1111 1111)补充8位的数据0,其中8是生成多项式的阶数;
- 使用补0之后的二进制数据对生成多项式的二进制序列进行模2运算(见下图)。其实际计算方式是从数据最高位开始和生成多项式进行异或运算,不断向数据低位滑动;
- 最终得到余数C4h(1100 0100),当不足8位时,需要高位补零得到8比特的CRC校验码。
2 CAN数据链路层的CRC Field
ISO 11898-1协议为CAN数据帧定义CRC字段:
- 该CRC字段长度为15比特;
- 该CRC生成多项式为 P ( x ) = x 15 + x 14 + x 10 + x 8 + x 7 + x 4 + x 3 + 1 P(x)=x^{15}+x^{14}+x^{10}+x^8+x^7+x^4+x^3+1 P(x)=x15+x14+x10+x8+x7+x4+x3+1 ;
- 该CRC校验数据的范围是SOF(Start of Frame,帧起始)字段至Data Field(数据域)结束;
- 若某接收节点计算的CRC字段与其接收到的CRC字段数值不一致,则会在ACK-DEL(ACK字段界定符)之后发出错误帧。
3 CAN报文的Rolling Counter和Checksum
为了提高CAN通信传输的可靠性,重要的CAN报文通常需要包含Rolling Counter和Checksum两个信号。如下图,是常见的Rolling Counter和Checksum的在一帧CAN报文中的布局。
3.1 Rolling Counter
Rolling Counter是CAN报文的滚动计数器,用于跟踪报文的序列,确保报文按预期顺序接收。它是一个简单的递增计数器,范围为0-15之间递增循环。通常以一个4比特长度Singal的形式体现。Rolling Counter可以帮助接收方应用软件判断:报文传输过程中是否出现丢帧和乱序。
3.2 Checksum
Checksum是一种CAN报文的数据校验码,用于检查通信数据的完整性。Checksum在CAN报文中通常以一个8比特长度信号的形式体现,常用CRC-8算法。Checksum信号中是发送方按照算法计算出的校验码,其校验范围是本条CAN报文中的其他信号。接收方收到CAN报文后,会根据同样的算法计算校验码,并与Checksum信号进行对比,若两者一致,则认为报文传输过程未出现错误。
在CAN通信设计中,需要约定系统中所有CAN控制器使用的Checksum校验算法,供应商按照此算法实现控制器。下表是CRCH1D算法的参数,以此算法为例介绍发送方和接收方需要约定的CRC8算法参数。
算法参数 | 数值 | 解释 |
---|---|---|
宽度 Width | 8 Bits | CRC-8算法计算结果的宽度是8比特 |
生成多项式 Polynomial | 1Dh | 发送、接收双方约定的计算CRC校验值的多项式 |
初始值 Initial Value | FFh | CRC寄存器的初始值 |
输入数据反转 Input Data Reflected | NO | 输入数据是否进行反转 |
输出数据反转 Output Data Reflected | NO | 输出数据是否进行反转 |
异或值 XOR Value | FFh | 输出数据与此值进行异或计算 |
校验值 Check | 4Bh | 用户在指定一段数据,此段数据进入校验后的数值。 |
魔术校验值 Magic Check | C4h | 详见解释 |
解释:
- 生成多项式:CRC-8算法的多项式可以通过十六进制表示。如1Dh的二进制表示为0001 1101,CRC-8第一位默认隐藏,故实际多项式二进制序列为(1) 0001 1101。按照二进制序列对应 x x x 的指数,则生成多项式 P ( x ) = x 8 + x 4 + x 3 + x 2 + 1 P(x)=x^8+x^4+x^3+x^2+1 P(x)=x8+x4+x3+x2+1 ;
- 初始值:初始值是在开始CRC计算之前,CRC寄存器被设置的值;
- 输入数据反转:在进行CRC计算之前,输入数据的位不会被反转。该反转指位反转,即1101位反转后为1011;
- 输出数据反转:在进行CRC计算之后,输出数据的位不会被反转;
- 异或值:XOR值是在CRC计算完成后,与CRC寄存器的最终值进行XOR(异或)操作的值;
- 校验值:用户指定一段输入数据,经过此CRC算法校验后的输出值。如使用ASCII值’1’,‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, '9’作为输入数据,输出得到的校验值;
- 魔术校验值:任意一段数据经过CRC校验后,得到CRC校验值。将CRC校验值附加于原数据后形成新的输入数据,并进行CRC校验,得到的校验值与异或值(XOR Value)异或,最终输出魔术校验值(Magic Check)。此数值不受原始数据影响,任意数据经过此过程后可得到唯一的魔术校验值。
4 CRC算法代码实现
# python
def crc8h1d(ptr, length):
crc = 0xFF # [参数]初始值 Initial Value : 0xFF
polynomial = 0x1D # [参数]生成多项式 Polynomial = P(x)=x^4+x^3+x^2+1
for i in range(length): # 读入数据
crc ^= ptr[i] # 数据与当前CRC寄存器中的数值进行异或
for j in range(8): # 逐位处理 模拟模2除法
if (crc & 0x80): # 当前高位是1,则左移1位并异或生成多项式(模2除法):左移1位的原因是当前生成多项式表达式不包含最高次幂
crc = ((crc << 1) ^ polynomial) & 0xFF
else: # 当前高位是0,则左移1位
crc = (crc << 1) & 0xFF
crc &= 0xFF # [参数]宽度 Width : 8 bits
return crc ^ 0xFF # [参数]最终异或值 XOR Value : 0xFF
ptr = [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] # 输入数据(此输入数据为计算Check值的输入)
length = 9 # 输入数据长度
crc_value = crc8h1d(ptr, length) # 计算CRCH1D校验值
print(f"The CRC value is: {crc_value:#04x}") # The CRC value is: 0x4b