【问题标题】:CRC 16 -DECT with poly x^16 + x^10 + x^8 + x^7 + x^3 + 1CRC 16 -DECT 与 poly x^16 + x^10 + x^8 + x^7 + x^3 + 1
【发布时间】:2010-11-27 01:32:33
【问题描述】:

相信我,我尝试过编写此代码,尝试过 Google,但没有任何运气。 我正在尝试使用这个 poly 实现 CRC16

x^16 + x^10 + x^8 + x^7 + x^3 + 1

使用 C 语言。由于我对 PHP 的理解更好,我正在尝试运行一个函数,但我没有得到 28713 的正确答案。此代码生成的 CRC 为 32713。

function crc16($string,$crc=0) {

for ( $x=0; $x<strlen( $string ); $x++ ) {

    $crc = $crc ^ ord( $string[$x] );
    echo $crc.'<br />';
    for ($y = 0; $y < 8 ; $y++) {

        if ( ($crc & 0x0001) == 0x0001 ) $crc = ( ($crc >> 1 ) ^ 0x10589  );
        else                             $crc =    $crc >> 1;
    }
}

    return $crc;
}


echo 'CRC:'.crc16('10100011');

请大家帮忙解决这个问题..提前谢谢。

【问题讨论】:

    标签: php c crc16


    【解决方案1】:
    1. 有些 CRC 被定义为处理从每个字节从 MSB 到 LSB 的位,有些被定义为从 LSB 到 MSB 处理位(后者通常是被描述为“反射”的顺序并使用反向多项式)。您的代码将新位放入 CRC 的 LSB 端并右移,这适用于反射 CRC,但 CRC-16-DECT 似乎是未反射的之一。

    2. 您输入的“10100011”建​​议使用二进制,但正在处理为 8 字节 ASCII 字符串。

    要查看将 10100011 视为二进制并首先从 MSB 工作时会发生什么,这里是手动计算(因为 8 位输入不需要太多努力):

    polynomial coefficients
            |
            |            10100010  <--- quotient (irrelevant)
            v          __________
     10000010110001001 ) 10100011  <-------- input
                       ^ 10000010110001001
                         -----------------
                       =   100001110001001
                         ^ 10000010110001001
                           -----------------
                         =      101110101101
                              ^ 10000010110001001
                                -----------------
       remainder (CRC) -----> =   111000000101001
         = 0x7029 = 28713
    

    因此,将输入视为二进制并首先使用 MSB 是正确的做法。

    这里有一些 C 代码来完成这项工作(因为我不是很喜欢 PHP,最终你还是想要 C 代码):

    #include <stdio.h>
    #include <stdint.h>
    
    static uint16_t crc16(const uint8_t *data, size_t len)
    {
        size_t i, j;
        uint16_t crc = 0;
    
        for (i = 0; i < len; i++) {
            crc ^= (data[i] << 8);              /* data at top end, not bottom */
            for (j = 0; j < 8; j++) {
                if ((crc & 0x8000) == 0x8000)   /* top bit, not bottom */
                    crc = (crc << 1) ^ 0x0589;  /* shift left, not right */
                else
                    crc <<= 1;                  /* shift left, not right */
            }
        }
    
        return crc;
    }
    
    int main(void)
    {
        const uint8_t in[] = { 0xa3 };          /* = 10100011 in binary */
        uint16_t crc = crc16(in, sizeof(in));
    
        printf("%u (0x%x)\n", crc, crc);
        return 0;
    }
    

    结果:

    $ gcc -Wall -o crc16 crc16.c
    $ ./crc16  
    28713 (0x7029)
    $ 
    

    【讨论】:

    • 马修,伙计。我欠你一杯。工作完美,非常感谢,这解决了我关于 CRC 的很多问题。
    • 假设我不知道数据的大小,而不是 8 位,我得到 16 位...0xA4321。
    • 不确定我理解你的意思。 crc16() 采用指向字节缓冲区的指针和字节长度 - 所以如果您需要 16 位以上的 CRC(0xA4321 是 20 位!),请传入 2 字节缓冲区和长度为 2。(在我的例如,我使用sizeof(in) 自动计算出数组的长度,因此您可以将{ 0xa3 } 更改为{ 0xa3, 0x21 } 或其他任何值。)
    • 输入文件会有这样的数据,0123456789ABCEDF。我需要能够将其分解并传递...
    • 感谢您花时间帮我解决这个问题。你的代码就像你说的那样工作。我的问题是 c 不像 php 那样动态,例如我需要将这样的字符串“0123456789ABCDEF”转换为 in[] = { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCE,0xDF };跨度>
    【解决方案2】:

    尝试将 0x10589 更改为 0xA001:

    function crc16($string,$crc=0) {
    
        for ( $x=0; $x<strlen( $string ); $x++ ) {
    
            $crc = $crc ^ ord( $string[$x] );
            for ($y = 0; $y < 8; $y++) {
    
                if ( ($crc & 0x0001) == 0x0001 ) $crc = ( ($crc >> 1 ) ^ 0xA001 );
                else                             $crc =    $crc >> 1;
            }
        }
    
        return $crc;
    }
    

    【讨论】:

    • 返回的 CRC 为 46445...这不是反向多边形吗?
    • 最重要的 Bit First 等于 0x0589,而不是 0x10589。但我仍然得到错误的答案。
    【解决方案3】:

    这段代码每次都有效,但我并不完全理解发生了什么。

      char *MakeCRC(char *BitString)
       {
      static char Res[17];                                 // CRC Result
      char CRC[16];
        int  i;
      char DoInvert;
    
       for (i=0; i<16; ++i)  CRC[i] = 0;                    // Init before calculation
    
       for (i=0; i<strlen(BitString); ++i)
        {
       DoInvert = ('1'==BitString[i]) ^ CRC[15];         // XOR required?
    
      CRC[15] = CRC[14];
      CRC[14] = CRC[13];
      CRC[13] = CRC[12];
      CRC[12] = CRC[11];
      CRC[11] = CRC[10];
      CRC[10] = CRC[9] ^ DoInvert;
      CRC[9] = CRC[8]; 
      CRC[8] = CRC[7] ^ DoInvert;
      CRC[7] = CRC[6] ^ DoInvert;
      CRC[6] = CRC[5];
      CRC[5] = CRC[4];
      CRC[4] = CRC[3];
      CRC[3] = CRC[2] ^ DoInvert;
      CRC[2] = CRC[1];
      CRC[1] = CRC[0];
      CRC[0] = DoInvert;
      }
    
      for (i=0; i<16; ++i)  Res[15-i] = CRC[i] ? '1' : '0'; // Convert binary to ASCII
      Res[16] = 0;                                         // Set string terminator
    
        return(Res);
        }
    
    
         // A simple test driver:
    
        #include <stdio.h>
    
       int main()
        {
        char *Data, *Result;                                       // Declare two strings
    
        Data = "1101000101000111";
        Result = MakeCRC(Data);                                    // Calculate CRC
    
        printf("CRC of [%s] is [%s] with P=[10000010110001001]\n", Data, Result);
    
         return(0);
          }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多