RSS

CRC的原理和实现

来源: 作者: 时间:2008-04-02 Tag: 点击:
现在内循环只与index相关了,可以事先以数组形式生成一个表crc16_ccitt_table,使得
to_xor = crc16_ccitt_table[index],于是可以简化为:
unsigned short do_crc(unsigned char *message, unsigned int len)
{
    unsigned short crc_reg = 0;
         
    while (len--)
        crc_reg = (crc_reg >> 8) ^ crc16_ccitt_table[(crc_reg ^ *message++) & 0xff];
       
    return crc_reg;
}  
crc16_ccitt_table通过以下代码生成:
int main()
{
    unsigned char index = 0;
    unsigned short to_xor;
    int i;
    printf("unsigned short crc16_ccitt_table[256] =\n{");

字串8


    while (1)
    {
        if (!(index % 8))
            printf("\n");
       
        to_xor = index;      
        for (i = 0; i < 8; i++)
        {
            if (to_xor & 0x0001)
                to_xor = (to_xor >> 1) ^ 0x8408;
            else
                to_xor >>= 1;          
        }            字串9
        printf("0x%04x", to_xor);
       
        if (index == 255)
        {
            printf("\n");
            break;
        }
        else
        {
            printf(", ");
            index++;
        }
    }
    printf("};");
    return 0;
}
生成的表如下:
unsigned short crc16_ccitt_table[256] =
字串2

{
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 字串9
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
字串3

0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
这样对于消息unsigned char message[len],校验码为:
    unsigned short code = do_crc(message, len);
并且按以下方式发送出去:
    message[len] = code & 0x00ff;
    message[len + 1] = (code >> 8) & 0x00ff;
   
接收端对收到的len + 2字节执行do_crc,如果没有差错发生则结果应为0。
在一些传输协议中,发送端并不指出消息长度,而是采用结束标志,考虑以下几种差错:
    1)在消息之前,增加1个或多个0字节;
    2)消息以1个或多个连续的0字节开始,丢掉1个或多个0;
    3)在消息(包括校验码)之后,增加1个或多个0字节;
    4)消息(包括校验码)以1个或多个连续的0字节结尾,丢掉1个或多个0;
   
显然,这几种差错都检测不出来,其原因就是如果寄存器值为0,处理0消息字节(或位),寄 字串2
存器值不变。为了解决前2个问题,只需寄存器的初值非0即可,对do_crc作以下改进:
 
unsigned short do_crc(unsigned short reg_init, unsigned char *message, unsigned int len)
{
    unsigned short crc_reg = reg_init;
         
    while (len--)
        crc_reg = (crc_reg >> 8) ^ crc16_ccitt_table[(crc_reg ^ *message++) & 0xff];
       
    return crc_reg;
}
在CRC16-CCITT标准中reg_init = 0xffff,为了解决后2个问题,在CRC16-CCITT标准中将计
算出的校验码与0xffff进行异或,即:
    unsigned short code = do_crc(0xffff, message, len);
    code ^= 0xffff;
    message[len] = code & 0x00ff;
    message[len + 1] = (code >> 8) & 0x00ff;  
    字串2
显然,现在接收端对收到的所有字节执行do_crc,如果没有差错发生则结果应为某一常值
GOOD_CRC。其满足以下关系:
    unsigned char p[]= {0xff, 0xff};
    GOOD_CRC = do_crc(0, p, 2);
其结果为GOOD_CRC = 0xf0b8。

上一页 1 2下一页
Google
最新评论共有 0 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册
栏目列表
热点关注
相关文章