PDA

View Full Version : ModBus RTU CRC


Cobra_Phil
06-25-2010, 11:33 AM
I thought I would share with everyone a routine to calculate the ModBus CRC value. Snippets of code were pulled from this forum among other places. I don't really understand why this is needed, but it works in all the scenarios I have tested.

if crc < 0:
crc -= 256

I am brand new to programming in python. So, be kind. I'm open to suggestions if something can be done better or faster.

def CRC16(Output):
crc = 0xFFFF
l = len(Output)
i = 0
while i < l:
j = 0
crc = crc ^ ord(Output[i])
while j < 8:
if (crc & 0x1):
mask = 0xA001
else:
mask = 0x00
crc = ((crc >> 1) & 0x7FFF) ^ mask
j += 1
i += 1
if crc < 0:
crc -= 256
print Output + chr(crc % 256) + chr(crc / 256)

gre7g
06-25-2010, 04:45 PM
That's excellent! A very handy script to have.

I had to calculate a Modbus-CRC earlier on an Atmel-based engine (RF200) and so I went the embedded-C route, to get a little extra speed. I suspect this code would work on other engines, but I've only tested it on the 200.

Note that to use this script, you add two characters onto your string and then call this function. It replaces the last two characters inline with the proper CRC value.

// Take the packet string, add two characters (any value), and pass to the
// Python calc_crc(packet) function. This will replace those two characters with
// the calculated CRC value.
void calc_crc(U8 num_args, U8 *snappy_stack, void *reserved)
{
U16 crc = 0xFFFF;
U8 *str, len, c, i;

// Fetch a pointer to str from
str = (U8 *) ((snappy_stack[-1] << 8) | snappy_stack[-2]);
len = *str++;

// Calculate CRC
while (len-- > 2)
{
c = *str++;
for (i = 8; i; i--)
{
if ((c ^ crc) & 1)
crc = (crc >> 1) ^ crc_poly;
else
crc >>= 1;
c >>= 1;
}
}

// Save CRC in string & return it as a TC_INT
snappy_stack[-7] = *str = crc >> 8;
snappy_stack[-8] = *str++ = crc & 0xFF;
snappy_stack[-9] = TC_INT;
}