unsigned short crc_dsp(unsigned short reg, unsigned char data_crc)
//reg为crc寄存器, data_crc为将要处理的8bit数据流
{
unsigned short msb; //crc寄存器将移出的最高1bit
unsigned short data;
unsigned short gx = 0x8005, i = 0; //i为左移次数, gx为生成多项式
data = (unsigned short)data_crc;
data = data << 8;
reg = reg ^ data;
do
{
msb = reg & 0x8000;
reg = reg << 1;
if(msb == 0x8000)
{
reg = reg ^ gx;
}
i++;
}
while(i < 8);
return (reg);
}
串口通讯中,发送的是字符串或者说是字节数组。接收或发送的总字节数已知,一般最后一个或两个字节为CRC校验字节。你可以做一个子函数,以该字节数组作为函数变量,返回值为CRC校验字节。对于发送数据,将返回的校验字节放在发送字节的最后,然后发送即可;对于接收数据校验,则将子函数返回的校验字节与接收到的校验字节比较,相等即校验通过,不相等则校验失败。
CRC校验码的获取有两种方法,可以用查表法,也可以用多项式法计算。
using System;
using SystemCollectionsGeneric;
using SystemLinq;
using SystemText;
namespace ConvertToCRC16
{
public static class CRC16Util
{
// CRC高位字节表
private static readonly byte[] m_CRCHighOrderByteTable = new byte[]
{
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};
// CRC低位字节表
private static readonly byte[] m_CRCLowOrderByteTable = new byte[]
{
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};
/// <summary>
/// 获得CRC16效验码
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
public static void CalculateCrc16(byte[] buffer, out byte crcHighOrderByte, out byte crcLowOrderByte)
{
// CRC高位字节/低位字节
crcHighOrderByte = crcLowOrderByte = 0xff;
for (int i = 0; i < bufferLength; i++)
{
// 计算CRC查找索引
int crcIndex = crcHighOrderByte ^ buffer[i];
crcHighOrderByte = (byte)(crcLowOrderByte ^ m_CRCHighOrderByteTable[crcIndex]);
crcLowOrderByte = (byte)m_CRCLowOrderByteTable[crcIndex];
}
}
}
}
// 工具函数如上
CRC循环校验是什么????????
CRC是什么东西呢?其实我们大家都不应该会对它陌生,回忆一下?你用过RAR和ZIP等压缩软件吗?它们是不是常常会给你一个恼人的“CRC校验错误”信息呢?我想你应该明白了吧,CRC就是块数据的计算值,它的全称是“Cyclic
Redundancy
Check”,中文名是“循环冗余码”,“CRC校验”就是“循环冗余校验”。(哇,真拗口,希望大家不要当我是唐僧,呵呵。^_^)
CRC有什么用呢?它的应用范围很广泛,最常见的就是在网络传输中进行信息的校对。其实我们大可以把它应用到软件保护中去,因为它的计算是非常非常非常严格的。严格到什么程度呢?你的程序只要被改动了一个字节(甚至只是大小写的改动),它的值就会跟原来的不同。Hoho,是不是很厉害呢?所以只要给你的“原”程序计算好CRC值,储存在某个地方,然后在程序中随机地再对文件进行CRC校验,接着跟第一次生成并保存好的CRC值进行比较,如果相等的话就说明你的程序没有被修改/破解过,如果不等的话,那么很可能你的程序遭到了病毒的感染,或者被Cracker用16进制工具暴力破解过了。
参考资料:
'Text1Text 输入数据
'Text2Text 输出数据
Dim ReturnData(1) As Byte
Private Sub Command1_Click()
Dim CRC(2) As Byte
Dim d(6) As Byte '待传输数据
ReDim data(7) As Byte
For i = 0 To 5
data(i) = "&h" + Mid(Text1Text, 2 i + 1, 2)
DebugPrint data(i)
Next i
Call CRC16(data, UBound(data) - 2, data(6), data(7)) '调用CRC16计算函数
' CRC(0)为高位
' CRC(1)为低位
End Sub
Function CRC16(data() As Byte, i As Integer, ByRef ReturnDatalo As Byte, ByRef ReturnDatahi 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 Flag As Integer
CRC16Lo = &HFF
CRC16Hi = &HFF
CL = &H1
CH = &HA0
For i = 0 To UBound(data) - 2
CRC16Lo = CRC16Lo Xor data(i) '每一个数据与CRC寄存器进行异或
For Flag = 0 To 9
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
ReturnDatahi = CRC16Hi 'CRC高位
ReturnDatalo = CRC16Lo 'CRC低位
DebugPrint Hex(CRC16Lo), Hex(CRC16Hi)
Text2Text = Text1Text & Hex(CRC16Lo) & Hex(CRC16Hi)
End Function
下面我们以CRC-16为例来说明任意长度数据流的CRC校验码生成过程。我们采用将数据流分成若干个8bit字符,并由低字节到高字节传送的并行方法来求CRC校验码。具体计算过程为:用一个16bit的寄存器来存放CRC校验值,且设定其初值为0x0000;将数据流的第一个8bit与16bit的CRC寄存器的高字节相异或,并将结果存入CRC寄存器高字节;CRC寄存器左移一位,最低1bit补零,同时检查移出的最高1bit,若移出的最高1bit为0,则继续按上述过程左移,若最高1bit为1,则将CRC寄存器中的值与生成多项式码相异或,结果存入CRC寄存器值;继续左移并重复上述处理方法,直到将8bit数据处理完为止,则此时CRC寄存器中的值就是第一个8bit数据对应的CRC校验码;然后将此时CRC寄存器的值作为初值,用同样的处理方法重复上述步骤来处理下一个8bit数据流,直到将所有的8bit字符都处理完后,此刻CRC寄存器中的值即为整个数据流对应的CRC校验码。
下面示出了其计算过程的流程图:
在用C语言编写CRC校验码的实现程序时我们应该注意,生成多项式 对应的十六进制数为0x18005,由于CRC寄存器左移过程中,移出的最高位为1时与 相异或,所以与16bit的CRC寄存器对应的生成多项式的十六进制数可用0x8005表示。下面给出并行处理8bit数据流的C源程序:
unsigned short crc_dsp(unsigned short reg, unsigned char data_crc)
//reg为crc寄存器, data_crc为将要处理的8bit数据流
{
unsigned short msb; //crc寄存器将移出的最高1bit
unsigned short data;
unsigned short gx = 0x8005, i = 0; //i为左移次数, gx为生成多项式
data = (unsigned short)data_crc;
data = data << 8;
reg = reg ^ data;
do
{
msb = reg & 0x8000;
reg = reg << 1;
if(msb == 0x8000)
{
reg = reg ^ gx;
}
i++;
}
while(i < 8);
return (reg);
}
以上为处理每一个8bit数据流的子程序,在计算整个数据流的CRC校验码时,我们只需将CRC_reg的初值置为0x0000,求第一个8bit的CRC值,之后,即可将上次求得的CRC值和本次将要处理的8bit数据作为函数实参传递给上述子程序的形参进行处理即可,最终返回的reg值便是我们所想得到的整个数据流的CRC校验值。
你就是想要CRC8-CCITT的代码,这个到处都是。
>
以上就是关于求教C语言编写的CRC16的校验程序全部的内容,包括:求教C语言编写的CRC16的校验程序、请教,如何在串口通讯编程中如何加入CRC检验程序、求教 C#语言编写 的CRC16的校验程序 (多项式为:CRC-16/X25 x16+x12+x5+1)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)