文章目录
A.1 CRC8 算法
A.1.1 CRC8 算法参数设置
CRC8 算法中要求了 Counter、Data ID、CRC 等参数设置。
参数描述Counter共 4bits,在 CAN 总线通信时,从 0-15 滚动发送。Message ID共 16bits(在 ID 前用 ‘0’ 填充后),总线报文 ID,在进行 CRC 计算时应包含。CRC共 8bits,CRC 算法参照 SAE J1850,生成多项式为0x1D(x8+x4+x3+x2+1),但初始值和 XOR 值均替换为0x00,在 CAN 总线上发送
A.1.2 Counter
在 CRC8 算法中,发送方在第一次发送时将 Counter 置为 0,并在后续每次发送时将
Counter 加 1。当 Counter 值达到 15(0xF)后,发送方的下一次发送将 Counter 重新置为0。
接收节点在接收到报文后对 Counter 值进行监控:
a)连续接收到 4 个周期 Counter 值相同时不计为错误,但在随后第 5 个周期中 Counter
值仍相同时,需记录 Counter 错误;
b)当连续接收到连续 3 个周期的 Counter 差值≥2 时,需记录 Counter 错误;
当检查到 Counter 错误时,将使用信号定义的 Invalid 值或替代值,直到 Counter 值恢复连续为止。
A.1.3 Message ID
在 CRC8 算法中,Message ID( 在 ID 前用 ‘0’ 填充)的 2 个字节(16bits)都会包含在 CRC计算中。在计算时,将 Data ID 加入在需保护数据之前。
A.1.4 CRC
在 CRC8 算法中,CRC 计算使用了 SAE J1850,生成多项式为 0x1D(x8+x4+x3+x2+1) ,但初始值和 XOR 值均替换为 0x00。*
(Autosar E2E profile 1 规定采用CRC-8-SAE J1850 ,对应多项式 [公式] ,即100011101,通常写为0x1D,注意这里不是0x11D,最高位为1省去了。)*
在 CRC 计算时,计算示例见图 1
a)首先计算 Message ID 的两个字节,先 高字节 后 低字节 ;
b)其次计算在总线上发送的需要保护的信号/信号组(不包含 CRC 字段)
A.1.5 CRC8 算法示例
a)报文 ID(Msg ID):0x345
b)需保护的数据(Protected Data):0x11 0x22 0x33 0x44 0x55 0x66 0x77
c)CRC8_Checksum = CRC8(0x03 0x45 0x11 0x22 0x33 0x44 0x55 0x66 0x77)
d)CRC8_checksum = 0x15
A.1.6 CRC8 算法推荐
/*定义 CRC8(计算规则 0x1D)的查表的表格*/const uint8_t crc_table[256]={0x00,0x1D,0x3A,0x27,0x74,0x69,0x4E,0x53,0xE8,0xF5,0xD2,0xCF,0x9C,0x81,0xA6,0xBB,0xCD,0xD0,0xF7,0xEA,0xB9,0xA4,0x83,0x9E,0x25,0x38,0x1F,0x02,0x51,0x4C,0x6B,0x76,0x87,0x9A,0xBD,0xA0,0xF3,0xEE,0xC9,0xD4,0x6F,0x72,0x55,0x48,0x1B,0x06,0x21,0x3C,0x4A,0x57,0x70,0x6D,0x3E,0x23,0x04,0x19,0xA2,0xBF,0x98,0x85,0xD6,0xCB,0xEC,0xF1,0x13,0x0E,0x29,0x34,0x67,0x7A,0x5D,0x40,0xFB,0xE6,0xC1,0xDC,0x8F,0x92,0xB5,0xA8,0xDE,0xC3,0xE4,0xF9,0xAA,0xB7,0x90,0x8D,0x36,0x2B,0x0C,0x11,0x42,0x5F,0x78,0x65,0x94,0x89,0xAE,0xB3,0xE0,0xFD,0xDA,0xC7,0x7C,0x61,0x46,0x5B,0x08,0x15,0x32,0x2F,0x59,0x44,0x63,0x7E,0x2D,0x30,0x17,0x0A,0xB1,0xAC,0x8B,0x96,0xC5,0xD8,0xFF,0xE2,0x26,0x3B,0x1C,0x01,0x52,0x4F,0x68,0x75,0xCE,0xD3,0xF4,0xE9,0xBA,0xA7,0x80,0x9D,0xEB,0xF6,0xD1,0xCC,0x9F,0x82,0xA5,0xB8,0x03,0x1E,0x39,0x24,0x77,0x6A,0x4D,0x50,0xA1,0xBC,0x9B,0x86,0xD5,0xC8,0xEF,0xF2,0x49,0x54,0x73,0x6E,0x3D,0x20,0x07,0x1A,0x6C,0x71,0x56,0x4B,0x18,0x05,0x22,0x3F,0x84,0x99,0xBE,0xA3,0xF0,0xED,0xCA,0xD7,0x35,0x28,0x0F,0x12,0x41,0x5C,0x7B,0x66,0xDD,0xC0,0xE7,0xFA,0xA9,0xB4,0x93,0x8E,0xF8,0xE5,0xC2,0xDF,0x8C,0x91,0xB6,0xAB,0x10,0x0D,0x2A,0x37,0x64,0x79,0x5E,0x43,0xB2,0xAF,0x88,0x95,0xC6,0xDB,0xFC,0xE1,0x5A,0x47,0x60,0x7D,0x2E,0x33,0x14,0x09,0x7F,0x62,0x45,0x58,0x0B,0x16,0x31,0x2C,0x97,0x8A,0xAD,0xB0,0xE3,0xFE,0xD9,0xC4};4/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * crc_table[256]表中参数是{0...255}中每个元素与OX1D异或的结果******
* * CRC8 校验子程序 0x1D(x8+x4+x3+x2+1) * * * * * * * * * * * *
* * 参数 1,uint8_t *data:需要计算的数据 * * * * * * * * * * *
* * 参数 1,uint16_t len:需要计算的数据字节长度 * * * * * * * *
* * 返回值,uint8_t crc8:计算出的 CRC 值 * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint8_t crc_8find(uint8_t *data, uint16_t len){
uint8_t crc8 =0x00;while( len--){
crc8 = crc_table[crc8 ^*data];
data++;}return crc8;}
附手写计算图片:
A.1.7 CRC8 算法示例实操
下边是C代码实现部分,可以看出每计算一个byte移位8次,如果考虑运行速度的话可以提前计算出0x00-0xFF每一个数据对应的CRC先放好,然后再查表,这就是上面推荐的CRC方法(
查表法
)。
下面我们用异或的方式计算:
unsignedcharmyCRC8(unsignedchar pData[],int len){unsignedchar u8Crc;int i;int j;
u8Crc =0;//一个字节均为0for(i=0; i<len; i++)//字节循环{
u8Crc ^= pData[i];//与0异或是自己本身,取得第一个字节for(j=0;j<8;j++)//计算循环{if(u8Crc &0x80)//判断高位是否为1{
u8Crc <<=1;//对齐与0x11D,低位补0
u8Crc ^=0x1D;//Autosar profile 1.原为0X11D舍弃了高位1}else{
u8Crc <<=1;//左移一位}}}
u8Crc ^=0;//与0异或是自己本身return u8Crc;//传回CRC}intmain(){unsignedchar Crc;unsignedchar data[9]={0x030x450x110x220x330x440x550x660x77};
Crc =myCRC8(data,9);//传入参数到函数 printf("Crc=0x%x---%d",Crc,Crc);return0;}
验证计算是否正确可以在网站上搜索CRC在线计算:
A.1.8 CAN有关小知识
缩写全称LSBleast significant byteMSBmost significant bytelsbleast significant bitmsbmost significant bit
CAN报文数据域传输顺序:
字节顺序:先传Byte0(LSB),最后传Byte7(MSB);
字节内位序:先传bit7(lsb),最后传bit0(msb);
当信号在一个字节内实现(信号不跨字节)时,Intel模式和Motorola模式的信号字节顺序,完全一样:
**
信号的高位(MSB)放在该字节的高位,信号的低位(LSB)放在该字节的低位。
**
当信号在多个字节内实现(信号跨字节)时,Intel模式和Motorola模式的信号字节顺序,明显不同:
**
Intel模式:信号的高位(MSB)放在高字节的高位,信号的低位(LSB)放在低字节的低位;
**
**
Motorola模式:信号的高位(MSB)放在低字节的高位,信号的低位(LSB)放在高字节的低位。
**
俗称:小端模式
“高在后,低在前”
;大端模式
“高在前,低在后”
。不管Intel模式,还是Motorola模式,起始位都该信号的低位(lsb)。
高八位、低八位
高八位:10101100
G=(AC47>>8)&0XFF
低八位:01000111
D=AC47&0XFF
高四位、低四位
高四位:1101
G=D4&0XF0
低四位:0100
D=D4&0X0F
A.1.9 附加小知识
两个数组合并一个数组输出
#include<stdio.h>intmain(){int i;int j=0;unsignedchar A[7]={0x11,0x22,0x33,0x44,0x55,0X66,0x77};int p;
p=0x345;unsignedchar C[9];
C[0]=((p>>8)&0xFF);
C[1]=(p &0xFF);//for(i=0;i<7;i++){
C[j+2]=A[i];
j++;}//C[j]='\0'; for(i=0;i<9;i++){printf("C=%x",C[i]);printf("\n");}return0;}
版权归原作者 SDK.Paraman 所有, 如有侵权,请联系我们删除。