计算超过 1 个字节的 CRC16 MCRF4XX 的问题

Issues calculating CRC16 MCRF4XX for more than 1 byte

我一直在尝试在我的代码中执行 CRC16 MCRF4XX,但我只成功地执行了 1 个字节。

我已经按照这个指南,具体方法:http://www.piclist.com/techref/method/error/quickcrc16.htm 我在 https://crccalc.com/

中测试了相同的字节

代码如下:

register uint32_t i;
    uint16_t Crc = 0;


    for ( i = 0; i < Len; i++ )
        Crc = Utils_CRC16_MCRF4XX(Crc,pData[i]);

    return ( Crc );

函数"Utils_CRC16_MCRF4XX":

    uint8_t     i;
uint16_t    TempByte, CurrentCRC = 0xFFFF;
//make byte 16 bit format
TempByte = (uint16_t)Byte;

for ( i = 0; i < 8; i++ )
{
    if ( (CurrentCRC & 0x0001) == (TempByte & 0x0001) )
    {
        //right shift crc
        CurrentCRC >>= 1;
        //right shift data
        TempByte >>= 1;   
    }
    else
    {
        CurrentCRC >>= 1;
        TempByte >>= 1;
        CurrentCRC = CurrentCRC ^ 0x8408; /* 1000 0100 0000 1000 = x^16 + x^12 + x^5 + 1 */
    }
}

return ( Crc ^ CurrentCRC);

字节 0x54 的输出将是 0x1B26。 我试过用插入的 Crc 对输出进行异或运算,但结果不正确。

现在,当我尝试为函数提供超过 1 个字节时,我的问题就开始了。

如果假设我会发送它:0x54 0xFF。 它会给我一个与计算器给出的完全不同的计算结果。

我假设我的错误是在对每个字节执行操作后将字节加在一起。

感谢您的帮助!

完成的代码,包括 main() 驱动程序。


#include <stdint.h>
#include <stdio.h>

uint16_t Utils_CRC16_MCRF4XX(uint16_t crc, uint16_t byte);

int main(int argc, char **argv) {

uint32_t i;
    uint16_t crc ;
    uint8_t data[200] =  { 0 };
    uint32_t len ;

    for(len = 0; len+1 < argc; len++ ) {
        sscanf(argv[len+1], "%hhx", &data[len] );
        }

    crc = 0xffff;
    for ( i = 0; i < len; i++ ) {
        crc = Utils_CRC16_MCRF4XX(crc, data[i] );
        fprintf(stderr, "[%u] %2hhx CrC=%04x\n", (unsigned) i, data[i], (unsigned) crc);
    }

    fprintf(stderr, "CrC=%04x\n", (unsigned) crc);
    return 0 ;
}

uint16_t Utils_CRC16_MCRF4XX(uint16_t crc, uint16_t byte)
{
uint8_t i;

for ( i = 0; i < 8; i++ ) {
    register int samelow;
    samelow =  (crc & 1) == (byte & 1) ?1 : 0 ;

    crc >>= 1;
    byte >>= 1;
    if (!samelow) crc ^= 0x8408; /* 1000 0100 0000 1000 = x^16 + x^12 + x^5 + 1 */
    }

  return crc;
}

你的函数 Utils_CRC16_MCRF4XX 应该 更新 Crc,但保留它自己的 CurrentCRC 变量,该变量与当前 CRC 值没有任何关系并重新初始化为每次调用 0xFFFF。 Crc 参数 传入 是当前 CRC,应该更新。

以最少的更改调整您的函数:

uint16_t Utils_CRC16_MCRF4XX( uint16_t Crc, uint8_t Byte )
{
    //make byte 16 bit format
    uint16_t TempByte = (uint16_t)Byte;

    for( uint8_t i = 0; i < 8; i++ )
    {
        if( (Crc & 0x0001) == (TempByte & 0x0001) )
        {
            //right shift crc
            Crc >>= 1;
            //right shift data
            TempByte >>= 1;
        }
        else
        {
            Crc >>= 1;
            TempByte >>= 1;
            Crc = Crc ^ 0x8408;
        }
    }

    return Crc ;
}

在调用它的代码中,Crc 必须初始化为 0xFFFF,而不是零:

uint16_t crc( uint8_t* pData, uint32_t Len )
{
    uint16_t Crc = 0xffffu ;

    for( uint32_t i = 0; i < Len; i++ )
    {
        Crc = Utils_CRC16_MCRF4XX( Crc, pData[i] );
    }
    return (Crc);
}

下面的测试代码产生的结果 0x6F91 与 https://crccalc.com/ 一致:

int main()
{
    uint8_t test[] = "123456789" ;
    uint16_t c = crc( test, sizeof(test) - 1 ) ;
    printf( "%X", (int)c ) ;

    return 0 ;
}

应用 & 运算符时发生的隐式转换使 TempByte 变得多余,因此可以进一步简化:

uint16_t Utils_CRC16_MCRF4XX( uint16_t Crc, uint8_t Byte )
{
    for( uint8_t i = 0; i < 8; i++ )
    {
        if( (Crc & 0x0001) == (Byte & 0x0001) )
        {
            Crc >>= 1;
            Byte >>= 1;
        }
        else
        {
            Crc >>= 1;
            Byte >>= 1;
            Crc = Crc ^ 0x8408;
        }
    }

    return Crc ;
}

调整 https://gist.github.com/aurelj/270bb8af82f65fa645c1 处的解决方案会产生更简洁的解决方案:

uint16_t Utils_CRC16_MCRF4XX( uint16_t Crc, uint8_t Byte )
{
    Crc ^= Byte ;

    for( uint8_t i = 0; i < 8; i++ )
    {
        Crc = (Crc & 0x0001) != 0 ? (Crc >> 1) ^ 0x8408 : 
                                    Crc >> 1 ;
    }

    return Crc ;
}