CRC64用在单片机上很好,因为单片机存放内容小,CRC64比CRC16等更准确,虽然耗时(CRC64时间复杂度为8n,CRC16时间复杂度为2n),但在单片机上来讲,没有什么区别。
CRC在线计算
下面是代码,可以在写进flash内容时候计算一下改内容的CRC64值,附加也写入内容后面(Generate_CRC64_ECMA)。
在进行校验(开机校验,重启校验)时,把内容进行CRC64计算,与写入到Flash里面的CRC64值进行对比,如果一致,则数据没有出错。
// CRC64 ECMA多项式: 0x42F0E1EBA9EA3693
#define CRC64_ECMA_POLY 0x42F0E1EBA9EA3693ULL
/*
判断FLASH里面存放热电偶类型数据是否出错
参数:无
返回:成功返回1,失败返回0
*/
uint8_t Check_CRC64_ECMA(void)
{
unsigned short length = THREMO_NUM;
unsigned long long crc_value = 0xFFFFFFFFFFFFFFFF;
unsigned long long flash_crc_value = 0;
//uint32_t repoAddr = FLASH_BANK2_BASE;
uint8_t data[8];
Flash_Read(FLASH_BANK2_BASE,(uint32_t *)&data,8);
for(int i=0;i<length;i++) // 每个字节都参与运算
{
crc_value ^= (data[i]); // 按位异或XOR
for (uint8_t i = 0; i < 8; i++) // 右移8位
{
if (crc_value & 1) // 如果此时crc_value是奇数,逻辑右移1位后与多项式异或
crc_value = (crc_value >> 1) ^ 0xC96C5795D7870F42; // 多项式POLY为0x42F0E1EBA9EA3693,忽略最高位的1,然后翻转
else
crc_value = crc_value >> 1; // 如果此时crc_value是偶数,仅逻辑右移1位
}
}
crc_value ^= 0xFFFFFFFFFFFFFFFF; // 结果异或值XOROUT为0xFFFFFFFFFFFFFFFF
Flash_Read(FLASH_BANK2_BASE+THREMO_NUM,(uint32_t*)&flash_crc_value,8);
if(crc_value != flash_crc_value)
return 0;
return 1;
}
/*
生成CRC64_ECMA校验的值
参数:data:要检验的数据头指针,length要校验的数据长度
返回:CRC64_VALUE
*/
uint64_t Generate_CRC64_ECMA(const unsigned char *data, unsigned short length)
{
unsigned long long crc_value = 0xFFFFFFFFFFFFFFFF;
uint32_t repoAddr = (uint32_t)data;
const unsigned short length_init = length;
while (length) // 每个字节都参与运算
{
crc_value ^= data[length_init-length]; // 按位异或XOR
for (uint8_t i = 0; i < 8; i++) // 右移8位
{
if (crc_value & 1) // 如果此时crc_value是奇数,逻辑右移1位后与多项式异或
crc_value = (crc_value >> 1) ^ 0xC96C5795D7870F42; // 多项式POLY为0x42F0E1EBA9EA3693,忽略最高位的1,然后翻转
else
crc_value = crc_value >> 1; // 如果此时crc_value是偶数,仅逻辑右移1位
}
++repoAddr;
--length;
}
crc_value ^= 0xFFFFFFFFFFFFFFFF; // 结果异或值XOROUT为0xFFFFFFFFFFFFFFFF
return crc_value;
}