Modbus RTU协议CRC16编解码用VB6写起来比较啰嗦,需要做一些简单处理。下面就查表法,贴上源代码,并做一些简要说明。
源程序,对照上面的图看更方便。
Private Sub Command2_Click()
Dim I As Integer, J As Integer
Dim CRCHi As Integer, CRCLo As Integer
Dim CRCindex As Byte, TestString As StringDim TABHi(), TABLo()
TABHi() = Array( _
"&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", _
"&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", _
"&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", _
"&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", _
"&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", _
"&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", _
"&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", _
"&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", _
"&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", _
"&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", _
"&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", _
"&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", _
"&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", _
"&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", _
"&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", _
"&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", _
"&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", _
"&H40")TABLo() = Array( _
"&H00", "&HC0", "&HC1", "&H01", "&HC3", "&H03", "&H02", "&HC2", "&HC6", "&H06", "&H07", "&HC7", "&H05", "&HC5", "&HC4", _
"&H04", "&HCC", "&H0C", "&H0D", "&HCD", "&H0F", "&HCF", "&HCE", "&H0E", "&H0A", "&HCA", "&HCB", "&H0B", "&HC9", "&H09", _
"&H08", "&HC8", "&HD8", "&H18", "&H19", "&HD9", "&H1B", "&HDB", "&HDA", "&H1A", "&H1E", "&HDE", "&HDF", "&H1F", "&HDD", _
"&H1D", "&H1C", "&HDC", "&H14", "&HD4", "&HD5", "&H15", "&HD7", "&H17", "&H16", "&HD6", "&HD2", "&H12", "&H13", "&HD3", _
"&H11", "&HD1", "&HD0", "&H10", "&HF0", "&H30", "&H31", "&HF1", "&H33", "&HF3", "&HF2", "&H32", "&H36", "&HF6", "&HF7", _
"&H37", "&HF5", "&H35", "&H34", "&HF4", "&H3C", "&HFC", "&HFD", "&H3D", "&HFF", "&H3F", "&H3E", "&HFE", "&HFA", "&H3A", _
"&H3B", "&HFB", "&H39", "&HF9", "&HF8", "&H38", "&H28", "&HE8", "&HE9", "&H29", "&HEB", "&H2B", "&H2A", "&HEA", "&HEE", _
"&H2E", "&H2F", "&HEF", "&H2D", "&HED", "&HEC", "&H2C", "&HE4", "&H24", "&H25", "&HE5", "&H27", "&HE7", "&HE6", "&H26", _
"&H22", "&HE2", "&HE3", "&H23", "&HE1", "&H21", "&H20", "&HE0", "&HA0", "&H60", "&H61", "&HA1", "&H63", "&HA3", "&HA2", _
"&H62", "&H66", "&HA6", "&HA7", "&H67", "&HA5", "&H65", "&H64", "&HA4", "&H6C", "&HAC", "&HAD", "&H6D", "&HAF", "&H6F", _
"&H6E", "&HAE", "&HAA", "&H6A", "&H6B", "&HAB", "&H69", "&HA9", "&HA8", "&H68", "&H78", "&HB8", "&HB9", "&H79", "&HBB", _
"&H7B", "&H7A", "&HBA", "&HBE", "&H7E", "&H7F", "&HBF", "&H7D", "&HBD", "&HBC", "&H7C", "&HB4", "&H74", "&H75", "&HB5", _
"&H77", "&HB7", "&HB6", "&H76", "&H72", "&HB2", "&HB3", "&H73", "&HB1", "&H71", "&H70", "&HB0", "&H50", "&H90", "&H91", _
"&H51", "&H93", "&H53", "&H52", "&H92", "&H96", "&H56", "&H57", "&H97", "&H55", "&H95", "&H94", "&H54", "&H9C", "&H5C", _
"&H5D", "&H9D", "&H5F", "&H9F", "&H9E", "&H5E", "&H5A", "&H9A", "&H9B", "&H5B", "&H99", "&H59", "&H58", "&H98", "&H88", _
"&H48", "&H49", "&H89", "&H4B", "&H8B", "&H8A", "&H4A", "&H4E", "&H8E", "&H8F", "&H4F", "&H8D", "&H4D", "&H4C", "&H8C", _
"&H44", "&H84", "&H85", "&H45", "&H87", "&H47", "&H46", "&H86", "&H82", "&H42", "&H43", "&H83", "&H41", "&H81", "&H80", _
"&H40")TestString = "010303E80002"CRCHi = &HFF: CRCLo = &HFFDim PP As StringFor I = 1 To Len(TestString) / 2 'Convert 2-characters hex into ByteCRCindex = CRCHi Xor Val("&H" + Mid$(TestString, I * 2 - 1, 2))PP = TABHi(CRCindex): CRCHi = CRCLo Xor Val(PP)PP = TABLo(CRCindex): CRCLo = Val(PP)
Next IText1.Text = Right$(("0" + Hex$(CRCHi)), 2) + Right$(("0" + Hex$(CRCLo)), 2)
End Sub
一、对码表的处理
C语言可以定义时初始化数组,VB则需要另想办法。可以从网上考贝C的码表,比如下表:
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
然后贴到VB里,用"&H 全部替换掉0x,再用 ", 全部替换掉 , 替换后的表是如下的样子。
TABHi() = Array( _
"&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", _
"&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", _
"&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", _
"&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", _
"&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", _
"&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", _
"&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", _
"&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", _
"&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", _
"&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", _
"&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", _
"&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", _
"&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", _
"&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", _
"&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", _
"&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", "&H40", "&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", _
"&H00", "&HC1", "&H81", "&H40", "&H01", "&HC0", "&H80", "&H41", "&H01", "&HC0", "&H80", "&H41", "&H00", "&HC1", "&H81", _
"&H40")TABLo() = Array( _
"&H00", "&HC0", "&HC1", "&H01", "&HC3", "&H03", "&H02", "&HC2", "&HC6", "&H06", "&H07", "&HC7", "&H05", "&HC5", "&HC4", _
"&H04", "&HCC", "&H0C", "&H0D", "&HCD", "&H0F", "&HCF", "&HCE", "&H0E", "&H0A", "&HCA", "&HCB", "&H0B", "&HC9", "&H09", _
"&H08", "&HC8", "&HD8", "&H18", "&H19", "&HD9", "&H1B", "&HDB", "&HDA", "&H1A", "&H1E", "&HDE", "&HDF", "&H1F", "&HDD", _
"&H1D", "&H1C", "&HDC", "&H14", "&HD4", "&HD5", "&H15", "&HD7", "&H17", "&H16", "&HD6", "&HD2", "&H12", "&H13", "&HD3", _
"&H11", "&HD1", "&HD0", "&H10", "&HF0", "&H30", "&H31", "&HF1", "&H33", "&HF3", "&HF2", "&H32", "&H36", "&HF6", "&HF7", _
"&H37", "&HF5", "&H35", "&H34", "&HF4", "&H3C", "&HFC", "&HFD", "&H3D", "&HFF", "&H3F", "&H3E", "&HFE", "&HFA", "&H3A", _
"&H3B", "&HFB", "&H39", "&HF9", "&HF8", "&H38", "&H28", "&HE8", "&HE9", "&H29", "&HEB", "&H2B", "&H2A", "&HEA", "&HEE", _
"&H2E", "&H2F", "&HEF", "&H2D", "&HED", "&HEC", "&H2C", "&HE4", "&H24", "&H25", "&HE5", "&H27", "&HE7", "&HE6", "&H26", _
"&H22", "&HE2", "&HE3", "&H23", "&HE1", "&H21", "&H20", "&HE0", "&HA0", "&H60", "&H61", "&HA1", "&H63", "&HA3", "&HA2", _
"&H62", "&H66", "&HA6", "&HA7", "&H67", "&HA5", "&H65", "&H64", "&HA4", "&H6C", "&HAC", "&HAD", "&H6D", "&HAF", "&H6F", _
"&H6E", "&HAE", "&HAA", "&H6A", "&H6B", "&HAB", "&H69", "&HA9", "&HA8", "&H68", "&H78", "&HB8", "&HB9", "&H79", "&HBB", _
"&H7B", "&H7A", "&HBA", "&HBE", "&H7E", "&H7F", "&HBF", "&H7D", "&HBD", "&HBC", "&H7C", "&HB4", "&H74", "&H75", "&HB5", _
"&H77", "&HB7", "&HB6", "&H76", "&H72", "&HB2", "&HB3", "&H73", "&HB1", "&H71", "&H70", "&HB0", "&H50", "&H90", "&H91", _
"&H51", "&H93", "&H53", "&H52", "&H92", "&H96", "&H56", "&H57", "&H97", "&H55", "&H95", "&H94", "&H54", "&H9C", "&H5C", _
"&H5D", "&H9D", "&H5F", "&H9F", "&H9E", "&H5E", "&H5A", "&H9A", "&H9B", "&H5B", "&H99", "&H59", "&H58", "&H98", "&H88", _
"&H48", "&H49", "&H89", "&H4B", "&H8B", "&H8A", "&H4A", "&H4E", "&H8E", "&H8F", "&H4F", "&H8D", "&H4D", "&H4C", "&H8C", _
"&H44", "&H84", "&H85", "&H45", "&H87", "&H47", "&H46", "&H86", "&H82", "&H42", "&H43", "&H83", "&H41", "&H81", "&H80", _
"&H40")
然后就可以定义 Dim TABLo(), TABHi()
定义后面什么也不用写,写上as string之类的就不能初始赋值了。另外,想换行的话就空格后下划线,这表就很清楚地可用了。
二、对传输字符串的处理
传送的字符串是十六进制的,二个字符构成一个字节,所以在循环读解字符串时要除以2,变成可用于计算机的字节(如果直接定义 Byte 数组一次性装入函数中也是可以的)。
For I = 1 To Len(TestString) / 2 'Convert 2-characters hex into ByteCRCindex = CRCHi Xor Val("&H" + Mid$(TestString, I * 2 - 1, 2))PP = TABHi(CRCindex): CRCHi = CRCLo Xor Val(PP)PP = TABLo(CRCindex): CRCLo = Val(PP)
Next I
注意一下除以2 和形成表索引时的 I*2-1
除了查表法,下面是计算法,也涉及到字符串拆解,供参考。
Private Sub Command1_Click()
Dim TestString
TestString = "010303E80002"
Dim CRC16High As Byte, CRC16Low As Byte, CalCRC16Hi As Byte, CalCRC16Lo As Byte
Dim I As Integer, J As Byte, defCRC16Hi As Byte, defCRC16Lo As ByteCRC16Low = &HFF
CRC16High = &HFFdefCRC16Hi = &HA0: defCRC16Lo = &H1For I = 0 To Len(TestString) / 2 - 1CRC16Low = CRC16Low Xor (Val("&H" + Mid$(TestString, I * 2 + 1, 2)))For J = 0 To 7CalCRC16Hi = CRC16HighCalCRC16Lo = CRC16LowCRC16High = CRC16High \ 2CRC16Low = CRC16Low \ 2If ((CalCRC16Hi And &H1) = &H1) ThenCRC16Low = CRC16Low Or &H80End IfIf ((CalCRC16Lo And &H1) = &H1) ThenCRC16High = CRC16High Xor defCRC16HiCRC16Low = CRC16Low Xor defCRC16LoEnd IfNext JNext IText1.Text = Hex$(CRC16Low) + Hex$(CRC16High)
End Sub
CRC16是做Modbus RTU编解绕不过去的重要环节,也是做工控必须掌握的,因为太多工业仪表、PLC都用这协议,是不以个人意志为转移的。