计算超过 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 ;
}
我一直在尝试在我的代码中执行 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 ;
}