数据校验概念
数据在传输的过程中,会受到各种干扰的影响,如脉冲干扰,随机噪声干扰和人为干扰等,这会使数据产生差错。为了能够控制传输过程的差错,通信系统必须采用有效的检错方案。因此产生了数据校验。
数据校验是为保证数据的完整性进行的一种验证操作。通常用一种指定的算法对原始数据计算出的一个校验值,接收方用同样的算法计算一次校验值,如果两次计算得到的检验值相同,则说明数据是完整的。
数据校验常见种类
最简单的检验
实现方法:最简单的校验就是把原始数据和待比较数据直接进行比较,看是否完全一样这种方法是最安全最准确的。同时也是效率最低的。
应用例子:龙珠cpu在线调试工具bbug.exe。它和龙珠cpu间通讯时,bbug发送一个字节cpu返回收到的字节,bbug确认是刚才发送字节后才继续发送下一个字节的。
奇偶校验
实现方法:根据被传输的一组二进制代码的数位中“1”的个数是奇数或偶数来进行校验。采用奇数的称为奇校验,反之,称为偶校验。采用何种校验是事先规定好的。通常专门设置一个奇偶校验位,用它使这组代码中“1”的个数为奇数或偶数。若用奇校验,则当接收端收到这组代码时,校验“1”的个数是否为奇数,从而确定传输代码的正确性。
应用例子:单片机串口通讯有一模式就是8位数据通讯,另加第9位用于放校验值。
BCC异或校验法(Block Check Character)
实现方法:将数据按字节与校验码寄存器(寄存器初始值通常0))进行异或计数并存入校验码寄存器。
应用例子:IC卡接口通讯、很多单片机系统的串口通讯都使用。
CRC循环冗余校验(Cyclic Redundancy Check)
实现方法:这是利用除法(这里除法是模2除法也就是异或运算)及余数的原理来进行错误检测的.将接收到的码组进行除法运算,如果除尽,则说明传输无误;如果未除尽,则表明传输出现差错。CRC校验具还有自动纠错能力。CRC检验主要有计算法和查表法两种方法。
适用范围:CRC-12码通常用来传送6-bit字符串; CRC-16及CRC-CCITT码则用是来传送8-bit字符; CRC-32:硬盘数据,网络传输等。
应用例子:rar,以太网卡芯片、MPEG解码芯片中。
MD5校验和数字签名
实现方法:主要有MD5和DES算法。
适用范围:数据比较大或要求比较高的场合。如MD5用于大量数据、文件校验,des用于保密数据的校验(数字签名)等等。
应用例子:文件校验、银行系统的交易数据。
累加和检验(checksum)
实现方法:一组数据项的和。对溢出部分进行处理等到一个校验数值(8位,16位等)。累加和溢出各种方法有所差别。详见代码。
应用例子:数据通信领域等。
LRC校验(纵向冗余校验)(Longitudinal Redundancy Check)是一种从纵向通道上的特定比特串产生校验比特的错误检测方法。
实现方法:将每个字节数据求和结果与256求余,再按位取反加 1(256 - 余数)后即得到校验码
应用例子:在工业领域Modbus协议Ascii模式采用该算法
源码链接
BCC校验(异或校验),LRC校验(纵向冗余校验),累加和校验(CheckSum) 源码 链接:https://blog.csdn.net/weixin_46672094/article/details/117135918?spm=1001.2014.3001.5501
CRC校验 (计算方式) 通用源码(兼容CRC4/5/6/7/8/16/32/自定义) 链接:https://blog.csdn.net/weixin_46672094/article/details/117136044?spm=1001.2014.3001.5501
CRC校验 (查表方式) 通用源码(兼容CRC4/5/6/7/8/16/32/自定义),包含 CRC表 计算代码 链接:https://blog.csdn.net/weixin_46672094/article/details/117136086?spm=1001.2014.3001.5501
CRC计算原理:被校验的数据 除以 多项式,得到的余数就是CRC数值。不过这里的除法是模2除法,也就是异或。多项式是通信中双方约定数,可以自己定义,不过目前有各个领域定义好的,可直接用。
以下以 数据 11001000(0xC8) 为例,演算CRC计算过程!
单个数据CRC计算过程:
数 据:11001000(0xC8)
多项式:10011(x4 + x + 1)(4位多项式) 多项式最高位总是1.
11001000 0000 //数据11001000(0xC8),4位多项式所以末尾补4个零
10011 //多项式
————————————————
1010000 0000 //按位异或
10011
————————————————
11100 0000 //最高位是1才能除
10011
————————————————
1111 0000
1001 1
————————————————
110 1000
100 11
————————————————
10 0100
10 011
————————————————
0010 //余数 就是CRC值
通信中多数据CRC计算过程:其实就是把单数据的CRC最为下个数据CRC计算的初值。下面还可以单个数据为例,多了CRC初值和一些数据的处理。
CRC5_EPC算法 逻辑演算过程:
//CRC算法名称 宽度 多项式 初始值 结果异或值 输入反转 输出反转
{"CRC5_EPC", 5, 0x09, 0x09, 0x00, E_FALSE, E_FALSE},
数据0 输入不反转 得到 数据1 : 0001 0011
数据1高位 与 CRC初始值异或 得到 数据2 : 0101 1011
0001 0011
0100 1 //初值与数据高位进行异或
————————————————
0101 1011
数据2 补CRC宽度数量的零 得到 数据3 : 0101 1011 00000
完整多项式: 1 01001 //高位异或始终为0,在计算可省了,下面为了展示原理过程加上的 1
数据3 与多项式模2除法(异或)计算 :
01011011 00000
101001
————————————————
1001 00000
1010 01
————————————————
11 01000
10 1001
————————————————
1 11010
1 01001
————————————————
10011
数据3 与多项式计算后 得到 余数0 : 1 0011
余数0 输出不反转 得到 余数1 : 1 0011
余数1 与结果异或值 异或 得到 CRC值 : 0001 0011 => 0x13
1 0011
0000 0000 //与结果异或值 直接异或
————————————————
0001 0011
CRC5_USB算法 逻辑演算过程:
//CRC算法名称 宽度 多项式 初始值 结果异或值 输入反转 输出反转
{"CRC5_USB", 5, 0x05, 0x1F, 0x1F, E_TRUE, E_TRUE},
数据0 输入反转 得到 数据1 : 1100 1000
数据1 与 初始值异或 得到 数据2 : 0011 0000
1100 1000
1111 1 //初值与数据高位进行异或
————————————————
0011 0000
数据2 补CRC宽度数量的零 得到 数据3 : 0011 0000 00000
完整多项式: 1 00101 //高位异或始终为0,在计算可省了,下面为了展示原理过程加上的 1
数据3 与多项式模2除法(异或)计算 :
00110000 00000
100101
————————————————
10101 00000
10010 1
————————————————
111 10000
100 101
————————————————
11 00100
10 0101
————————————————
1 01110
1 00101
————————————————
01011
数据3 与多项式计算后 得到 余数0 : 0 1011
余数0 输出要反转 得到 余数1 : 1 1010 //按位数宽度反转
余数1 与结果异或值 异或 得到 CRC值 : 0000 0101 => 0x05
1 1010
0001 1111 //与结果异或值 直接异或
————————————————
0000 0101
CRC5_EPC算法 程序计算过程:
//CRC算法名称 宽度 多项式 初始值 结果异或值 输入反转 输出反转
{"CRC5_EPC", 5, 0x09, 0x09, 0x00, E_FALSE, E_FALSE},
data = 00010011(0x13)
with = 5;
poly = 00000000 00000000 00000000 00001001
crc = 00000000 00000000 00000000 00001001
xorout = 00000000 00000000 00000000 00000000
refin = E_FALSE
refout = E_FALSE
crc = 00000000 00000000 00000000 01001000 //宽度小于8,右移8-5
poly = 00000000 00000000 00000000 01001000 //宽度小于8,右移8-5
{
data = 00010011 //不移动
crc = 00000000 00000000 00000000 01001000
—————————————————————————————————————————————
crc = 00000000 00000000 00000000 01011011 //0,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00000000 10110110 //1,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00000001 01101100
poly = 00000000 00000000 00000000 01001000
—————————————————————————————————————————————
crc = 00000000 00000000 00000001 00100100 //2,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00000010 01001000 //3,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00000100 10010000 //4,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00001001 00100000
poly = 00000000 00000000 00000000 01001000
—————————————————————————————————————————————
crc = 00000000 00000000 00001001 01101000 //5,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00010010 11010000 //6,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00100101 10100000
poly = 00000000 00000000 00000000 01001000
—————————————————————————————————————————————
crc = 00000000 00000000 00100101 11101000 //7,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 01001011 11010000
poly = 00000000 00000000 00000000 01001000
—————————————————————————————————————————————
crc = 00000000 00000000 01001011 10011000
}
crc = 00000000 00000000 00001001 01110011 //宽度小于8,右移8-5
11111 //有效位 5
—————————————————————————————————————————————
crc = 00000000 00000000 00000000 00010011
CRC5_USB算法 程序计算过程:
//CRC算法名称 宽度 多项式 初始值 结果异或值 输入反转 输出反转
{"CRC5_USB", 5, 0x05, 0x1F, 0x1F, E_TRUE, E_TRUE},
data = 00010011(0x13)
with = 5;
poly = 00000000 00000000 00000000 00000101
crc = 00000000 00000000 00000000 00011111
xorout = 00000000 00000000 00000000 00011111
refin = E_TRUE
refout = E_TRUE
crc = 00000000 00000000 00000000 11111000 //宽度小于8,右移8-5
poly = 00000000 00000000 00000000 00101000 //宽度小于8,右移8-5
{
data = 11001000 //输入反转 8位
data = 11001000 //不移动
crc = 00000000 00000000 00000000 11111000
—————————————————————————————————————————————
crc = 00000000 00000000 00000000 00110000 //0,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00000000 01100000 //1,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00000000 11000000 //2,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00000001 10000000
poly = 00000000 00000000 00000000 00101000
—————————————————————————————————————————————
crc = 00000000 00000000 00000001 10101000 //3,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00000011 01010000
poly = 00000000 00000000 00000000 00101000
—————————————————————————————————————————————
crc = 00000000 00000000 00000011 01111000 //4,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00000110 11110000 //5,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00001101 11100000
poly = 00000000 00000000 00000000 00101000
—————————————————————————————————————————————
crc = 00000000 00000000 00001101 11001000 //6,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00011011 10010000
poly = 00000000 00000000 00000000 00101000
—————————————————————————————————————————————
crc = 00000000 00000000 00011011 10111000 //7,crc & 0x80; 0-右移,1-右移后与多项式异或
crc = 00000000 00000000 00110111 01110000
poly = 00000000 00000000 00000000 00101000
—————————————————————————————————————————————
crc = 00000000 00000000 00110111 01011000
}
crc = 00000000 00000000 00000110 111 01011 //宽度小于8,右移8-5
crc = 00000000 00000000 00000110 111 11010 //输出反转 5位
xorout = 00000000 00000000 00000000 000 11111
—————————————————————————————————————————————
crc = 00000000 00000000 00000110 111 00101
11111 //有效位 5
—————————————————————————————————————————————
crc = 00000000 00000000 00000000 000 00101