CRC校验算法及C#程序实现

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

CRC校验算法及C#程序实现
CRC校验可以运用于传输数据过程中的验证,发送端发送有效数据时,先根据有效数据和生成多项式(比如CCITT标准的多项式是X16+X12+X5+1)计算出CRC校验码,把CRC校验码加到有效数据后面一起发送;当接收数据时,取出前面有效数据部分,用同样生成多项式计算出CRC校验码,然后取出接收数据后面CRC校验码部分,对比两个校验码是否相同。

如果相同,认为接收到的数据与发送的数据是一致的,传输正确;如果不同,认为传输数据出错。

CRC(循环冗余校验)算法主要是一个计算除法的过程。

算法有两个输入值,第一个是输入的信号,这通常是一个很长的数据,作为被除数。

第二个是一个与具体的CRC算法相关的多项式,称为生成多项式,用作除数。

基本的计算过程是,两者作模2除法(本质上是对应位做异或运算),余数就是CRC校验码的结果。

I、基本算法(人工笔算):
以CRC16-CCITT为例进行说明,它的生成多项式是X16+X12+X5+1,CRC校验码为16位,生成多项式17位。

假如数据流为4字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0];
数据流左移16位,相当于扩大256×256倍,再除以生成多项式0x11021,做不借位的除法运算(相当于按位异或),所得的余数就是CRC校验码。

发送时的数据流为6字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0]、CRC[1]、CRC[0];
II、计算机算法1(比特型算法):
1)将扩大后的数据流(6字节)高16位(BYTE[3]、BYTE[2])放入一个长度为16的寄存器;
2)如果寄存器的首位为1,将寄存器左移1位(寄存器的最低位从下一个字节获得),再与生成多项式的简记式异或;
否则仅将寄存器左移1位(寄存器的最低位从下一个字节获得);
3)重复第2步,直到数据流(6字节)全部移入寄存器;
4)寄存器中的值则为CRC校验码CRC[1]、CRC[0]。

III、计算机算法2(字节型算法):
字节型算法的一般描述为:本字节的CRC码,等于上一字节CRC 码的低8位左移8位,与上一字节CRC右移8位同本字节异或后所得的CRC码异或。

字节型算法如下:
1)CRC寄存器组初始化为全"0"(0x0000)。

(注意:CRC寄存器组初始化全为1时,最后CRC应取反。


2)CRC寄存器组向左移8位,并保存到CRC寄存器组。

3)原CRC寄存器组高8位(右移8位)与数据字节进行异或运算,得出一个指向值表的索引。

4)索引所指的表值与CRC寄存器组做异或运算。

5)数据指针加1,如果数据没有全部处理完,则重复步骤2)。

6)得出CRC。

简单例子
下面用一个简单的例子来说明CRC算法的计算过程。

输入信号是101111,生成多项式是1001(对应数学表达式为X3+1)。

被除数后面需要补充3个0。

即101111000对1001做模2除法运算,得到一个3位的余数010,这个就是CRC校验码。

在上例中,余数为010。

将余数附加到输入信号后面,即发送数据为101111010,取接收端接收到的数据的前六位对1001做模2除法运算,看看得到的CRC校验码是不是等于接收数据的后三位。

如果是,传输正确,如果不是,传输错误。

4 C#程序代码
这是采用比特型算法编写的程序。

以下CRCVerifyLHY类中的GetCRC方法就是用来计算CRC校验码的,在Main函数中byte数组用来存放要传输的数据(注意:前面两个字节都初始为0,用来存放CRC校验码结果,真正要传输的数据从第三个字节开始)。

这里简单地只传输一个字节的数据,如下面的157,可以先人工用笔算出一个CRC校验码,然后看程序的输出是否
和人工算的一致,经本人验证,此算法程序应该是正确的。

using System;
using System.Collections.Generic;
using System.Text;
namespace CRCVerify
{
class CRCVerifyLHY
{
//dataStream数组中的dataStream[0]和dataStream[1]为CRC 校验码的初始值,即0x0000。

其他的数组元素即为要传输的信息码,cRC_16为生成多项式的简记式
//以CRC16-CCITT为例进行说明,CRC校验码为16位,生成多项式17位,其简记式实际是0x11021,
//但是生成多项式的最高位固定为1,故在简记式中忽略最高位1了,CRC16-CCITT的简记式就可以写为0x1021
public static ushort GetCRC(byte[] dataStream, ushort cRC_16)
{
ushort cRC_temp = Convert.T oUInt16((dataStream[dataStream.Length - 1] << 8) + dataStream[dataStream.Length - 2]);
int totalBit = (dataStream.Length - 2) * 8;
for (int i = totalBit - 1; i >= 0; i--)
{
ushort a = Convert.ToUInt16(i / 8);
ushort b = Convert.ToUInt16(i % 8);
ushort nextBit = Convert.T oUInt16((dataStream[a] >> b) & 0x01);
if (cRC_temp >= 32768)
{
cRC_temp = Convert.ToUInt16(((cRC_temp - 32768) << 1) + nextBit);
cRC_temp = Convert.ToUInt16(cRC_temp ^ cRC_16);
}
else
{
cRC_temp = Convert.ToUInt16((cRC_temp << 1) + nextBit);
}
}
return cRC_temp;
}
}
class Program
{
static void Main(string[] args)
{
byte[] array = new byte[] { 0, 0, 157 };
ushort cRC_Result = CRCVerifyLHY.GetCRC(array, 0x1021);
Console.WriteLine(cRC_Result);
Console.ReadKey();
}
}
}
建议使用以下:
using System;
namespace USTC
{
/// <summary>
/// 消息CRC校验算法
/// </summary>
public class CRC
{
//private int key = 0x11021H;
public CRC()
{
}
public static int GetKey(byte[] data)
{
int count = data.Length;
byte[] buf = new byte[data.Length + 2];
data.CopyTo(buf, 0);
int ptr = 0;
int i = 0;
int crc = 0;
byte crc1, crc2, crc3;
crc1 = buf[ptr++];
crc2 = buf[ptr++];
buf[count] = 0;
buf[count + 1] = 0;
while (--count >= 0)
{
crc3 = buf[ptr++];
for (i = 0; i < 8; i++)
{
if (((crc1 & 0x80) >> 7) == 1)//判断crc1高位是否为1 {
crc1 = (byte)(crc1 << 1); //移出高位
if (((crc2 & 0x80) >> 7) == 1)//判断crc2高位是否为1 {
crc1 = (byte)(crc1 | 0x01);//crc1低位由0变1
crc2 = (byte)(crc2 << 1);//crc2移出高位
if (((crc3 & 0x80) >> 7) == 1) //判断crc3高位是否为1 {
crc2 = (byte)(crc2 | 0x01); //crc2低位由0变1
}
crc3 = (byte)(crc3 << 1);//crc3移出高位
crc1 = (byte)(crc1 ^ 0x10);
crc2 = (byte)(crc2 ^ 0x21);
}
else
{
crc1 = (byte)(crc1 << 1); //移出高位
if (((crc2 & 0x80) >> 7) == 1)//判断crc2高位是否为1 {
crc1 = (byte)(crc1 | 0x01);//crc1低位由0变1
}
crc2 = (byte)(crc2 << 1);//crc2移出高位
if (((crc3 & 0x80) >> 7) == 1) //判断crc3高位是否为1 {
crc2 = (byte)(crc2 | 0x01); //crc2低位由0变1
}
crc3 = (byte)(crc3 << 1);//crc3移出高位
}
}
}
crc = (int)((crc1 << 8) + crc2);
return crc;
}
}。

相关文档
最新文档