200分求教以下要求的C# 代码,最后入口要封装成一个。回答的人多了,都符合要求的话 在追加100分。
原意描述:CRC 是先调入一值是全“1”的 16 位寄存器,然后调用一过程将消息中连续的 8 位字
节各当前寄存器中的值进行处理。仅每个字符中的 8Bit 数据对 CRC 有效,起始位和停止位
以及奇偶校验位均无效。
CRC 校验字节的生成步骤如下:
① 装一个 16 位寄存器,所有数位均为 1。
② 取被校验串的一个字节与 16 位寄存器的高位字节进行“异或”运算。运算结果放
入这个 16 位寄存器。
③ 把这个 16 寄存器向右移一位。
④ 若向右(标记位)移出的数位是 1,则生成多项式 1010 0000 0000 0001 和这个寄
存器进行“异或”运算;若向右移出的数位是 0,则返回③。
⑤ 重复③和④,直至移出 8 位。
⑥ 取被校验串的下一个字节
⑦ 重复③~⑥,直至被校验串的所有字节均与 16 位寄存器进行“异或”运算,并移位
8 次。
⑧ 这个 16 位寄存器的内容即 2 字节 CRC 错误校验码。
校验码按照先高字节后低字节的顺序存放。
C++ 代码
C++ 代码如下unsigned long LLHCRC::reflect(unsigned long data, unsigned char nBits)
{
unsigned long reflection = 0x00000000;
unsigned char bit;
/*
/*
* Reflect the data about the center bit.
*/
//for (bit = nBits-1; bit >=0 ; --bit)
for (bit = 0; bit < nBits ; ++bit)
{
/*
* If the LSB bit is set, set the reflection of it.
*/
if (data & 0x01)
{
reflection |= (1 << ((nBits - 1) - bit));
}
data = (data >> 1);
}
return (reflection); }
void LLHCRC::crcInit(void)
{
crc remainder;
int dividend;
unsigned char bit;
/*
* Compute the remainder of each possible dividend.
*/
for (dividend = 0; dividend < 256; ++dividend)
{
/*
* Start with the dividend followed by zeros.
*/
remainder = dividend << (WIDTH - 8);
/*
* Perform modulo-2 division, a bit at a time.
*/
for (bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}
/*
* Store the result into the table.
*/
crcTable[dividend] = remainder;
}
}
unsigned long LLHCRC::crcFast(unsigned char const message[], int nBytes)
{
unsigned char data;
int byte;
if(m_nWorkMode==0)
return crcFastSingle(message,nBytes);
/*
* Divide the message by the polynomial, a byte at a time.
*/
for (byte = 0; byte < nBytes; ++byte)
{
data = REFLECT_DATA(message[byte]) ^ (m_remainder >> (WIDTH - 8));
m_remainder = crcTable[data] ^ (m_remainder << 8);
}
return 0;//用GetCRC()得到最后的CRC值
}///设置工作模式,0-计算完一组数据的CRC后,立即返回CRC值,
///1-可以计算多组数据,生成一个CRC值,调用者必须显示调用GETCRC()函数才能得到CRC
// 莫志勇 2008-8-13,
// 添加LLHCRC的工作模式,兼容原有的无工作模式的状态,
// 原有的LLHCRC只能计算计算一组数据的CRC,计算完毕立即返回CRC值,相当于工作模式0。
void LLHCRC::SetWorkMode(int nWorkMode)
{
m_nWorkMode=nWorkMode;
}
///必须在工作模式1下调用,否则只返回0
//读取一次CRC值后,CRC值自动回复到初始状态。可以再次计算。
unsigned long LLHCRC::GetCRC()
{
if(m_nWorkMode==1)
{
DWORD CRC=m_remainder;
m_remainder=INITIAL_REMAINDER;
return (REFLECT_REMAINDER(CRC) ^ FINAL_XOR_VALUE);
}
else
return 0;
}unsigned long LLHCRC::crcFastSingle(unsigned char const message[], int nBytes)
{
if(m_nWorkMode==1)
return 0; unsigned char data;
int byte;
unsigned long remainder=INITIAL_REMAINDER;
/*
* Divide the message by the polynomial, a byte at a time.
*/
for (byte = 0; byte < nBytes; ++byte)
{
data = REFLECT_DATA(message[byte]) ^ (remainder >> (WIDTH - 8));
remainder = crcTable[data] ^ (remainder << 8);
}
return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE);
}
C++ 算法代码
#define CRC16typedef unsigned short crc; #define CRC_NAME "CRC-16" #define POLYNOMIAL 0x8005 //生成多项式#define INITIAL_REMAINDER 0x0000 //寄存器初始化#define FINAL_XOR_VALUE 0x0000 #define WIDTH (8 * sizeof(crc)) #define TOPBIT (1 << (WIDTH - 1)) #define REFLECT_DATA(X) ((unsigned char) reflect((X), 8)) #define REFLECT_REMAINDER(X) ((crc) reflect((X), WIDTH)) //建立CRC16映射表/********************************************************************* * * 函数名称: crcInit() * * 描述: Populate the partial CRC lookup table. * * 注意: This function must be rerun any time the CRC standard * is changed. If desired,it can be run "offline"" and * the table results stored in an embedded system'ss ROM. * *返回值: 空值. * ********************************************************************/void crcInit(void) { crc remainder; int dividend; unsigned char bit; /* * 计算所有可能的余数. */ for (dividend = 0; dividend < 256; ++dividend) { /* * Start with the dividend followed by zeros. */ remainder = dividend << (WIDTH - 8); /* * 执行模2除法, 每次一位. */ for (bit = 8; bit > 0; --bit) { /* * Try to divide the current data bit. */ if (remainder & TOPBIT) { remainder = (remainder << 1) ^ POLYNOMIAL; } else { remainder = (remainder << 1); } } /* * 储存结果到表中去 */ crcTable[dividend] = remainder; } } /* crcInit() */ //返回值即为所求CRC值/********************************************************************* * * Function: crcFast() * * Description: Compute the CRC of a given message. * * Notes: crcInit() must be called first. * * Returns: The CRC of the message. ********************************************************************/crc crcFast(unsigned char const message[], int nBytes) { crc remainder = INITIAL_REMAINDER; unsigned char data; int byte; /* *使用多项式对消息求校验码,每次一个字节 */ for (byte = 0; byte < nBytes; ++byte) { data = REFLECT_DATA(message[byte]) ^ (remainder >> (WIDTH - 8)); remainder = crcTable[data] ^ (remainder << 8); } /* * 最后剩余的就是CRC */ return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE); } /* crcFast() */
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace Monitoring_On_line.ClassInfo
{
public class CRC16
{
public CRC16()
{
}
private readonly byte[] _auchCRCHi = new byte[]//crc高位表
{
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
} ; private readonly byte[] _auchCRCLo = new byte[]//crc低位表
{
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
} ;
public ushort CalculateCrc16( byte[] buffer )
{
byte crcHi = 0xff; // 高位初始化 byte crcLo = 0xff; // 低位初始化 for ( int i = 0; i < buffer.Length; i++ )
{
int crcIndex = crcHi ^ buffer[ i ]; //查找crc表值 crcHi = (byte)( crcLo ^ _auchCRCHi[crcIndex ] );
crcLo = _auchCRCLo[ crcIndex ] ;
} return (ushort)( crcHi << 8 | crcLo );
} CalculateCrc16返回的是一个ushort类型的值,如果要返回Crc高字节和低字节,可重写CalculateCrc16函数为:
public ushort CalculateCrc16( byte[] buffer, out byte crcHi, out byte crcLo )
{
crcHi = 0xff; // high crc byte initialized
crcLo = 0xff; // low crc byte initialized for ( int i = 0; i < buffer.Length - CRC_LEN; i++ )
{
int crcIndex = crcHi ^ buffer[ i ]; // calculate the crc lookup index crcHi = (byte)( crcLo ^ _auchCRCHi[ crcIndex ] );
crcLo = _auchCRCLo[ crcIndex ] ;
} return (ushort)( crcHi << 8 | crcLo );
}
}
}
调用方式: private void button1_Click(object sender, EventArgs e)
{
byte[] by = new byte[2];
by[0] = Convert.ToByte("79", 16);
by[1] = Convert.ToByte("83", 16);
ClassInfo.CRC16 CRC = new Monitoring_On_line.ClassInfo.CRC16();
MessageBox.Show(CRC.CalculateCrc16(by).ToString("X"));
}