【问题标题】:Issues calculating CRC16 MCRF4XX for more than 1 byte计算 CRC16 MCRF4XX 超过 1 个字节的问题
【发布时间】:2019-12-26 09:17:50
【问题描述】:

我一直在尝试在我的代码中执行 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。 它会给我一个与计算器给出的完全不同的计算。

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

感谢您的帮助!

【问题讨论】:

  • 调用代码在参数中传递 CRC,但函数从不使用它,而是在每次调用时设置 CurrentCRC = 0xffff。
  • 我明白你在说什么,但正如我所提到的,我尝试异或返回到 Crc 参数,但最终它返回错误的 CRC 计算 2 个字节。据我了解,我需要为每个字节做初始 FFFF,如果我错了,请纠正我。
  • 你错了。 CRC 仅在每个字节块之前初始化一次以计算 CRC。根据算法,在计算时您甚至需要输入 0 字节来代替附加的 CRC 以获得正确的 CRC,并且在检查时您将输入附加的 CRC 并检查生成的 CRC 是否为 0。您可能想阅读@ 987654323@了解更多详情。
  • 发布完整的代码——不仅仅是函数体。这将使某人更容易和更有可能构建代码来复制您的问题。无论如何,参数Crc 是当前的CRC - currentCrc 没有任何作用。你当然不是第一个这样做的人 - 没有必要自己发明:gist.github.com/aurelj/270bb8af82f65fa645c1, ww1.microchip.com/downloads/en/AppNotes/00752a.pdf
  • 不要自欺欺人地认为register 做了任何有用的事情。

标签: c embedded crc calculation crc16


【解决方案1】:

您的函数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 ;
}

应用&amp; 运算符时发生的隐式转换使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 ;
}

【讨论】:

  • 在二进制补码机器上,crc = (crc&gt;&gt;1)^((0-(crc&amp;1))&amp;0x8408);(无条件)。优化编译器可能会为? : 版本生成基本相同的代码。
  • @rcgldr :当然,但问题是关于修复代码而不是优化它。鉴于 MCRF4XX 的性质,我怀疑是否有必要进一步优化,并且有利于清晰。同一链接的替代实现甚至不使用位循环,但如果必须解释它,如果不需要优化,最好不要使用它。
  • 在优化 CRC 时更常见的是一次处理 8 位的表查找。我之前的评论只是关于 ? :这消除了条件,并且可能已经有优化编译器可以做到这一点。
  • 查找表会以内存为代价来优化速度 - 所以这取决于您要优化什么。我的观点是,这些都是值得关注的“过早优化”,但考虑到 MCRF4XX 设备的低数据速率(通常为 70kbps)和小数据长度(32 位),可能没有必要。
  • @rcgldr 是查找表增加了所需的内存,而不是代码。
【解决方案2】:

完整的代码,包括 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 2020-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多