Modbus CRC

D

Thread Starter

Daniel Santoso

I am a Modbus beginner and I need to calculate the CRC for a modbus command to a slave. The CRC examples I found are not clear to me and they seem to conflict with each other.

Can you give a hint where to find a good and valid example how to calculate CRC, preferably in Visual Basic?
 
<p>There are two simple ways to do this. Both are described in the book PI-MBUS-300 REV J.

<p>1. table lookup (memory hog)

<p>2. long division (looping 8 times per byte and processing with the generating polynomial GPOLY = 0xA001)

<p>For a fresh packet, set the CRC value to 0xFFFF to start.

<p>Here is how I do it, in C:<pre>
_______________________________________________

#define GPOLY 0xA001
#define SEED 0xFFFF

typedef struct {
int head; //the first byte pointer
int tail; //the last byte pointer
int n;//number of bytes in buff[]
unsigned short int CRC16;
byte buff[MAXBUFF];
} BFR;

void CRC16(BFR* b)
{//called after placing one byte into b->buff[] using Put(BFR* b), result left in b->CRC16
int i;

if (b->n==1)
{//setup the default seed for new buff input
b->CRC16 = SEED;
}

b->CRC16 ^= b->buff[b->tail];

for (i=0;i<8;i++)
{
if (b->CRC16 & 0x01)
{
b->CRC16 >>= 1;
b->CRC16 ^= GPOLY;
}
else
{
b->CRC16 >>= 1;
}
}
}
</pre>
 
<p>Assuming your source message is stored in a byte array, you can calculate the CRC16 using the following function.
<pre>
---
Function CRC16(Message() As Byte) As Integer
Dim I As Long, J As Long, Odd As Boolean
CRC16 = -1
For I = 0 To UBound(Message)
CRC16 = (CRC16 And &HFF00) Or ((CRC16 And 255) Xor Message(I))
For J = 1 To 8
Odd = CRC16 And 1
CRC16 = ((CRC16 And &HFFFE) \ 2) And &H7FFF 'shift right
If Odd Then CRC16 = &HA001 Xor CRC16
Next
Next
End Function
---
</pre>
<p>You shall use this function like this.
intCRC16 = CRC16(Buffer())
where Buffer() represents a byte array.

<p>If your source message is stored in a string, instead of a byte array, you can still use this function converting the string message into a byte array on-the-fly...
<pre>
intCRC16 = CRC16(StrConv(SourceString$, vbFromUnicode))
</pre>
<p>StrConv function returns a byte array based on source string and passes it to CRC16 function.
 
D

David Gibson, SPLat Controls

Here's the code I use:

<pre>
Function CRC(Message$) As Long
'Picked up off the web, tidied up slightly.
'' CRC runs cyclic Redundancy Check Algorithm on input message$
'' Returns value of 16 bit CRC after completion and
'' ************ always adds 2 crc bytes to message **********************
'' returns 0 if incoming message has correct CRC
'' Must use double word for CRC and decimal constants

Dim CRC16 As Long, C%, bit%, crch%, crcl%
CRC16& = 65535
For C% = 1 To Len(Message$)
CRC16& = CRC16& Xor Asc(Mid$(Message$, C%, 1))
For bit% = 1 To 8
If CRC16& Mod 2 Then
CRC16& = (CRC16& \ 2) Xor 40961
Else
CRC16& = CRC16& \ 2
End If
Next bit%
Next C%
crch% = CRC16& \ 256: crcl% = CRC16& Mod 256
Message$ = Message$ + Chr$(crcl%) + Chr$(crch%)
CRC = CRC16&
End Function
</pre>

I think the one you posted may have a problem in using INTs instead of LONGs. INTs are 16 bit <i>signed</> numbers, and run into grief when used as unsigned binary numbers.

David Gibson, SPLat Controls www.splatco.com
 
Top