分享

CRC16算法学习笔记

 生命随时光流逝 2017-03-29

一.CRC原理
CRC(Cyclic Redundancy Check)即循环冗余校检码,和奇偶校检码一样,是用来检验数据传输的错误的,其原理用到的是多项式除法。
首先一串比特流,可以表示为一个F2域上的多项式,比如10110110 可以表示为g(x) = x^7 + x^5 +x^4 + x^2 + x^1 ,我们所要做的是找到一个不可约多项式,比如h(x) = x^8+x^6+x^4+x^3+x^2+x,然后将g(x)乘以x^8,即比特流左移8位,然后将其除以h(x), 所得到的余数即为我们要的CRC码。
上面的例子是CRC-8的算法,相应的,CRC16将比特流左移16位,h(x)是一个次数为16的不可约多项式。
那么接下来讨论一下,如何生成CRC16码。

二.CRC的三种算法
1.比特型算法
由F2域上的多项式除法可知,两式相除,其实就是做异或运算。

多项式除法示例
可以观察到当首位为1的时候就进行异或运算,为0就将比特流左移一位,
直到比特流最后一位也参与到运算。
图引自百度文库:
http://wenku.baidu.com/link?url=W3vwtcrzv5f0G5hCke028G5FVZSCia1kyhmHFKArbKPWi5uFZLZFCJYqOF0qbvnQ-ws3uvATXpPKy9FyJaB21kBzsX5rBY7cfuhyVYo9ujG

算法如下:
1.扩大数据流(左移16位)
2.创建一个16位的寄存器,初始值为数据流前16位
3.
while(比特流最后一位未读入寄存器)
{
if(首位为0)
{
左移一位,低位从比特流中下一位读取
}
else
{
和h(x)进行异或运算
}
}
这样最后16位寄存器中的数据就是求得的16位CRC码。
需要注意的是,h(x)只要是传输方和接收方都约定好的16次不可约多项式都可以,标准CRC16用的多项式是x^16 + x^15 + x^2 + 1,即0x8005。

2.字节型算法
一位博主原理总结得十分详细,下面连接供大家参考:
http://www.cnblogs.com/Msisiterc/archive/2011/12/20/2294910.html

下面贴出字节型算法中的查表法C#的代码

        ///CRC16表
        static ushort[] CRC16Table = 
        {
            0x0, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,  
           0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,  
           0x1231, 0x210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,  
           0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,  
           0x2462, 0x3443, 0x420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,  
           0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,  
           0x3653, 0x2672, 0x1611, 0x630, 0x76D7, 0x66F6, 0x5695, 0x46B4,  
           0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,  
           0x48C4, 0x58E5, 0x6886, 0x78A7, 0x840, 0x1861, 0x2802, 0x3823,  
           0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,  
           0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0xA50, 0x3A33, 0x2A12,  
           0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,  
           0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0xC60, 0x1C41,  
           0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,  
           0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0xE70,  
           0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,  
           0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,  
           0x1080, 0xA1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,  
           0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,  
           0x2B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,  
           0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,  
           0x34E2, 0x24C3, 0x14A0, 0x481, 0x7466, 0x6447, 0x5424, 0x4405,  
           0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,  
           0x26D3, 0x36F2, 0x691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,  
           0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,  
           0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x8E1, 0x3882, 0x28A3,  
           0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,  
           0x4A75, 0x5A54, 0x6A37, 0x7A16, 0xAF1, 0x1AD0, 0x2AB3, 0x3A92,  
           0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,  
           0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0xCC1,  
           0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,  
           0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0xED1, 0x1EF0        
        };

/// <summary>
/// 生成CRC16码
/// </summary>
/// <param name="bytes">生成CRC的字节数组</param>
/// <returns>生成的冗余码数组</returns>
 private static byte[] CRC16(Byte[] bytes)
  {
     int count = bytes.Length;

     ushort crc = 0;

     Byte crctemp;

     int i = 0;

     while (count > 0)
     {
         count -= 1;

         crctemp = Convert.ToByte(crc >> 8);

         crc = (ushort)((crc << 8) & 0xFFFF);

         crc = (ushort)((CRC16Table[crctemp ^ bytes[i]] ^ crc) & 0xFFFF);

          i += 1;
      }

     return new byte[] { (byte)(crc >> 8), (byte)(crc & 0xFF) };

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多