CRC12 ,16 ,32校验方法
VB.NET语言版
1、CRC-16
CRC-16码由两个字节构成,在开始时CRC寄存器的每一位都预置为1,然后把CRC寄存器与8-bit的数据进行异或,之后对CRC寄存器从高到低进行移位,在最高位(MSB)的位置补零,而最低位(LSB,移位后已经被移出CRC寄存器)如果为1,则把寄存器与预定义的多项式码进行异或,否则如果 LSB为零,则无需进行异或。重复上述的由高至低的移位8次,第一个8-bit数据处理完毕,用此时CRC寄存器的值与下一个8-bit数据异或并进行如前一个数据似的8次移位。所有的字符处理完成后CRC寄存器内的值即为最终的CRC值。
校验原理:
1.设置CRC寄存器,并给其赋值FFFF(hex)。
2.将数据的第一个8-bit字符与16位CRC寄存器的低8位进行异或,并把结果存入CRC寄存器。
3.CRC寄存器向右移一位,MSB补零,移出并检查LSB。
4.如果LSB为0,重复第三步;若LSB为1,CRC寄存器与多项式码相异或。
5.重复第3与第4步直到8次移位全部完成。此时一个8-bit数据处理完毕。
6.重复第2至第5步直到所有数据全部处理完成。
7.最终CRC寄存器的内容即为CRC值。
实现方法:
Function CRC16(data() As Byte) As String
Dim CRC16Lo As Byte, CRC16Hi As Byte ’CRC寄存器
Dim CL As Byte, CH As Byte ’多项式码&HA001
Dim SaveHi As Byte, SaveLo As Byte
Dim I As Integer
Dim Flag As Integer
CRC16Lo = &HFF
CRC16Hi = &HFF
CL = &H1
CH = &HA0
For I = 0 To Ubound(data)
CRC16Lo = CRC16Lo Xor data(I) ’每一个数据与CRC寄存器进行异或
For Flag = 0 To 7
SaveHi = CRC16Hi
SaveLo = CRC16Lo
CRC16Hi = CRC16Hi \\ 2 ’高位右移一位
CRC16Lo = CRC16Lo \\ 2 ’低位右移一位
If ((SaveHi And &H1) = &H1) Then ’如果高位字节最后一位为1
CRC16Lo = CRC16Lo Or &H80 ’则低位字节右移后前面补1
End If ’否则自动补0
If ((SaveLo And &H1) = &H1) Then ’如果LSB为1,则与多项式码进行异或
CRC16Hi = CRC16Hi Xor CH
CRC16Lo = CRC16Lo Xor CL
End If
Next Flag
Next I
Dim ReturnData(1) As Byte
ReturnData(0) = CRC16Hi ’CRC高位
ReturnData(1) = CRC16Lo ’CRC低位
CRC16 = ReturnData
End Function
C语言版本的
print?//
// CRC16码表
static WORD const wCRC16Table[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040};
//
// CRC16码表
static WORD const wCRC16Table[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040};
然后在文件中加入下列函数:
view plaincopy to clipboardprint?//
// 函数功能: CRC16效验
// 输入参数: pDataIn: 数据地址
// iLenIn: 数据长度
// 输出参数: pCRCOut: 2字节校验值
void CCRCDlg::CRC16(const CHAR* pDataIn, int iLenIn, WORD* pCRCOut)
{
WORD wResult = 0;
WORD wTableNo = 0;
for(int i = 0; i < iLenIn; i++)
{
wTableNo = ((wResult & 0xff) ^ (pDataIn[i] & 0xff));
wResult = ((wResult >> 8) & 0xff) ^ wCRC16Table[wTableNo];
}
*pCRCOut = wResult;
}
//
// 函数功能: CRC16效验
// 输入参数: pDataIn: 数据地址
// iLenIn: 数据长度
// 输出参数: pCRCOut: 2字节校验值
void CCRCDlg::CRC16(const CHAR* pDataIn, int iLenIn, WORD* pCRCOut)
{
WORD wResult = 0;
WORD wTableNo = 0;
for(int i = 0; i < iLenIn; i++)
{
wTableNo = ((wResult & 0xff) ^ (pDataIn[i] & 0xff));
wResult = ((wResult >> 8) & 0xff) ^ wCRC16Table[wTableNo];
}
*pCRCOut = wResult;
}
二.CRC16(MODBUS)
view plaincopy to clipboardprint?//
// CRC MODBUS 效验
// 输入参数: pDataIn: 数据地址
// iLenIn: 数据长度
// 输出参数: pCRCOut: 2字节校验值
void CCRCDlg::CheckCRCModBus(const CHAR* pDataIn, int iLenIn, WORD* pCRCOut)
{
WORD wHi = 0;
WORD wLo = 0;
WORD wCRC;
wCRC = 0xFFFF;
for (int i = 0; i < iLenIn; i++)
{
wCRC = CalcCRCModBus(*pDataIn, wCRC);
pDataIn++;
}
wHi = wCRC / 256;
wLo = wCRC % 256;
wCRC = (wHi << 8) | wLo;
*pCRCOut = wCRC;
}
WORD CCRCDlg::CalcCRCModBus(CHAR cDataIn, WORD wCRCIn)
{
WORD wCheck = 0;
wCRCIn = wCRCIn ^ cDataIn;
for(int i = 0; i < 8; i++)
{
wCheck = wCRCIn & 1;
wCRCIn = wCRCIn >> 1;
wCRCIn = wCRCIn & 0x7fff;
if(wCheck == 1)
{
wCRCIn = wCRCIn ^ 0xa001;
}
wCRCIn = wCRCIn & 0xffff;
}
return wCRCIn;
}
//
// CRC MODBUS 效验
// 输入参数: pDataIn: 数据地址
// iLenIn: 数据长度
// 输出参数: pCRCOut: 2字节校验值
void CCRCDlg::CheckCRCModBus(const CHAR* pDataIn, int iLenIn, WORD* pCRCOut)
{
WORD wHi = 0;
WORD wLo = 0;
WORD wCRC;
wCRC = 0xFFFF;
for (int i = 0; i < iLenIn; i++)
{
wCRC = CalcCRCModBus(*pDataIn, wCRC);
pDataIn++;
}
wHi = wCRC / 256;
wLo = wCRC % 256;
wCRC = (wHi << 8) | wLo;
*pCRCOut = wCRC;
}
WORD CCRCDlg::CalcCRCModBus(CHAR cDataIn, WORD wCRCIn)
{
WORD wCheck = 0;
wCRCIn = wCRCIn ^ cDataIn;
for(int i = 0; i < 8; i++)
{
wCheck = wCRCIn & 1;
wCRCIn = wCRCIn >> 1;
wCRCIn = wCRCIn & 0x7fff;
if(wCheck == 1)
{
wCRCIn = wCRCIn ^ 0xa001;
}
wCRCIn = wCRCIn & 0xffff;
}
return wCRCIn;
}
三.CRC16(CCITT的0XFFFF)
view plaincopy to clipboardprint?//
// 函数功能: CRC16效验(CCITT的0XFFFF效验)
// 输入参数: pDataIn: 数据地址
// iLenIn: 数据长度
// 输出参数: pCRCOut: 2字节校验值
void CCRCDlg::CRCCCITT(const CHAR* pDataIn, int iLenIn, WORD* pCRCOut)
{
WORD wTemp = 0;
WORD wCRC = 0xffff;
for(int i = 0; i < iLenIn; i++)
{
for(int j = 0; j < 8; j++)
{
wTemp = ((pDataIn[i] << j) & 0x80 ) ^ ((wCRC & 0x8000) >> 8);
wCRC <<= 1;
if(wTemp != 0)
{
wCRC ^= 0x1021;
}
}
}
*pCRCOut = wCRC;
}
2、32位操作方法
'VB源代码
'注意:本代码仅运行于VB 2005,不适用VB 2003
Public Class ClsoCRC
Public Shared ReadOnly Table As UInteger()
Shared Sub New()
ReDim Table(256)
For i As UInteger = 0 To 255
Dim r As UInteger = i
For j As Integer = 0 To 7
If (r And 1) <> 0 Then
r = (r >> 1) Xor 3988292384
Else
r >>= 1
End If
Next
Table(i) = r
Next
End Sub
Private _value As UInteger = UInteger.MaxValue
''' <summary>初始化类,重新计算CRC前请先调用本过程。</summary>
Public Sub Init()
_value = UInt32.MaxValue
End Sub
''' <summary>更新并计算单个字节。(追加方式)</summary>
''' <param name="b">数据字节。</param>
Public Sub UpdateByte(ByVal b As Byte)
_value = Table(UInt32toByte(_value) Xor b) Xor (_value >> 8)
End Sub
''' <summary>更新类并开始计算CRC。</summary>
''' <param name="data">需要计算的数据组。</param>
''' <param name="offset">偏移,一般设为0。</param>
''' <param name="size">大小,一般设为数据组的Length。</param>
Public Sub Update(ByVal data As Byte(), ByVal offset As UInt32, ByVal size As UInt32)
For i As UInteger = 0 To size - 1
_value = Table(UInt32toByte(_value) Xor data(offset + i)) Xor (_value >> 8)
Next
End Sub
''' <summary>获取CRC数据。</summary>
Public Function GetDigest() As UInt32
Return _value Xor UInt32.MaxValue
End Function
''' <summary>计算并获取CRC数据。(利用静态实例化实现)</summary>
''' <param name="data">需要计算的数据组。</param>
''' <param name="offset">偏移,一般设为0。</param>
''' <param name="size">大小,一般设为数据组的Length。</param>
Public Shared Function CalculateDigest(ByVal data As Byte(), ByVal offset As UInt32, ByVal size As UInt32) As UInt32
Dim crc As New ClsoCRC
'crc.Init()
crc.Update(data, offset, size)
Return crc.GetDigest
End Function
''' <summary>校验摘要</summary>
''' <param name="digest">摘要</param>
''' <param name="data">数据组</param>
''' <param name="offset">偏移</param>
''' <param name="size">大小</param>
Private Shared Function VerifyDigest(ByVal digest As UInt32, ByVal data As Byte(), ByVal offset As UInt32, ByVal size As UInt32) As Boolean
Return CalculateDigest(data, offset, size) = digest
End Function
''' <summary>返回BYTE (CLE添加)</summary>
Private Shared Function UInt32toByte(ByVal UInt32Value As UInteger) As Byte
Return UInt32Value Mod 256
End Function
End Class