CRC校验
本文只说明如何实现CRC-8,其它参数模型解释请看其它大佬的文章
模二运算相关内容不再赘述
动画推荐
B站up
【[CRC校验]手算与直观演示】 https://www.bilibili.com/video/BV1V4411Z7VA/?share_source=copy_web&vd_source=734d9fe130776e8ae82b2b5371a5f5b8
CRC校验网站推荐
http://www.ip33.com/crc.html
一个大佬的文章
他代码本人看不懂,不知道他是如何实现的。
https://blog.youkuaiyun.com/u013073067/article/details/86621770
本人代码
思路就是动画里这个
就跟“流”进来数据似的
关键就是,将变量CRC左移1位,最低位补入1比特新的数据(来自需要校验的字符串str)
/**
* 左移一位并补充最后一位的数据.
*
* \param D_now 当前字节指针
* \param D_next 下一字节
* \param i 序号
* \note 在循环中使用
*/
void left_and_supply(uint8_t* crc, uint8_t data, int i);
void left_and_supply(uint8_t* D_now, uint8_t D_next, int i)
{
(*D_now) <<= 1;
if (D_next & (0x80 >> i))
(*D_now) |= 0x01;
}
这样使用这个函数
uint8_t arr[4] = { 0x31, 0x32, 0x33, 0x34 };
uint8_t temp = arr[0];
uint8_t* p = arr;
for (; p < &arr[3]; )
{
p++;
for (int i = 0; i < 8; i++)
{
left_and_supply(&temp, *p, i);
printf(" i = %d ", i); binPrintf(temp); printf(" %#0X\n", temp);
}
puts("");
}
binPrintf()调试用的,二进制打印一个字节
/*
* @brief 调试用二进制打印一个字节
*/
void binPrintf(uint8_t binData)
{
for (int i = 0; i < 8; i++)
{
if (binData & (0x80 >> i))
putchar('1');
else
putchar('0');
}
}
测试结果为
i = 0 01100010 0X62
……
i = 7 00110010 0X32
i = 0 01100100 0X64
……
i = 7 00110011 0X33
i = 0 01100110 0X66
……
i = 7 00110100 0X34
CRC-8校验实现
有了准备可容易实现
注意,它多项式为x8 + x2 + x + 1,也就是 1 0000 0111
做模二除法时“找到开头的1”然后后面异或就行。
所以
#define POLY_8 0x07 //0000 0111
void myCRC_8(const void* pStart, size_t count, void* pResult)
{
uint8_t* pEnd = (uint8_t*)pStart + count - 1;
uint8_t* p = (uint8_t*)pStart;
uint8_t crc = *p;
int i;
for (; p < pEnd; )
{
p++;
for (i = 0; i < 8; i++) //循环8位
{
if (crc & 0x80)//最高位为1,应当再次左移后与多项式异或
{
left_and_supply(&crc, *p, i);
crc ^= POLY_8;
}
else
{
left_and_supply(&crc, *p, i);
}
}
}
uint8_t tem = 0x00;//补8个0
p = &tem;
for (i = 0; i < 8; i++) //循环8位
{
if (crc & 0x80)//最高位为1,应当再次左移后与多项式异或
{
left_and_supply(&crc, *p, i);
crc ^= POLY_8;
}
else //否则直接左移
{
left_and_supply(&crc, *p, i);
}
}
*((uint8_t*)pResult) = crc;
}
当然,那个函数可以直接写进去
得到最终代码
/**
* @brief CRC-8校验
*
* @param pStart 校验数据起始位置
* @param count 校验数据长度
* @param pResult 校验码保存位置
*/
void CRC_8(const void* pStart, size_t count, void* pResult);
void CRC_8(const void* pStart, size_t count, void* pResult)
{
uint8_t* pEnd = (uint8_t*)pStart + count - 1;//数据结束位置
uint8_t* p = (uint8_t*)pStart;
uint8_t crc = *p;
int i;
for (; p < pEnd; )
{
p++;
for (i = 0; i < 8; i++)//循环8位
{
if (crc & 0x80)//最高位为1,应当再次左移后与多项式异或
{
crc <<= 1;
if (*p & (0x80 >> i))
crc |= 0x01;
crc ^= POLY_8;
}
else
{
crc <<= 1;
if (*p & (0x80 >> i))
crc |= 0x01;
}
}
}
uint8_t tem = 0x00;//补8个0
p = &tem;
for (i = 0; i < 8; i++)//循环8位
{
if (crc & 0x80)//最高位为1,应当再次左移后与多项式异或
{
crc <<= 1;
if (*p & (0x80 >> i))
crc |= 0x01;
crc ^= POLY_8;
}
else//否则直接左移
{
crc <<= 1;
if (*p & (0x80 >> i))
crc |= 0x01;
}
}
*((uint8_t*)pResult) = crc;
}
其它
谁能解释一下大佬的代码是怎么实现的,真看不懂
https://blog.youkuaiyun.com/u013073067/article/details/86621770
直接左移是补0呀……
#define POLY_8 0x07 //0000 0111
void bigCRC_8(const void* pStart, size_t count, void* pResult)
{
uint8_t crc = 0x00; //初始值
uint8_t* p = (uint8_t*)pStart;
uint8_t* pEnd = (uint8_t*)pStart + count - 1;
int i;
for (; p<=pEnd; p++)
{
crc ^= *p; //与crc初始值异或
for (i = 0; i < 8; i++) //循环8位
{
if (crc & 0x80) //左移移出的位为1,左移后与多项式异或
{
crc <<= 1;
crc ^= POLY_8;
}
else //否则直接左移
{
crc <<= 1;
}
}
}
*((uint8_t*)pResult) = crc;
}
?????