两种CRC-16算法的实现以及验证

关于CRC-16算法的介绍,请自行查阅相关文章,这里介绍两种常用的CRC-16算法的实现,以及验证其正确性,这两种CRC-16的算法,分别是CRC-16/Modbus和CRC-16/XModem。

一、实现

1. CRC-16/Modbus
名称 宽度 多项式 初始值 结果异或值 输入翻转 输出翻转
CRC-16/Modbus 16 8005 FFFF 0000
/**
 * @brief  计算 Modbus CRC16
 * @param  pDat 数据指针
 * @param  u16Len 数据长度
 * @retval uint16_t CRC16
 */
uint16_t CRC16Modbus_CalculateWithPoly(const uint8_t *pDat, uint16_t u16Len)
{
	// Init: 0xffff, Poly: 0x8005
    uint16_t u16Crc = 0xffff;
	uint8_t i;

    while (u16Len--)
    {
        u16Crc ^= *pDat++;

        for (i = 0; i < 8; i++)
        {
            if (u16Crc & 0x1)
            {
                u16Crc >>= 1;
                u16Crc ^= 0xa001; // 0x8005 翻转 0xa001
            }
            else
            {
                u16Crc >>= 1;
            }
        }
    }

    return u16Crc;
}

由于CRC-16/Modbus算法需要输入反转,为了提高代码的执行效率,提前将多项式0x8005按位翻转成0xa001,并且用 u16Crc & 0x1 的条件进行判断,这样输入就不需要翻转了。

2. CRC-16/XModem
名称 宽度 多项式 初始值 结果异或值 输入翻转 输出翻转
CRC-16/XModem 16 1021 0000 0000
/**
 * @brief 计算 CRC16/XMODEM
 * @param pDat 数据指针
 * @param u16Len 数据长度
 * @return uint16_t CRC16
 */
uint16_t CRC16XModem_CalculateWithPoly(const uint8_t *pDat, uint16_t u16Len)
{
	uint16_t u16Crc = 0x0000;
	uint16_t u16Poly = 0x1021;
	uint8_t u8Dat = 0;
	uint8_t i;

	while (u16Len--)
	{
		u8Dat = *pDat++;
		u16Crc ^= (u8Dat << 8);

		for (i = 0; i < 8; i++)
		{
			if (u16Crc & 0x8000)
			{
				u16Crc = (u16Crc << 1) ^ u16Poly;
			}
			else
			{
				u16Crc = u16Crc << 1;
			}
		}
	}

	return u16Crc;
}

这两种CRC-16的算法同样也可以使用查表法进行实现,相关的代码可以参考:https://gitee.com/zzxnj/chip_c

二、验证

分别使用直接计算法和查表法,对相同的数据区进行计算,并打印出结果;

static void TestCrc_privCrc16(const uint8_t *pBuf, uint16_t u16Len)
{
    uint16_t u16Crc1, u16Crc2;

    // 计算 CRC16/Modbus
    u16Crc1 = CRC16Modbus_CalculateWithPoly(pBuf, u16Len);
    u16Crc2 = CRC16Modbus_CalculateWithTable(pBuf, u16Len);
    printf("CRC16 Modbus -> 0x%X 0x%X\n\n", u16Crc1, u16Crc2);

    // 计算 CRC16/XMODEM
    u16Crc1 = CRC16XModem_CalculateWithPoly(pBuf, u16Len);
    u16Crc2 = CRC16XModem_CalculateWithTable(pBuf, u16Len);
    printf("CRC16 XModem -> 0x%X 0x%X\n\n", u16Crc1, u16Crc2);
}

打印出的结果可以和第三方软件计算的结果进行比较,以验证其正确性;

static const uint8_t trBuffer1[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
TestCrc_privCrc16(trBuffer1, sizeof(trBuffer1));

用户可以自行修改 trBuffer1 中的内容,实现对不同数据进行CRC-16的计算。

你可能感兴趣的:(chip,c,算法)