完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
内容摘要】CRC-16是检测数据在发送过程中发生错误的常用校验方法,本文通过从工程应用的角度,讲述如何实现CRC-16的程序开发,并给出了Visual Basic和Visual C++程序代码,给从事工业控制的人员在写通信程序的时候提供一些有价值的参考。
一、前言 CRC的计算方式是将欲传输的数据块视为一堆连续位所构成的整个数值,将此数值除以一个特定的除数,通常以二进制表示,此除数称为生成多项式(ANSI CRC-16的生成多项式为:x16 + x15 + x2 + 1)。目前较常用的CRC位数目有8和16以及32,在这里只讲述如何写CRC位数目为16的程序。CRC位数目越大,数据的错误检测率则越高,但必须多花一些时间进行数据的计算。 二、CRC-16计算步骤 CRC-16的计算方法有两种:查表法与计算法,在这里只讲述计算法。本人在2000年在江西亚东水泥公司上班时,在某电力仪表上的说明书中摘录下来的计算CRC-16步骤如下: 1、 Load a 16-bit register with FFFF hex. Call this the CRC register. 2、 Exclusive OR the first 8-bit byte of the message with the low-order byte of the 16-bit CRC, putting the result in the CRC register. 3、 Shift the CRC register one bit to the right (toward the LSB), zero-filling the MSB. Extract and Examine. 4、 If the LSB was 1: Exclusive OR the CRC register with polynomial value A001 hex. If the LSB was 0: Repeat step 3 (another shift). 5、 Repeat step 3 and 4 until 8 shifts have been performed. When this is done, a complete 8-bit byte will have been processed. 6、 Repeat step 2 through 5 for the next 8-bit byte of them message. 7、 The final content of the CRC register is the CRC value. 中文解释如下: 1、定义一个初始值为FFFF的16位的变量,该变量称为CRC寄存器。(想想在程序中,应该怎么表示16位的变量呢?) 2、把欲发送或接收消息的高8位和CRC寄存器的底8位作异或运算,并把结果在赋到CRC寄存器。 3、CRC寄存器右移1位(朝最低位),同时最高位添零。取出并检查最低位是否为1。(Visual Basic 里如何做移位的运算呢?) 4、如果为1,则CRC寄存器与多项式A001异或;如果为0,则重复第3步的动作。(Visual Basic 里如何判断一个字节里某个位的值呢?) 5、重复3和4直到完成了8次移位。这样完整的8位字节将完成处理了。 6、对于下一个8位字节的处理就是重复第2步到第5步了 7、把所有的欲发送或接收消息这样处理后, CRC寄存器里的值就是我们最终需要得到的CRC校验码。 如果你能正确回答我的问题,那么恭喜你,你自己可以用Visual Basic写数据采集卡的控制程序了。 三、Visual Basic程序实现 以江阴长江斯菲尔电力仪表公司CD194E系列多功能电力仪表的MODBUS-RTU通讯协议的报文格式为例,该表通信报文格式使用的校验方式就是CRC-16。通过对地址01H、命令04H、数据地址005CH和数据长度0004H的CRC-16运算后得到主机请求数据报文的CRC16的校验码为31DBH。 程序界面 程序代码: Private Sub cmdGenerate_Click() Dim OutByte(7) As Byte, CRC16() As Byte, CRC16LO As Byte, CRC16HI As Byte, TempHI As Byte, TempLO As Byte Dim i As Integer, j As Integer ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' OutByte(0) = Val("&H" & txtOutByte(0).Text) OutByte(1) = Val("&H" & txtOutByte(1).Text) OutByte(2) = Val("&H" & txtOutByte(2).Text) OutByte(3) = Val("&H" & txtOutByte(3).Text) OutByte(4) = Val("&H" & txtOutByte(4).Text) OutByte(5) = Val("&H" & txtOutByte(5).Text) CRC16LO = &HFF '(1)Load a 16-bit register with FFFF hex.call this the CRC register. CRC16HI = &HFF For i = 0 To UBound (OutByte) - 2 CRC16LO = CRC16LO Xor OutByte (i) '(2)Exclusive OR the first 8-bit byte of the message 'with the low-order byte of the 16-bit CRC, 'putting the result in the CRC register For j = 0 To 7 TempHI = CRC16HI TempLO = CRC16LO CRC16HI = CRC16HI 2 '(3)Shift the CRC register one bit to the right(toward the LSB),zero-filling CRC16LO = CRC16LO 2 'the MSB.Extract and Examine If ((TempHI And &H1) = &H1) Then CRC16LO = CRC16LO Or &H80 '移位时,如果高低位是1,则低高位加1 End If If ((TempLO And &H1) = &H1) Then '(4)if the LSB was 1: CRC16HI = CRC16HI Xor &HA0 'Exclusive OR the CRC register with polynomial value A001 hex. CRC16LO = CRC16LO Xor &H1 End If 'if the LSB was 0: Repeat step 3 (another shift) Next j '(5)Repeat step 3 and 4 until 8 shifts have been performed. 'when this is done, a complete 8-bit byte will have been processed. Next i '(6)Repeat step 2 through 5 for the next 8-bit byte of them message. OutByte(6) = CRC16LO '(7)The final contents of the CRC register is the CRC value txtOutByte(6) = Hex(OutByte(6)) OutByte(7) = CRC16HI txtOutByte(7) = Hex(OutByte(7)) End Sub 四、Visual C++程序实现 程序界面 主要代码: #define CHECKVALUE(pt,nl) if((btData==NULL)||(nLength<=0)){AfxMessageBox("无效数组!");return -1;} BOOL CCRC_16Dlg::OnInitDialog() { …… m_strCRC="01 04 00 5C 00 04"; UpdateData(FALSE); return TRUE; // return TRUE unless you set the focus to a control } void CCRC_16Dlg::OnOK() { UpdateData(TRUE); CString strTemp; strTemp=m_strCRC; WORD CRC; BYTE btData[4096]; int nLength=StrToHex(strTemp,btData); CRC=ANSI_CRC_16(btData,nLength); //ANSI-16 CString str; str.Format(" %02X %02X",(BYTE)(CRC>>8),(BYTE)CRC); AfxMessageBox(str); CDialog::OnOK(); } WORD CCRC_16Dlg::ANSI_CRC_16(BYTE* btData,int nLength) //ANSI CRC-16,x16 + x15 + x2 + 1 { CHECKVALUE(btData,nLength); WORD CRC=0xFFFF; BYTE j,Tmp=0; int i; for(i=0;i CRC^=btData[i]; for (j=0;j<8;j++) { Tmp=CRC&0x0001; CRC=CRC>>1; if(Tmp)CRC=(CRC^0xA001); } } return ((CRC>>8)+(CRC<<8)); /* 应用时高在先 */ } int CCRC_16Dlg::StrToHex(CString str, BYTE *btData) { int nLength=str.GetLength(); if(nLength<2) return 0; for(int i=0;i } 五、结论 1, 这两个实例可以当作计算CRC-16的小工具,代码对于自己要开发CRC-16的人员也提供一些参考价值。 2, 同一个实例,两种开发语言,值得学习一下。看到这里,你可以告诉我在VC++中,异或是用什么符号?是不是很意外呢? |
|
相关推荐
4 个讨论
|
|
谢谢
|
|
|
|
|
|
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 18:04 , Processed in 0.701732 second(s), Total 52, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号