CRC16 三种算法及c实现
- 格式:docx
- 大小:16.76 KB
- 文档页数:5
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]。
C#语言CRC数据校验算法目录C#语言CRC数据校验算法 (1)前言 (1)Crc16 (2)Crc16CCITT和Crc16CCITT_False (5)Crc16FORX25 (6)Crc32 (7)赠送常用字节算法 (9)源码文件 (11)前言每个算法都经过验证的,都是在硬件采集上使用过,除了Crc32算法没验证外,其它算法请放心使用附C#源码文件。
(文档末尾有源码文件)Crc16#region crc16public static string GetCrc16(string data){byte[] bs = StrToToHexByte(data);string crc16 = Get_CRC16_C(bs);string crc16_r = string.Format("{0} {1}", crc16.Substring(2, 2),crc16.Substring(0, 2));bs = null;crc16 = null;return crc16_r;}public static string ReverseCrc16(string crc16){string crc16Reverse = string.Format("{0} {1}", crc16.Substring(2, 2), crc16.Substring(0, 2));return crc16Reverse;}///<summary>///字符串转16进制字节数组///</summary>///<param name="hexString"></param>///<returns></returns>public static byte[] StrToToHexByte(string hexString){hexString = hexString.Replace(" ", "");if ((hexString.Length % 2) != 0)hexString = string.Format("{0} ", hexString);byte[] returnBytes = new byte[hexString.Length / 2];for (int i = 0; i < returnBytes.Length; i++)returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);return returnBytes;}///<summary>///字节数组转16进制字符串///</summary>///<param name="bytes"></param>///<returns></returns>public static string ByteToHexStr(byte[] bytes){string returnStr = "";if (bytes != null){for (int i = 0; i < bytes.Length; i++){returnStr = string.Format("{0}{1}", returnStr, bytes[i].ToString("X2"));}}return returnStr;}///<summary>///计算CRC校验码,并转换为十六进制字符串/// Cyclic Redundancy Check 循环冗余校验码///是数据通信领域中最常用的一种差错校验码///特征是信息字段和校验字段的长度可以任意选定///</summary>///<param name="data"></param>///<returns></returns>public static string Get_CRC16_C(byte[] data){byte num = 0xff;byte num2 = 0xff;byte num3 = 1;byte num4 = 160;byte[] buffer = data;for (int i = 0; i < buffer.Length; i++){//位异或运算num = (byte)(num ^ buffer[i]);for (int j = 0; j <= 7; j++){byte num5 = num2;byte num6 = num;//位右移运算num2 = (byte)(num2 >> 1);num = (byte)(num >> 1);//位与运算if ((num5 & 1) == 1){//位或运算num = (byte)(num | 0x80);}if ((num6 & 1) == 1){num2 = (byte)(num2 ^ num4);num = (byte)(num ^ num3);}}}return ByteToHexStr(new byte[] { num, num2 }, 2);}///<summary>///获取并校验两数据是否一致///</summary>///<param name="srcData"></param>///<param name="desData"></param>///<returns></returns>public static bool CheckCRC(byte[] srcData, byte[] desData) {string crc = Get_CRC16_C(srcData);if (crc == ByteToHexStr(desData, desData.Length))return true;elsereturn false;}///<summary>///字节数组转16进制字符串///</summary>///<param name="bytes"></param>///<returns></returns>public static string ByteToHexStr(byte[] bytes, int size) {string returnStr = "";if (bytes != null){for (int i = 0; i < size; i++){returnStr = string.Format("{0}{1}", returnStr, bytes[i].ToString("X2"));}}return returnStr;}#endregion crc16Crc16CCITT和Crc16CCITT_False#region Crc16CCITTpublic static string ConvertToHEX(int dec){return dec.ToString("X");}public static string GetCrc16CCITT_False(string hexString){string hex = ConvertToHEX(crc16(StrToToHexByte(hexString))).PadLeft(4, '0');string crc = ReverseCrc16(hex);return crc;}public static int crc16(byte[] bytes){return crc16(bytes, bytes.Length);}public static int crc16(byte[] bytes, int len){int crc = 0xFFFF;for (int j = 0; j < len; j++){crc = ((crc >> 8) | (crc << 8)) & 0xffff;crc ^= (bytes[j] & 0xff);// byte to int, trunc signcrc ^= ((crc & 0xff) >> 4);crc ^= (crc << 12) & 0xffff;crc ^= ((crc & 0xFF) << 5) & 0xffff;}crc &= 0xffff;return crc;}public static int crc16(byte[] bytes, int start, int len){int crc = 0xFFFF;for (; start < len; start++){crc = ((crc >> 8) | (crc << 8)) & 0xffff;crc ^= (bytes[start] & 0xff);// byte to int, trunc signcrc ^= ((crc & 0xff) >> 4);crc ^= (crc << 12) & 0xffff;crc ^= ((crc & 0xFF) << 5) & 0xffff;}crc &= 0xffff;return crc;}public static short crc16_short(byte[] bytes){return crc16_short(bytes, 0, bytes.Length);}public static short crc16_short(byte[] bytes, int len){return (short)crc16(bytes, len);}public static short crc16_short(byte[] bytes, int start, int len) {return (short)crc16(bytes, start, len);}#endregion Crc16CCITTCrc16FORX25#region CRC16FORX25public static byte[] CRC_16forx25(byte[] bytes){byte[] returnVal = new byte[2];int i, j, lsb;int h = 0xffff;for (i = 0; i < bytes.Length; i++){h ^= bytes[i];for (j = 0; j < 8; j++){lsb = h & 0x0001; //取 CRC 的移出位h >>= 1;if (lsb == 1){h ^= 0x8408;}}}h ^= 0xffff;returnVal[1] = (byte)(h >> 8);//CRC高位returnVal[0] = (byte)(h & 0x00ff);//CRC低位return returnVal;}#endregion CRC16FORX25Crc32#region crc32public class CRC32{static UInt32[] crcTable = {0x0, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535,0x9e6495a3,0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07,0x90bf1d91,0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5,0xe8b8d433,0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97,0xe6635c01,0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615,0x73dc1683,0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27,0x7d079eb1,0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713,0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21,0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,};public static byte[] GetCrc32(byte[] bytes){//e6dda9daint crc = GetCRC32(bytes);string str = Convert.ToString(crc, 16).ToUpper();byte[] b4 = new byte[4];b4[0] = Convert.ToByte(str.Substring(6), 16);b4[1] = Convert.ToByte(str.Substring(4, 2), 16);b4[2] = Convert.ToByte(str.Substring(2, 2), 16);b4[3] = Convert.ToByte(str.Substring(0, 2), 16);return b4;}public static int GetCRC32(byte[] bytes){int iCount = bytes.Length;UInt32 crc = 0xFFFFFFFF;for (int i = 0; i < iCount; i++){crc = ((crc >> 8) & 0x00FFFFFF) ^ crcTable[(crc ^ bytes[i]) & 0xFF];}UInt32 temp = crc ^ 0xFFFFFFFF;int t = (int)temp;return (t);}}#endregion赠送常用字节算法public static int LastIndexOf(byte[] data, byte[] find){if (find == null || find.Length == 0)return -1;int pos = -1;for (int i = data.Length; i >= find.Length; i--){bool isFind = true;for (int j = 0; j < find.Length; j++){if (find[j] != data[i - (find.Length - j)]){isFind = false;break;}}if (isFind){pos = i - find.Length;break;}}return pos;}public static int IndexOf(byte[] data, byte[] find){if (find == null || find.Length == 0)return -1;if (find.Length > data.Length)return -1;int pos = -1;for (int i = 0; i < data.Length; i++){if (data.Length - i >= find.Length){bool isFind = true;for (int j = 0; j < find.Length; j++){if (find[j] != data[i + j]){isFind = false;break;}}if(isFind){pos = i;break;}}}return pos;}public static int LastIndexOf(List<byte> data, byte[] find) {if (find == null || find.Length == 0)return -1;int pos = -1;for (int i = data.Count; i >= find.Length; i--){bool isFind = true;for (int j = 0; j < find.Length; j++){if (find[j] != data[i - (find.Length - j)]){isFind = false;break;}}if (isFind){pos = i - find.Length;break;}}return pos;}//是否能通过crc校验public static bool IsCrc16Pass(string fullData){if (fullData.Length >= 6){string data = fullData.Substring(0, fullData.Length - 5).Trim();string crc16 = fullData.Substring(fullData.Length - 5);string calcCrc16 = GetDefalutCrc16(data);string calcCrc16Rev = ReverseCrc16(calcCrc16);return crc16.Replace(" ", "") == calcCrc16.Replace(" ", "") || crc16.Replace(" ", "") == calcCrc16Rev.Replace(" ", "");}return false;}文件CrcHelper.cs。
按字节计算CRCunsigned int cal_crc(unsigned char *ptr,unsigned char len) {unsigned int crc;unsigned char da;unsigned int crc_ta[256]={/*CRC余式表*/0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0};crc=0;while(len--!=0){da=(unsigned char)(crc/256); /*以8位二进制数的形式暂存CRC的高8位*/crc<<=8; /*左移8位,相当于CRC的低8位乘以82*/crc^=crc_ta[da^*ptr]; /*高8位和当前字节相加后再查表求CRC,再加上以前的CRC*/ptr++;}return(crc);}按半字节计算CRCunsigned cal_crc(unsigned char*ptr,unsigned char len){unsigned int crc;unsigned char da;unsigned int crc_ta[16]={/*CRC余式表*/0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,};crc=0;while(len--!=0){da=((unsigned char)(crc/256))/16; /*暂存CRC的高四位*/crc<<=4; /*CRC右移4位,相当于取CRC的低12位)* /crc^=crc_ta[da^(*ptr/16)]; /*CRC的高4位和本字节的前半字节相加后查表计算CRC,然后上上一次CRC的余数*/da=((unsigned char)(crc/256))/16; /*暂存CRC的高4位*/crc<<=4; /*CRC右移4位,相当于CRC的低12位)*/crc^=crc_ta[da^(*ptr&0x0f)]; /*CRC的高4位和本字节的后半字节相加后查表计算CRC,然后再加上上一次CRC的余数*/ ptr++;}return(crc);}按位计算CRCunsigned int cal_crc(unsigned char *ptr,unsigned char len){unsigned char i;unsigned int crc=0;while(len--!=0){for(i=0x80;i!=0;i/=2){if((crc&0x8000)!=0) /*余式CRC乘以2再求CRC*/{crc*=2;crc^=0x1021;}else crc*=2;if((*ptr&i)!=0)crc^=0x1021; /*再加上本位的CRC*/}ptr++;}return(crc);}。
C语言实现CRC16校验1.定义CRC16多项式和初始化值:CRC16校验使用的多项式可以是多种不同的值,常用的是0x8005、此外,需要定义一个初始值,初值可为0xFFFF。
```c#define CRC16_POLY 0x8005#define CRC16_INIT 0xFFFF```2.实现CRC16计算函数:根据CRC16校验算法,需要对输入数据的每个字节进行计算,不断更新CRC16值,最终得到校验结果。
```cunsigned short crc16(unsigned char *data, int length)unsigned short crc = CRC16_INIT;int i, j;for (i = 0; i < length; i++)crc ^= (unsigned short) data[i] << 8;for (j = 0; j < 8; j++)if (crc & 0x8000)crc = (crc << 1) ^ CRC16_POLY;} elsecrc = crc << 1;}}}return crc;```3.调用CRC16计算函数:将需要校验的数据传递给CRC16计算函数,并得到校验结果。
```cint mai//示例数据unsigned char data[] = {0x01, 0x02, 0x03, 0x04, 0x05};int length = sizeof(data) / sizeof(data[0]);//计算CRC16校验值unsigned short crc = crc16(data, length);//打印结果printf("CRC16校验值为:%04X\n", crc);return 0;```以上就是一个简单的C语言实现CRC16校验的代码。
请注意,这只是一个实现的简化版本,对于更复杂的数据校验场景,可能需要更多的处理。
CRC16(循环冗余校验码)是一种通过对数据进行多项式除法来生成校验码的方法。
它通常用于数据传输过程中的错误检测和校验,以确保数据的完整性和准确性。
CITT False CRC16 是其中一种常见的CRC16 校验码算法,它采用了 CITT 标准的多项式生成 16 位的校验码。
在 C 语言中,我们可以通过编写相应的函数来实现 CITT False CRC16 校验码的生成和验证。
本文将对 CITT False CRC16 算法进行介绍,并提供一个基于 C 语言的实现示例。
一、CITT False CRC16 算法介绍CITT False CRC16 算法采用了多项式 0x1021(x^16 + x^12 + x^5 + 1)来生成 16 位的校验码。
该算法将数据与 0x8005 进行按位异或运算,然后将结果与 0x8408 进行按位取反操作。
最终得到的余数就是 16 位的 CRC16 校验码。
该算法在数据通信领域得到了广泛的应用,因其计算速度快、效果稳定而备受青睐。
二、CITT False CRC16 算法实现在 C 语言中实现 CITT False CRC16 算法并不复杂,我们可以编写一个函数来完成 CRC16 校验码的生成和验证。
以下是一个基于 C 语言的示例代码:```c#include <stdio.h>#include <stdint.h>// 定义 CITT False CRC16 多项式#define POLY 0x1021// 计算 CRC16 校验码uint16_t crc16(uint8_t *data, uint32_t len) {uint16_t crc = 0;for (uint32_t i = 0; i < len; i++) {crc = crc ^ (data[i] << 8);for (int j = 0; j < 8; j++) {if (crc 0x8000) {crc = (crc << 1) ^ POLY;} else {crc = crc << 1;}}}return crc;}int m本人n() {// 测试数据uint8_t test_data[] = {0x01, 0x02, 0x03, 0x04, 0x05};uint32_t data_len = sizeof(test_data) / sizeof(test_data[0]);// 计算 CRC16 校验码uint16_t crc_code = crc16(test_data, data_len);printf("CRC16 校验码为:04X\n", crc_code);return 0;}```以上示例代码中,我们定义了一个 crc16 函数来计算 CITT False CRC16 校验码,同时编写了一个 m本人n 函数来调用 crc16 函数并打印结果。
CRC常见算法的C语言实现CRC(Cyclic Redundancy Check)是一种常见的数据校验算法,用于检测或校正以循环方式传输的数据中的错误。
CRC算法在通信、存储、校验等领域得到广泛应用。
以下是CRC常见算法的C语言实现示例。
1.CRC-8校验算法:```// CRC-8 polynomial: x^8+x^2+x+1 (0x07)unsigned char crc8(const unsigned char *data, unsigned int length)unsigned char crc = 0;for (unsigned int i = 0; i < length; i++)crc ^= data[i];for (unsigned int j = 0; j < 8; j++)if (crc & 0x80)crc = (crc << 1) ^ 0x07;elsecrc <<= 1;}}return crc;```2.CRC-16校验算法:```// CRC-16 polynomial: x^16+x^15+x^2+1 (0x8005)unsigned short crc16(const unsigned char *data, unsigned int length)unsigned short crc = 0;for (unsigned int i = 0; i < length; i++)crc ^= (unsigned short)data[i] << 8;for (unsigned int j = 0; j < 8; j++)if (crc & 0x8000)crc = (crc << 1) ^ 0x8005;elsecrc <<= 1;}}return crc;```3.CRC-32校验算法:```// CRC-32 polynomial: 0x04c11db7unsigned int crc32(const unsigned char *data, unsigned int length)unsigned int crc = 0xFFFFFFFF;for (unsigned int i = 0; i < length; i++)crc ^= data[i];for (unsigned int j = 0; j < 8; j++)if (crc & 1)elsecrc >>= 1;}}return ~crc;```以上是常见的CRC校验算法的C语言实现示例。
CRC算法及C实现学习体会2008-09-20 15:21:13 阅读161 评论0 字号:大中小订阅一、CRC算法原理CRC校验的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的监督码(既CRC码)r位,并附在信息后边,构成一个新的二进制码序列数共(k+r)位,最后发送出去。
在接收端,则根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
16位的CRC码产生的规则是先将要发送的二进制序列数左移16位(既乘以)后,再除以一个多项式,最后所得到的余数既是CRC码。
假设数据传输过程中需要发送15位的二进制信息 g=101001110100001,这串二进制码可表示为代数多项式g(x) = x^14 + x^12 + x^9 + x^8 + x^7 + x^5 + 1,其中g中第k位的值,对应g(x)中x^k的系数。
将g(x)乘以x^m,既将g后加m个0,然后除以m阶多项式h(x),得到的(m-1)阶余项 r(x)对应的二进制码r就是CRC编码。
h(x)可以自由选择或者使用国际通行标准,一般按照h(x)的阶数m,将CRC算法称为CRC-m,比如CRC-32、CRC-64等。
国际通行标准可以参看/wiki/Cyclic_redundancy_checkg(x)和h(x)的除运算,可以通过g和h做xor(异或)运算。
比如将11001与10101做xor运算:明白了xor运算法则后,举一个例子使用CRC-8算法求101001110100001的效验码。
CRC-8标准的h(x) = x^8 + x^7 + x^6 + x^4 + x^2 + 1,既h是9位的二进制串111010101。
经过迭代运算后,最终得到的r是10001100,这就是CRC效验码。
通过示例,可以发现一些规律,依据这些规律调整算法:1. 每次迭代,根据gk的首位决定b,b是与gk进行运算的二进制码。
crc16校验算法c语言crc16校验算法是一种常用的数据校验方法,它可以检测出数据传输或存储过程中的错误,并提供纠错的依据。
crc16校验算法的原理是将待校验的数据看作一个多项式,用一个固定的生成多项式对其进行除法运算,得到的余数就是crc16校验码。
生成多项式的选择会影响crc16校验算法的性能,不同的应用场景可能需要不同的生成多项式。
本文主要介绍一种常用的生成多项式,即CRC-CCITT,它的二进制表示为0x1021,十六进制表示为0x11021。
本文将介绍三种实现crc16校验算法c语言的方法,分别是按位计算、按半字节计算和按单字节计算。
这三种方法的原理都是基于生成多项式对数据进行除法运算,但是具体的实现方式有所不同,各有优缺点。
下面分别介绍这三种方法,并给出相应的c语言代码。
按位计算按位计算是最直接的实现方式,它是将待校验的数据和生成多项式按位进行异或运算,得到余数。
这种方法的优点是不需要额外的存储空间,缺点是效率较低,需要循环处理每一位数据。
按位计算的c语言代码如下:#include<stdint.h>#define CRC_CCITT 0x1021//生成多项式//函数名称:crc_cal_by_bit;按位计算CRC//函数参数:uint8_t * ptr;指向发送缓冲区的首字节// uint32_t len;要发送的总字节数//函数返回值:uint16_tuint16_t crc_cal_by_bit(uint8_t*ptr, uint32_t len) {uint32_t crc =0xffff; //初始值while (len--!=0) {for (uint8_t i =0x80; i !=0; i >>=1) { //处理每一位数据crc <<=1; //左移一位if ((crc &0x10000) !=0) //如果最高位为1,则异或生成多项式crc ^=0x11021;if ((*ptr & i) !=0) //如果当前数据位为1,则异或生成多项式crc ^= CRC_CCITT;}ptr++; //指向下一个字节}uint16_t retCrc = (uint16_t)(crc &0xffff); //取低16位作为结果return retCrc;}按半字节计算按半字节计算是对按位计算的优化,它是将待校验的数据和生成多项式按半字节(4位)进行异或运算,得到余数。
CRC16C语⾔实现最近看到⼀个实现crc16的⼩程序,刚开始,不明觉厉,于是花了⼀个周末去know how。
CRC(Cyclic Redundancy Check)循环冗余校验是常⽤的数据校验⽅法。
先说说什么是数据校验。
数据在传输过程(⽐如通过⽹线在两台计算机间传⽂件)中,由于传输信道的原因,可能会有误码现象(⽐如说发送数字5但接收⽅收到的却是6),如何发现误码呢?⽅法是发送额外的数据让接收⽅校验是否正确,这就是数据校验。
最容易想到的校验⽅法是和校验,就是将传送的数据(按字节⽅式)加起来计算出数据的总和,并将总和传给接收⽅,接收⽅收到数据后也计算总和,并与收到的总和⽐较看是否相同。
如果传输中出现误码,那么总和⼀般不会相同,从⽽知道有误码产⽣,可以让发送⽅再发送⼀遍数据。
CRC校验也是添加额外数据做为校验码,这就是CRC校验码,那么CRC校验码是如何得到的呢? ⾮常简单,CRC校验码就是将数据除以某个固定的数(⽐如ANSI-CRC16中,这个数是0x18005),所得到的余数就是CRC校验码。
那这⾥就有⼀个问题,我们传送的是⼀串字节数据,⽽不是⼀个数据,怎么将⼀串数字变成⼀个数据呢?这也很简单,⽐如说2个字节B1,B2,那么对应的数就是(B1<<8)+B2;如果是3个字节B1,B2,B3,那么对应的数就是((B1<<16)+(B2<<8)+B3),⽐如数字是0x01,0x02,0x03,那么对应的数字就是0x10203;依次类推。
如果字节数很多,那么对应的数就⾮常⾮常⼤,不过幸好CRC只需要得到余数,⽽不需要得到商。
从上⾯介绍的原理我们可以⼤致知道CRC校验的准确率,在CRC8中出现了误码但没发现的概率是1/256,CRC16的概率是1/65536,⽽CRC32的概率则是1/2^32,那已经是⾮常⼩了,所以⼀般在数据不多的情况下⽤CRC16校验就可以了,⽽在整个⽂件的校验中⼀般⽤CRC32校验。
CRC校验C语言实现,转载请注明出处,谢谢CRC(Cyclic Redundancy Check)校验应用较为广泛,以前为了处理简单,在程序中大多数采用LRC(Longitudinal Redundancy Check)校验,LRC校验很好理解,编程实现简单。
用了一天时间研究了CRC的C语言实现,理解和掌握了基本原理和C语言编程。
结合自己的理解简单写下来。
1、CRC简介CRC检验的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个检验码r位(就是CRC码),附在信息后面,构成一个新的二进制码序列数共(k+r)位,最后发送出去。
接收端根据同样的规则校验,以确定传送中是否出错。
接收端有两种处理方式:1、计算k位序列的CRC码,与接收到的CRC比较,一致则接收正确。
2、计算整个k+r位的CRC码,若为0,则接收正确。
CRC码有多种检验位数,8位、16位、32位等,原理相同。
16位的CRC码产生的规则是先将要发送的二进制序列数左移16位(即乘以2的16次方后),除以一个多项式,最后所得到的余数就是CRC码。
求CRC码所采用的是模2运算法则,即多项式除法中采用不带借位的减法运算,运算等同于异或运算。
这一点要仔细理解,是编程的基础。
CRC-16: (美国二进制同步系统中采用) G(X) = X16 + X15 + X2 + 1CRC-CCITT: (由欧洲CCITT推荐) G(X) = X16 + X12 + X5 + 1CRC-32: G(X) = X32 + X26 + X23 + X22 + X16 +X12 + X11 + X10 + X8 + X7 + X5 + X4 + X2 + X1 + 12、按位计算CRC采用CRC-CCITT多项式,多项式为0x11021,C语言编程时,参与计算为0x1021,这个地方得深入思考才能体会其中的奥妙,分享一下我的思路:当按位计算CRC时,例如计算二进制序列为1001 1010 1010 1111时,将二进制序列数左移16位,即为1001 1010 1010 1111 (0000 0000 0000 0000),实际上该二进制序列可拆分为1000 0000 0000 0000 (0000 0000 0000 0000) + 000 0000 0000 0000 (0000 0000 0000 0000) + 00 0000 0000 0000 (0000 0000 0000 0000) + 1 0000 0000 0000 (0000 0000 0000 0000) + ……现在开始分析运算:<1>对第一个二进制分序列求余数,竖式除法即为0x10000 ^ 0x11021运算,后面的0位保留;<2>接着对第二个二进制分序列求余数,将第一步运算的余数*2后再和第二个二进制分序列一起对0x11021求余,这一步理解应该没什么问题。
CCITT CRC-16计算原理与实现时间:2011-08-28 22:37:20 来源:作者:CRC的全称为Cy clic Redundancy Check,中文名称为循环冗余校验。
它是一类重要的线性分组码,编码和解码方法简单,检错和纠错能力强,在通信领域广泛地用于实现差错控制。
实际上,除数据通信外,CRC在其它很多领域也是大有用武之地的。
例如我们读软盘上的文件,以及解压一个ZIP文件时,偶尔会碰到“Bad CRC”错误,由此它在数据存储方面的应用可略见一斑。
差错控制理论是在代数理论基础上建立起来的。
这里我们着眼于介绍CRC的算法与实现,对原理只能捎带说明一下。
若需要进一步了解线性码、分组码、循环码、纠错编码等方面的原理,可以阅读有关资料。
利用CRC进行检错的过程可简单描述为:在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息后边,构成一个新的二进制码序列数共k+r位,然后发送出去。
在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
这个规则,在差错控制理论中称为“生成多项式”。
1 代数学的一般性算法在代数编码理论中,将一个码组表示为一个多项式,码组中各码元当作多项式的系数。
例如1100101 表示为1·x6+1·x5+0·x4+0·x3+1·x2+0·x+1,即x6+x5+x2+1。
设编码前的原始信息多项式为P(x),P(x)的最高幂次加1等于k;生成多项式为G(x),G(x)的最高幂次等于r;CRC多项式为R(x);编码后的带CRC的信息多项式为T(x)。
发送方编码方法:将P(x)乘以xr(即对应的二进制码序列左移r位),再除以G(x),所得余式即为R(x)。
用公式表示为T(x)=xr P(x)+R(x)接收方解码方法:将T(x)除以G(x),如果余数为0,则说明传输中无错误发生,否则说明传输有误。
下面我们以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寄存器将移出的最高1bitunsigned 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校验值。
CRC16常见⼏个标准的算法及C语⾔实现CRC16常见的标准有以下⼏种,被⽤在各个规范中,其算法原理基本⼀致,就是在数据的输⼊和输出有所差异,下边把这些标准的差异列出,并给出C语⾔的算法实现。
CRC16_CCITT:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,⾼位在后,结果与0x0000异或CRC16_CCITT_FALSE:多项式x16+x12+x5+1(0x1021),初始值0xFFFF,低位在后,⾼位在前,结果与0x0000异或CRC16_XMODEM:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在后,⾼位在前,结果与0x0000异或CRC16_X25:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,⾼位在后,结果与0xFFFF异或CRC16_MODBUS:多项式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,⾼位在后,结果与0x0000异或CRC16_IBM:多项式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,⾼位在后,结果与0x0000异或CRC16_MAXIM:多项式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,⾼位在后,结果与0xFFFF异或CRC16_USB:多项式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,⾼位在后,结果与0xFFFF异或多项式产⽣:如x16+x12+x5+1x16表⽰第16位为1,x5表⽰第5位为1(1 << 16) | (1 << 12) | (1 << 5) | (1) = 0x11021但是CRC16只取低16位,写成16进制数就是 0x1021CRC16的算法原理:1.根据CRC16的标准选择初值CRCIn的值。
2.将数据的第⼀个字节与CRCIn⾼8位异或。
CRC16校验C语⾔程序源码-(附完整的可执⾏的C语⾔代码)CRC16校验C语⾔程序源码-(附完整的可执⾏的C语⾔代码)CRC16校验C语⾔程序源码(附完整的可执⾏的C语⾔代码)//CRC16校验在通讯中应⽤⼴泛,这⾥不对其理论进⾏讨论,只对常见的2种//实现⽅法进⾏测试。
⽅法⼀:查表法(256长度的校验表)速度快,准确,但是对于单⽚机设备存储占⽤⼤,且校验表长度⼤,输⼊时容易出现错误。
// ---------------- POPULAR POLYNOMIALS ----------------// CCITT: x^16 + x^12 + x^5 + x^0 (0x1021) // CRC-16: x^16 + x^15 + x^2 + x^0 (0x8005) #define CRC_16_POLYNOMIALS 0x8005const BYTE chCRCHTalbe[] = // 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};const BYTE chCRCLTalbe[] = // 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};WORD CRC16_1(BYTE* pchMsg, WORD wDataLen){BYTE chCRCHi = 0xFF; // ⾼CRC字节初始化BYTE chCRCLo = 0xFF; // 低CRC字节初始化WORD wIndex; // CRC循环中的索引while (wDataLen--){// 计算CRCwIndex = chCRCLo ^ *pchMsg++ ;chCRCLo = chCRCHi ^ chCRCHTalbe[wIndex];chCRCHi = chCRCLTalbe[wIndex] ;}return ((chCRCHi << 8) | chCRCLo) ;}⽅法⼀:列表法(简单表)const WORD wCRCTalbeAbs[] ={0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400,};WORD CRC16_2(BYTE* pchMsg, WORD wDataLen){WORD wCRC = 0xFFFF;WORD i;BYTE chChar;for (i = 0; i < wDataLen; i++){chChar = *pchMsg++;wCRC = wCRCTalbeAbs[(chChar ^ wCRC) & 15] ^ (wCRC >> 4); wCRC = wCRCTalbeAbs[((chChar >> 4) ^ wCRC) & 15] ^ (wCRC >> 4); }return wCRC;}⽅法⼆:定义法根据CRC16/MODBUS原理直接计算,算法简单但对单⽚机计算压⼒⼤。
标准CRC生成多项式如下表:名称生成多项式简记式* 标准引用CRC-4 x4+x+1 3 ITU G.704CRC-8 x8+x5+x4+1 0x31CRC-8 x8+x2+x1+1 0x07CRC-8 x8+x6+x4+x3+x2+x1 0x5ECRC-12 x12+x11+x3+x+1 80FCRC-16 x16+x15+x2+1 8005 IBM SDLCCRC16-CCITT x16+x12+x5+1 1021 ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCSCRC-32 x32+x26+x23+...+x2+x+1 04C11DB7 ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCSCRC-32c x32+x28+x27+...+x8+x6+1 1EDC6F41 SCTP生成多项式的最高位固定的1,故在简记式中忽略最高位1了,如0x1021实际是0x11021。
I、基本算法(人工笔算):以CRC16-CCITT为例进行说明,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];注意:使用长除法进行计算式,需要将除数多项式与预置位0x0000或0xFFFF异或以后再进行计算。
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(字节型算法):256^n表示256的n次方把按字节排列的数据流表示成数学多项式,设数据流为BYTE[n]BYTE[n-1]BYTE[n-2]、、、BYTE[1]BYTE[0],表示成数学表达式为BYTE[n]×256^n+BYTE[n-1]×256^(n-1)+...+BYTE[1]*256+BYTE[0],在这里+表示为异或运算。
设生成多项式为G17(17bit),CRC码为CRC16。
则,CRC16=(BYTE[n]×256^n+BYTE[n-1]×256^(n-1)+...+BYTE[1]×256+BYTE[0])×256^2/G17,即数据流左移16位,再除以生成多项式G17。
先变换BYTE[n-1]、BYTE[n-1]扩大后的形式,CRC16=BYTE[n]×256^n×256^2/G17+BYTE[n-1]×256^(n-1)×256^2/G17+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17=(Z[n]+Y[n]/G17)×256^n+BYTE[n-1]×256^(n-1)×256^2/G17+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17=Z[n]×256^n+{Y[n]×256/G17+BYTE[n-1]×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17=Z[n]×256^n+{(YH8[n]×256+YHL[n])×256/G17+BYTE[n-1]×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17 =Z[n]×256^n+{YHL[n]×256/G17+(YH8[n]+BYTE[n-1])×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17这样就推导出,BYTE[n-1]字节的CRC校验码为{YHL[n]×256/G17+(YH8[n]+BYTE[n-1])×256^2/G17},即上一字节CRC校验码Y[n]的高8位(YH8[n])与本字节BYTE[n-1]异或,该结果单独计算CRC校验码(即单字节的16位CRC校验码,对单字节可建立表格,预先生成对应的16位CRC校验码),所得的CRC校验码与上一字节CRC校验码Y[n]的低8位(YL8[n])乘以256(即左移8位)异或。
然后依次逐个字节求出CRC,直到BYTE[0]。
字节型算法的一般描述为:本字节的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 CCITT—1,“-1”的意思是CRC的初值为0Xffff。
方法1:将存有数据的字节数组进行逐位计算,求得字节形式的CRCtypedef unsigned __int16 INT16U;#define CRC_SEED 0xFFFF // 该位称为预置值,使用人工算法(长除法)时需要将除数多项式先与该与职位异或,才能得到最后的除数多项式#define POLY16 0x1021 // 该位为简式书写实际为0x11021INT16U crc16(unsigned char *buf,unsigned short length){INT16U shift,data,val;int i;shift = CRC_SEED;for(i=0;i<length;i++) {if((i % 8) == 0)data = (*buf++)<<8;val = shift ^ data;shift = shift<<1;data = data <<1;if(val&0x8000)shift = shift ^ POLY16;}return shift;}2、查表法static unsigned short ccitt_table[256] = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 };unsigned short crc_ccitt(unsigned char *q, int len){unsigned short crc = 0;while (len-- > 0)crc = ccitt_table[(crc >> 8 ^ *q++) & 0xff] ^ (crc << 8);return ~crc}。