CRC-16
文章目录A.1 CRC16 算法A.1.1 CRC16 算法参数设置A.1.2 LengthA.1.3 CounterA.1.4 Data IDA.1.5 CRCA.1.6 CRC16 算法示例A.1.7 CRC16 算法推荐(查表法)A.1.8 CRC16 实例(查表法)A.1 CRC16 算法A.1.1 CRC16 算法参数设置CRC16 算法中要求了 Counter、Data ID、CRC
文章目录
A.1 CRC16 算法
A.1.1 CRC16 算法参数设置
CRC16 算法中要求了 Counter、Data ID、CRC 等参数设置。
参数 | 描述 |
---|---|
Length | 共 16bits,支持长度可变的动态数据,在 CAN 总线发送 |
Counter | 共 8bits,在 CAN 总线通信时,从 0-255 滚动发送。 |
Data ID | 共 16bits,唯一的数据标识符,在进行 CRC 计算时应包含,但不在 CAN 总线上发送。 |
CRC | 共 16bits,CRC 算法的生成多项式为0x1021(x16+x12+x5+1),初始值为 0Xff,XOR 值为0x00,在 CAN 总线发送 |
A.1.2 Length
在 CRC16 算法中,在每次发送的数据长度可能变化时,可使用 Length 表示本次发送的
数据的长度,Length = CRC + Counter +Length。
A.1.3 Counter
在 CRC16 算法中,发送方在第一次发送时将 Counter 置为 0,并在后续每次发送时将Counter 加 1。当 Counter 值达到 255(0xFF)后,发送方的下一次发送将 Counter 重新置为 0。
接收节点在接收到报文后对 Counter 值进行监控:
a)连续接收到 4 个周期 Counter 值相同时不计为错误,但在随后第 5 个周期中 Counter值仍相同时,需记录 Counter 错误;
b)当连续接收到连续 3 个周期的 Counter 差值≥2 时,需记录 Counter 错误;当检查到 Counter 错误时,将使用信号定义的 Invalid 值或替代值,直到 Counter 值恢复连续为止。
A.1.4 Data ID
在 CRC16 算法中,Data ID 的 2 个字节(16bits)都会包含在 CRC 计算中。在计算时,将Data ID 加入在需保护数据之后。
A.1.5 CRC
在 CRC16 算法中,CRC 算法规则为:0x1021(x16+x12+x5+1),初始值为 0xFF,XOR 值为0x00
在 CRC 计算时,计算示例见图
a)首先计算在总线上发送的需要保护的信号/信号组(不包含 CRC 字段)
b)其次计算 Data ID 的两个字节,先高字节后低字节;
A.1.6 CRC16 算法示例
a)数据标识符(Data ID):0x1234
b)需保护的数据(Protected Data):0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
c)Counter = 0x01;Length = 0x000D;
d)CRC16_Checksum = CRC16(0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x01 0x00
0x0D 0x12 0x34)
e)CRC16_checksum = 0x821A
A.1.7 CRC16 算法推荐(查表法)
/*定义 CRC16(计算规则 0x1021)的查表的表格*/
const uint16_t crc_table[256] ={
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};
7
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * CRC 校验子程序 0x1021(x16+x12+x5+1) * * * * * * * * * * * *
* * 参数 1,uint8_t *data:需要计算的数据 * * * * * * * * * * *
* * 参数 1,uint16_t len:需要计算的数据字节长度 * * * * * * * *
* * 返回值,uint16_t crc16:计算出的 CRC 值 * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint16_t crc_16(uint8_t *data, uint16_t len)
{
uint16_t crc16 = 0xFFFF; //定义 CRC 计算的初始值
uint16_t crc_high8, crc_low8;
while( len-- ) {
crc_high8 = (crc16 >> 8);
crc_low8 = (crc16 << 8);
crc16 = crc_low8 ^ crc_table[crc_high8 ^ *data];
data++;
}
return crc16;
}
A.1.8 CRC16 实例(查表法)
查表法
#include<stdio.h>
const unsigned short crc_table[256] ={
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * CRC 校验子程序 0x1021(x16+x12+x5+1) * * * * * * * * * * * *
* * 参数 1,uint8_t *data:需要计算的数据 * * * * * * * * * * *
* * 参数 1,uint16_t len:需要计算的数据字节长度 * * * * * * * *
* * 返回值,uint16_t crc16:计算出的 CRC 值 * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
unsigned short crc_16(unsigned char *data, int len)
{
unsigned short crc16 = 0xFFFF; //定义 CRC 计算的初始值
unsigned short crc_high8, crc_low8;
while( len-- ) {
crc_high8 = (crc16 >> 8);
crc_low8 = (crc16 << 8);
crc16 = crc_low8 ^ crc_table[crc_high8 ^ *data];
data++;
}
return crc16;
}
void main()
{
unsigned char data[13]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x01,0x00,0x0d,0x12,0x34};
unsigned short crc;
crc=crc_16(data,13);
printf("0x%.2x",crc);
}
逻辑法
#include<stdio.h>
unsigned short UpdateCRC(unsigned char *CRC_input, unsigned int len)
{
unsigned char i,k = 0;
unsigned short CRC=0xffff;
int j;
#define POLY_ 0x1021
while (len--)
//for (j = 0; j <13; j++)
{
CRC = CRC ^ (CRC_input[k++] << 8);//CRC异或为本身,crc为16bits CRC_input[k] << 8为0x1100
for (i = 0; i < 8; i++)
{
if ((CRC & 0x8000) == 0x8000)//判断高位是否为1
{
CRC = CRC << 1;//左移一位
CRC ^= POLY_;//异或多项式
}
else
{
CRC = CRC << 1;//左移一位
}
}
}
return CRC;
}
int main(){
unsigned short crc;
unsigned char buf_value[13] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x01,0x00,0x0d,0x12,0x34};
int i;
crc=UpdateCRC(buf_value,13);
printf("%x\n",crc);
return 0;
}
更多推荐
所有评论(0)