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



我一直在尝试在我的代码中执行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 对输出进行 XOR 运算,但它加起来不正确。

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

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

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

感谢您的帮助!

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

在调用 this 的代码中,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);
}

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

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 ;
}

已完成的代码,包括 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=%04xn", (unsigned) i, data[i], (unsigned) crc);
}
fprintf(stderr, "CrC=%04xn", (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;
}

最新更新