奇偶校验
如二进制表示为0001 1010。
采用奇校验,则在数据后补上个0,数据变为0001 1010 0,数据中1的个数为奇数个(3个)
左移
采用偶校验,则在数据后补上个1,数据变为0001 1010 1,数据中1的个数为偶数个(4个)
左移+1
接收方通过计算数据中1个数是否满足奇偶性来确定数据是否有错
累加和校验
我们要传输的信息为: 1、2、3
加上校验和后的数据包:1、2、3、6
CRC 算法(模二计算)
CRC 算法的基本思想是将传输的数据当做一个位数很长的数。将这个数除以另一个数。得到的余数作为校验数据附加到原数据后面。
模二计算本质上就是异或运算,相同的位为0,不同的位为1,也就是不考虑进位、错位的二进制加减法运算,例如:10011011 + 11001010 = 01010001.
接收方接收此数据后,再做除数运算,余数应该为0。
1.宽度(Width): 指CRC校验码的宽度,同时也是指多项式的宽度。
crc16的width是16,crc32的宽度是32
2.多项式(Poly):指CRC校验的多项式的二进制码去掉最高位。
crc8的Poly:gx=x8+x2+x1+1,二进制码100000111,去掉最高位所以POLY这个参数为:0x07
3.初始值(Init),是指CRC的寄存器的初始值.
4.输入值反转(RefIN):是指需要校验的数据(输入值)二进制位数相反。
输入值为:10101100,则实际进行校验的值为00110101
5.输出值反转(RefOut):指输出的校验码二进制位进行反转。
输出值为:10101100,则实际输出值为00110101
6.结果异或值(XorOut): 指运算出的校验码与结果异或值异或之后,最终最为校验码。
XorOut为0xff,计算的校验码为0x17,则输出校验码为:0xff^0x17
- 规定:生成多项式对应的二进制位数 比 CRC校验码的宽度 多一位,
CRC校验的流程
(1)选定一个标准除数(二进制数据)
(2)在要发送的数据后面加上冗余校验码的宽度位0,然后将这个新数 以模2除法的方式除以上面这个标准除数,所得到的余数也就是该数据的CRC校验码
(注:余数必须比除数少且只少一位,不够就补0)
(3)将这个校验码附在 被除数 后面,构成新的数据,发送给接收端。
(4)接收端将接收到的数据 除以标准除数,如果余数为0则认为数据正确
1. 只有当位串的最高位为1,我们才将它与poly做XOR运算,否则我们只是将位串左移一位。
2. 异或运算的结果实质上是被操作位串与poly位长-1的各位进行运算的结果,因为最高位总为0。
因为除数和被除数第一位必定是1 异或之后就是0
代码
#define POLY 0x1021
/**
* @param: addr: 存放数据的数组地址
* lenth: 数组长度
* crc: crc初始化的值
*/
uint16_t crc16(unsigned char *addr, int lenth, uint16_t crc)
{
int i;
for (; lenth> 0; lenth--) // 数组有多少字节进行多少次计算
{
crc = crc ^ (*addr++ << 8); //先算第一个字节
for (i = 0; i < 8; i++)
{
if (crc & 0x8000)
crc = (crc << 1) ^ POLY;
else
crc <<= 1;
}
crc &= 0xFFFF; // 确保出来的CRC是16位,多余的清零
}
return crc;
常见crc表