![]() ![]() |
Looking for sample code of how to produce and decode modbus CRC in VB
![]() ![]() |
Here is an example of Modbus CRC calculation in VB (tested with success).
Enjoy.
Pascal
'-------------------------------------------------
Public Function CRC(buf() As Byte, lbuf As Integer) As Integer
'-------------------------------------------------
' returns the MODBUS CRC of the lbuf first bytes of "buf" buffer (buf is a global array of bytes)
Dim CRC1 As Integer
CRC1 = &HFFFF ' init CRC
For i = 0 To lbuf - 1 Step 1 ' for each byte
CRC1 = CRC1 Xor buf(i)
For j = 0 To 7 Step 1 ' for each bit
k = CRC1 And 1 ' memo bit 0 state
CRC1 = ((CRC1 And &HFFFE) / 2) And H7FFF ' Shift right with 0 at left
If k > 0 Then CRC1 = CRC1 Xor &HA001 ' Bocuse
Next j
Next i
CRC = CRC1
End Function
Enjoy.
Pascal
'-------------------------------------------------
Public Function CRC(buf() As Byte, lbuf As Integer) As Integer
'-------------------------------------------------
' returns the MODBUS CRC of the lbuf first bytes of "buf" buffer (buf is a global array of bytes)
Dim CRC1 As Integer
CRC1 = &HFFFF ' init CRC
For i = 0 To lbuf - 1 Step 1 ' for each byte
CRC1 = CRC1 Xor buf(i)
For j = 0 To 7 Step 1 ' for each bit
k = CRC1 And 1 ' memo bit 0 state
CRC1 = ((CRC1 And &HFFFE) / 2) And H7FFF ' Shift right with 0 at left
If k > 0 Then CRC1 = CRC1 Xor &HA001 ' Bocuse
Next j
Next i
CRC = CRC1
End Function
![]() ![]() |
Thanks for posting this function! I needed to communicate with a Modbus unit and was having trouble getting the checksum right .... Your code works GREAT.
Terry V. Shores
Terry V. Shores
![]() ![]() |
Thanks for the post it is very useful to me in modbus programming.
![]() ![]() |
Here is the routine that I use in Basic-X which is a subset of VB. Changing the variable types should be all thats required to make it run in VB. I start by setting iCurrentCRC (module level variable) to FFFF. As I assemble each byte of the Modbus message, I pass each byte thrugh this routine. Once the message is complete, the iCurrentCRC is appended to the end of the message in this order:
(iCurrentCRC Mod 256)
(iCurrentCRC \ 256)
Good luck!
Brad Watts.
Public Sub GetCRC(ByVal bValue As Byte)
Dim iValue As New UnsignedInteger
Dim CRCTemp As New UnsignedInteger
Dim Bit As Byte
iValue = CuInt(bValue)
CRCTemp = iCurrentCRC Xor iValue
For Bit = 0 To 7
If (CRCTemp And 1) = 1 Then
CRCTemp = CRCTemp \ 2
CRCTemp = CRCTemp Xor 40961
Else
CRCTemp = CRCTemp \ 2
End If
Next
iCurrentCRC = CRCTemp
End Sub
(iCurrentCRC Mod 256)
(iCurrentCRC \ 256)
Good luck!
Brad Watts.
Public Sub GetCRC(ByVal bValue As Byte)
Dim iValue As New UnsignedInteger
Dim CRCTemp As New UnsignedInteger
Dim Bit As Byte
iValue = CuInt(bValue)
CRCTemp = iCurrentCRC Xor iValue
For Bit = 0 To 7
If (CRCTemp And 1) = 1 Then
CRCTemp = CRCTemp \ 2
CRCTemp = CRCTemp Xor 40961
Else
CRCTemp = CRCTemp \ 2
End If
Next
iCurrentCRC = CRCTemp
End Sub
![]() ![]() |
My VB code for CRC16 is at: http://www.robustdc.com/crc_vb.txt
Since VB doesn't have the concept of unsigned 16-bit int, you must do all in LONGS and spend a lot of time masking this to 16-bit.
Best Regards
Lynn August Linse, LynnL@digi.com
IA Firmware Specialist, Digi Int'l (www.digi.com)
Board Member, The Modbus Organization (www.modbus.org)
Since VB doesn't have the concept of unsigned 16-bit int, you must do all in LONGS and spend a lot of time masking this to 16-bit.
Best Regards
Lynn August Linse, LynnL@digi.com
IA Firmware Specialist, Digi Int'l (www.digi.com)
Board Member, The Modbus Organization (www.modbus.org)
![]() ![]() |
For those that may be interested, here's a more compact way to create the crc table in VB.
Dim usCRC(0 To 255) As Long
Sub mbus_FillCRCTable()
usCRC(0) = &H0: usCRC(1) = &HC0C1: usCRC(2) = &HC181: usCRC(3) = &H140
usCRC(4) = &HC301: usCRC(5) = &H3C0: usCRC(6) = &H280: usCRC(7) = &HC241
For i = 0 To 127
If i < 8 Then usCRC(8 + i) = usCRC(i) Xor &HC601 ' 8 through 15
If i < 16 Then usCRC(16 + i) = usCRC(i) Xor &HCC01 '16 through 31
If i < 32 Then usCRC(32 + i) = usCRC(i) Xor &HD801 '32 through 63
If i < 64 Then usCRC(64 + i) = usCRC(i) Xor &HF001 '64 through 127
usCRC(128 + i) = usCRC(i) Xor &HA001 '128 through 255
Next
End Sub
Dim usCRC(0 To 255) As Long
Sub mbus_FillCRCTable()
usCRC(0) = &H0: usCRC(1) = &HC0C1: usCRC(2) = &HC181: usCRC(3) = &H140
usCRC(4) = &HC301: usCRC(5) = &H3C0: usCRC(6) = &H280: usCRC(7) = &HC241
For i = 0 To 127
If i < 8 Then usCRC(8 + i) = usCRC(i) Xor &HC601 ' 8 through 15
If i < 16 Then usCRC(16 + i) = usCRC(i) Xor &HCC01 '16 through 31
If i < 32 Then usCRC(32 + i) = usCRC(i) Xor &HD801 '32 through 63
If i < 64 Then usCRC(64 + i) = usCRC(i) Xor &HF001 '64 through 127
usCRC(128 + i) = usCRC(i) Xor &HA001 '128 through 255
Next
End Sub
![]() ![]() |
I had the same problem when dealing with VB and unsigned ints. During my bit shifting I used the "/" sign for the division. I noticed in Brad's code that he used the other "\" sign. I changed it and this corrected my overflow problems immediately!
![]() ![]() |
Better to use two Bytes to hold the lo and hi parts of the CRC, then you don't have to mask the longs.
Your use of this site is subject to the terms and conditions set forth under Legal Notices and the Privacy Policy. Please read those terms and conditions carefully. Subject to the rights expressly reserved to others under Legal Notices, the content of this site and the compilation thereof is © 1999-2013 Nerds in Control, LLC. All rights reserved.
Users of this site are benefiting from open source technologies, including PHP, MySQL and Apache. Be happy.
Fortune
Boren's Laws:
(1) When in charge, ponder.
(2) When in trouble, delegate.
(3) When in doubt, mumble.









