CRC16校验算法实现
- 格式:doc
- 大小:69.50 KB
- 文档页数:5
Node.js CRC16 Modbus校验计算方法1. 引言在Modbus通信中,CRC16校验是一种常见的校验方式,用于验证通信数据的完整性和准确性。
Node.js作为一种流行的后端开发语言,提供了丰富的库和工具,可以方便地实现CRC16 Modbus校验的计算方法。
2. CRC16 Modbus校验原理CRC(Cyclic Redundancy Check)循环冗余校验是一种通过对数据进行多项式除法操作来检测传输过程中可能出现的错误的校验方法。
在Modbus通信中,使用的是CRC16(16位循环冗余校验)算法,其计算方法如下:- 初始化CRC寄存器为0xFFFF- 对每一个字节进行如下操作:- CRC = CRC XOR 字节- 循环8次:- 如果(CRC AND 1) = 1,则CRC = (CRC >> 1) XOR 0xA001- 否则,CRC = CRC >> 1- 最终CRC即为校验结果3. Node.js实现CRC16 Modbus校验计算方法在Node.js中,可以使用Buffer类和位运算符来实现CRC16 Modbus校验的计算方法。
以下是一个简单的实现示例:```javascriptfunction crc16Modbus(buffer) {let crc = 0xFFFF;for (let i = 0; i < buffer.length; i++) {crc = (crc ^ buffer[i]) & 0xFF;for (let j = 0; j < 8; j++) {if (crc & 0x01) {crc = (crc >> 1) ^ 0xA001;} else {crc = crc >> 1;}}}return crc;}```4. 使用示例可以将上述代码保存为一个js文件,然后在Node.js环境中引入该文件,并调用crc16Modbus函数来计算需要校验的数据的CRC16值。
CRC16校验算法实现CRC16算法基于二进制位的异或和移位操作,它将数据按照二进制形式进行处理。
CRC16算法采用了多项式除法的思想,通过对数据进行除法运算并计算余数,生成一定长度的冗余校验码,用于检测数据是否出现错误。
1.首先,需要选择一个CRC-16生成多项式。
常用的生成多项式有多个,常见的有CRC-CCITT(0x1021)、CRC-IBM(0x8005)等。
生成多项式决定了CRC-16算法的性能和效果。
2.将待校验的数据按照二进制形式进行处理。
如果数据是字符串,则需要将字符串转换为二进制形式。
可以使用ASCII码表将每个字符转换为对应的二进制形式。
3.初始化CRC寄存器为一个指定的值(通常为0xFFFF)。
4.对数据进行逐位处理。
从高位到低位,逐位将数据与CRC寄存器进行异或操作。
如果结果为1,则进行一次右移操作。
如果结果为0,则直接进行一次右移操作。
重复该操作直到处理完所有的位。
5.当所有的位处理完成后,将CRC寄存器的当前值作为校验码。
下面是一个简单的CRC16算法实现的示例代码(基于CRC-CCITT生成多项式,0x1021):```pythondef crc16(data):crc = 0xFFFF # 初始化CRC寄存器为0xFFFF#CRC-CCITT生成多项式polynomial = 0x1021for byte in data:crc ^= (byte << 8) # 将数据与CRC寄存器进行异或操作for _ in range(8):if crc & 0x8000:crc = (crc << 1) ^ polynomialelse:crc <<= 1return crc & 0xFFFF#示例用法data = "hello world"data_bytes = [ord(c) for c in data] # 将字符串转换为对应的ASCII码列表checksum = crc16(data_bytes)print("CRC16校验码:", checksum)```在上述示例代码中,crc16函数接收一个数据参数,该数据参数可以是字符串、字节数组等形式。
CCITTCRC-16计算原理与实现CCITT CRC-16计算原理与实现CRC的全称为Cyclic 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)=xrP(x)+R(x)接收⽅解码⽅法:将T(x)除以G(x),如果余数为0,则说明传输中⽆错误发⽣,否则说明传输有误。
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 函数并打印结果。
c#CRC-16MODBUS校验计算⽅法及异或校验算法⼗年河东,⼗年河西,莫欺少年穷学⽆⽌境,精益求精只要是代码,如下:///<summary>///低字节在前///</summary>///<param name="pDataBytes"></param>///<returns></returns>static byte[] CRC16LH(byte[] pDataBytes){ushort crc = 0xffff;ushort polynom = 0xA001;for (int i = 0; i < pDataBytes.Length; i++){crc ^= pDataBytes[i];for (int j = 0; j < 8; j++){if ((crc & 0x01) == 0x01){crc >>= 1;crc ^= polynom;}else{crc >>= 1;}}}byte[] result = BitConverter.GetBytes(crc);return result;}///<summary>///⾼字节在前///</summary>///<param name="pDataBytes"></param>///<returns></returns>static byte[] CRC16HL(byte[] pDataBytes){ushort crc = 0xffff;ushort polynom = 0xA001;for (int i = 0; i < pDataBytes.Length; i++){crc ^= pDataBytes[i];for (int j = 0; j < 8; j++){if ((crc & 0x01) == 0x01){crc >>= 1;crc ^= polynom;}else{crc >>= 1;}}}byte[] result = BitConverter.GetBytes(crc).Reverse().ToArray() ;return result;}还有两个供⼤家验证的byte数组,如下:List<byte> llsst = new List<byte>() {0x79,0x79,0x01,0x01,0x00,0x1C,0x01,0x90,0x00,0x01,0x28,0xC3,0xC1,0x00,0xE9,0x9E,0x00,0x00,0x00,0x00,0x52,0x85,0x00,0x01,0x11,0x8E,0x15,0x02,0xD0,0x41,0x3E,0x02,0x0B var CrcLs3t22 = CRC16LH(llsst.ToArray());var CrcLs2t25 = CRC16HL(llsst.ToArray());低字节在前的结果为:83 9A⾼字节在前的结果为:9A 83异或校验算法:public static byte XOR_Check(List<byte> pbuf){int res = 0;int len = pbuf.Count;for (int i = 0; i < len; i++){res ^= pbuf[i];}return BitConverter.GetBytes(res)[0];}@天才卧龙的博客。
crc16算法原理
CRC16(循环冗余校验)是一种校验数据完整性的算法,可以找
出数据中的错误,用于检验传输过程中数据是否被错误地修改过,针
对数据传输过程中大量无意义码流及噪声对数据造成干扰等问题。
它
本质上是基于位运算(如异或运算)的特殊编码方法,经过这种编码,可以发现任何位级、字节级的改变,且此改变非常明显,以保证数据
的正确性。
是累加检验的实现。
它的一般过程是:首先把数据和一个
固定长度的码(最常用的是16位的CRC码)进行比较,如果数据中出
现改变,则导致码的改变,如果不一致,说明发生了数据错误;若一致,没有发生数据错误,则数据传输时正确。
CRC校验算法CRC校验算法CRC(Cyclic Redundancy Check)循环冗余校验是常用的数据校验方法,讲CRC算法的文章很多,之所以还要写这篇,是想换一个方法介绍CRC算法,希望能让大家更容易理解CRC算法。
先说说什么是数据校验。
数据在传输过程(比如通过网线在两台计算机间传文件)中,由于传输信道的原因,可能会有误码现象(比如说发送数字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校验。
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位)进行异或运算,得到余数。
CRC16校验算法实现(转)循环冗余码校验英文名称为Cyclical Redundancy Check,简称CRC。
它是利用除法及余数的原理来作错误侦测(Error Detecting)的。
实际应用时,发送装置计算出CRC值并随数据一同发送给接收装置,接收装置对收到的数据重新计算CRC并与收到的CRC相比较,若两个CRC值不同,则说明数据通讯出现错误。
根据应用环境与习惯的不同,CRC又可分为以下几种标准:①CRC-12码;②CRC-16码;③CRC-CCITT码;④CRC-32码。
CRC-12码通常用来传送6-bit字符串。
CRC-16及CRC-CCITT码则用是来传送8-bit字符,其中CRC-16为美国采用,而CRC-CCITT为欧洲国家所采用。
CRC-32码大都被采用在一种称为Point-to-Point的同步传输中。
下面着重是CRC-16检验码的生成过程。
CRC-16码由两个字节构成,在开始时CRC寄存器的每一位都预置为1,然后把CRC寄存器与8-bit的数据进行异或,之后对CRC寄存器从高到低进行移位,在最高位(MSB)的位置补零,而最低位(LSB,移位后已经被移出CRC寄存器)如果为1,则把寄存器与预定义的多项式码进行异或,否则如果 LSB为零,则无需进行异或。
重复上述的由高至低的移位8次,第一个8-bit数据处理完毕,用此时CRC寄存器的值与下一个8-bit数据异或并进行如前一个数据似的8次移位。
所有的字符处理完成后CRC寄存器内的值即为最终的CRC值。
下面为CRC16的计算过程,其中生成多项式为:X16+X15+X2+1: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值。
校验码实现编写CRC校验程序有两种办法:一种为计算法,一种为查表法。
下面是查表法的C语言实现:校验码算法程序实现样例(C语言):// Test.cpp : Defines the entry point for the console application. #include "stdafx.h"static unsigned char auchCRCHi[]={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};static unsigned char auchCRCLo[]={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};unsigned short CRC16(unsigned char* puchMsg, unsigned short usDataLen){unsigned char uchCRCHi = 0xFF ;unsigned char uchCRCLo = 0xFF ;unsigned char uIndex ;while (usDataLen--){uIndex = uchCRCHi ^ *puchMsg++;uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];uchCRCLo = auchCRCLo[uIndex];}return (uchCRCHi << 8 | uchCRCLo) ;};void main(int argc, char* argv[]){unsigned charsrc[21]={'1','2','3','6','3','4','2','3','4','2','9','8','7','3','6','5','2','8 ','9','3','5'};unsigned short code = CRC16(src,21);printf("the result is %d/n",code);}以下是Delphi实现的代码unit CRC16;interfaceusesWindows, SysUtils;function CRC(a_strPuchMsg:string):LongWord; implementationconstct_ArrayCRCHi: array[0..255] of LongWord=($00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0,$80, $41, $00, $C1, $81, $40, $01, $C0, $80, $41,$00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0,$80, $41, $01, $C0, $80, $41, $00, $C1, $81, $40,$00, $C1, $81, $40, $01, $C0, $80, $41, $00, $C1,$81, $40, $01, $C0, $80, $41, $01, $C0, $80, $41,$00, $C1, $81, $40, $01, $C0, $80, $41, $00, $C1,$81, $40, $00, $C1, $81, $40, $01, $C0, $80, $41,$00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0,$80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40,$01, $C0, $80, $41, $01, $C0, $80, $41, $00, $C1,$81, $40, $01, $C0, $80, $41, $00, $C1, $81, $40,$00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0,$80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40,$01, $C0, $80, $41, $00, $C1, $81, $40, $01, $C0,$80, $41, $01, $C0, $80, $41, $00, $C1, $81, $40,$00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0,$80, $41, $00, $C1, $81, $40, $01, $C0, $80, $41,$00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0,$80, $41, $00, $C1, $81, $40, $01, $C0, $80, $41,$01, $C0, $80, $41, $00, $C1, $81, $40, $01, $C0,$80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40,$01, $C0, $80, $41, $01, $C0, $80, $41, $00, $C1,$81, $40, $00, $C1, $81, $40, $01, $C0, $80, $41,$00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0,$80, $41, $00, $C1, $81, $40);ct_ArrayCRCLo:array[0..255] of LongWord=($00, $C0, $C1, $01, $C3, $03, $02, $C2, $C6, $06,$07, $C7, $05, $C5, $C4, $04, $CC, $0C, $0D, $CD,$0F, $CF, $CE, $0E, $0A, $CA, $CB, $0B, $C9, $09,$08, $C8, $D8, $18, $19, $D9, $1B, $DB, $DA, $1A,$1E, $DE, $DF, $1F, $DD, $1D, $1C, $DC, $14, $D4,$D5, $15, $D7, $17, $16, $D6, $D2, $12, $13, $D3,$11, $D1, $D0, $10, $F0, $30, $31, $F1, $33, $F3,$F2, $32, $36, $F6, $F7, $37, $F5, $35, $34, $F4,$3C, $FC, $FD, $3D, $FF, $3F, $3E, $FE, $FA, $3A,$3B, $FB, $39, $F9, $F8, $38, $28, $E8, $E9, $29,$EB, $2B, $2A, $EA, $EE, $2E, $2F, $EF, $2D, $ED,$EC, $2C, $E4, $24, $25, $E5, $27, $E7, $E6, $26,$22, $E2, $E3, $23, $E1, $21, $20, $E0, $A0, $60,$61, $A1, $63, $A3, $A2, $62, $66, $A6, $A7, $67,$A5, $65, $64, $A4, $6C, $AC, $AD, $6D, $AF, $6F,$6E, $AE, $AA, $6A, $6B, $AB, $69, $A9, $A8, $68,$78, $B8, $B9, $79, $BB, $7B, $7A, $BA, $BE, $7E,$7F, $BF, $7D, $BD, $BC, $7C, $B4, $74, $75, $B5,$77, $B7, $B6, $76, $72, $B2, $B3, $73, $B1, $71,$70, $B0, $50, $90, $91, $51, $93, $53, $52, $92,$96, $56, $57, $97, $55, $95, $94, $54, $9C, $5C,$5D, $9D, $5F, $9F, $9E, $5E, $5A, $9A, $9B, $5B,$99, $59, $58, $98, $88, $48, $49, $89, $4B, $8B,$8A, $4A, $4E, $8E, $8F, $4F, $8D, $4D, $4C, $8C,$44, $84, $85, $45, $87, $47, $46, $86, $82, $42,$43, $83, $41, $81, $80, $40);function CRC(a_strPuchMsg:string):LongWord;varl_CRCHi, l_CRCLo, l_Index, l_DataLen, i:LongWord; beginl_DataLen:= Length(a_strPuchMsg);l_CRCHi := $FF ;l_CRCLo := $FF ;l_Index :=0;i:=1;while (i<=l_DataLen) dobeginl_Index := l_CRCHi xor Integer(a_strPuchMsg[i]);l_CRCHi := l_CRCLo xor ct_ArrayCRCHi[l_Index];l_CRCLo := ct_ArrayCRCLo[l_Index];Inc(i);end;Result:= (l_CRCHi shl 8) or l_CRCLo;end;end.。