三种CRC校验其实大体上都是相同的,就是几个参数不同而已:
#include <stdint.h>
#include <stdio.h>
#define POLYNOMIAL_CRC7 0x89ul
#define POLYNOMIAL_CRC8 0x131
#define POLYNOMIAL_CRC16 0x11021ul
/* 计算CRC7校验码 */
uint8_t calc_crc7(const void *data, int len)
{
const uint8_t *p = data;
int i, j;
uint16_t temp = 0;
if (len != 0)
temp = p[0] << 8;
for (i = 1; i <= len; i++)
{
if (i != len)
temp |= p[i];
for (j = 0; j < 8; j++)
{
if (temp & 0x8000)
temp ^= POLYNOMIAL_CRC7 << 8;
temp <<= 1;
}
}
return temp >> 9;
}
/* 计算CRC8校验码 */
uint8_t calc_crc8(const void *data, int len)
{
const uint8_t *p = data;
int i, j;
uint16_t temp = 0;
if (len != 0)
temp = p[0] << 8;
for (i = 1; i <= len; i++)
{
if (i != len)
temp |= p[i];
for (j = 0; j < 8; j++)
{
if (temp & 0x8000)
temp ^= POLYNOMIAL_CRC8 << 7;
temp <<= 1;
}
}
return temp >> 8;
}
/* 计算CRC16校验码 */
uint16_t calc_crc16(const void *data, int len)
{
const uint8_t *p = data;
int i, j;
uint32_t temp = 0;
if (len & 1)
{
printf("%s: data size %d is odd!\n", __FUNCTION__, len);
len--; // 不允许出现奇数长度
}
if (len != 0)
temp = (p[0] << 24) | (p[1] << 16); // 填充前二分之一
if (len > 2)
temp |= p[2] << 8; // 填充到四分之三
for (i = 3; i <= len + 2; i++)
{
if (i < len)
temp |= p[i]; // 每次都填充最后四分之一的空间
// 从左数第0~7位计算到左数第16~23位
for (j = 0; j < 8; j++)
{
if (temp & 0x80000000)
temp ^= POLYNOMIAL_CRC16 << 15;
temp <<= 1;
}
}
return temp >> 16;
}
/* 计算CRC时翻转字节位 */
uint8_t invert_byte(uint8_t byte)
{
int i;
uint8_t value = 0;
for (i = 0; i < 8; i++)
{
if (byte & (1 << i))
value |= 1 << (7 - i);
}
return value;
}
/* 计算CRC8Inv校验码 */
uint8_t calc_crc8_inv(const void *data, int len)
{
const uint8_t *p = data;
int i, j;
uint16_t temp = 0;
if (len != 0)
temp = invert_byte(p[0]) << 8; // 输入数据反转(REFIN)
for (i = 1; i <= len; i++)
{
if (i != len)
temp |= invert_byte(p[i]);
for (j = 0; j < 8; j++)
{
if (temp & 0x8000)
temp ^= POLYNOMIAL_CRC8 << 7;
temp <<= 1;
}
}
return invert_byte(temp >> 8); // 输出数据反转(REFOUT)
}
int main(void)
{
uint8_t data[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef};
printf("CRC7: 0x%02x\n", calc_crc7(data, sizeof(data)));
printf("CRC8: 0x%02x\n", calc_crc8(data, sizeof(data)));
printf("CRC16: 0x%04x\n", calc_crc16(data, sizeof(data)));
printf("CRC8Inv: 0x%02x\n", calc_crc8_inv(data, sizeof(data)));
return 0;
}
程序运行结果:
CRC7: 0x7f
CRC8: 0x22
CRC16: 0x2fbc
CRC8Inv: 0xbe