Skip to content

Instantly share code, notes, and snippets.

@deldrid1
Last active January 21, 2024 09:33
Show Gist options
  • Save deldrid1/3839697 to your computer and use it in GitHub Desktop.
Save deldrid1/3839697 to your computer and use it in GitHub Desktop.
Two different Methods for calculating Modbus CRC's using the Electric Imp.
//Two Different methods of calculating Modbus's CRC16
//You can use http://www.lammertbies.nl/comm/info/crc-calculation.html to verify the calculation. Change Input Mode to Hex and input the string "0103" This is for Modbus CRC's.
imp.configure ("CRC Calculation", [], []);
server.log("============ PROGRAM START =============")
/*******************************************************************************
HELPER FUNCTIONS
*******************************************************************************/
function byteArrayString(arr){
local str = ""
for(local i = 0; i < arr.len(); i++){
if(arr[i] == null) break;
str = str + format("%.2X", arr[i]);
}
return str;
}
function hexConvert(val, len){ //Takes a numeric hex (0x1234) or int value and returns a string len bytes long with hex values
return format("%." + (len*2) + "X", val)
}
function lowByte(w) {
return w & 0xff
}
function highByte(w) {
return w >> 8
}
//Variable used by the two calculations
local u8ModbusADU = [0x01, 0x03];
/*******************************************************************************
Example 1 - Translated from the Modbus Library for Arduino - Arduino Programming Language Implementation
http://arduino.cc/playground/Code/ModbusMaster
https://github.com/2-718/ModbusMaster/blob/master/ModbusMaster.cpp
This code calculates the CRC so may be slower but uses less memory
*******************************************************************************/
function _crc16_update(crc, a)
{
crc = crc ^ a;
for (local i = 0; i < 8; ++i)
{
if (crc & 1)
crc = (crc >> 1) ^ 0xA001;
else
crc = (crc >> 1);
}
return crc;
}
/**
Modbus transaction engine.
Sequence:
- assemble Modbus Request Application Data Unit (ADU),
based on particular function called
- transmit request over selected serial port
- wait for/retrieve response
- evaluate/disassemble response
- return status (success/exception)
@param u8MBFunction Modbus function (0x01..0xFF)
@return 0 on success; exception number on failure*/
function ModbusMasterTransaction(_u8MBSlave, u8MBFunction)
{
local u8ModbusADU = array(256)
local u8ModbusADUSize = 0;
local i, u8Qty;
local u16CRC;
local u8BytesLeft = 8;
// assemble Modbus Request Application Data Unit
//Frame Format is | 8-bit Address | 8-bit Function | n*8-bits Data+Length | 16-bit CRC |
u8ModbusADU[u8ModbusADUSize++] = _u8MBSlave;
u8ModbusADU[u8ModbusADUSize++] = u8MBFunction;
u16CRC = 0xFFFF;
for (i = 0; i < u8ModbusADUSize; i++)
{
u16CRC = _crc16_update(u16CRC, u8ModbusADU[i]);
}
u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC);
u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC);
return byteArrayString([highByte(u16CRC), lowByte(u16CRC)])
}
server.log("Example 1 calculated CRC = 0x" + ModbusMasterTransaction(u8ModbusADU[0], u8ModbusADU[1])) //Example 1
/*******************************************************************************
Example 2 - Translated from MODBUS over serial line specification and implementation guide V1.02 (Appendix B)- C Implementation
http://modbus.com/docs/Modbus_over_serial_line_V1_02.pdf
This code uses a lookup table so should be faster but uses more memory
*******************************************************************************/
// blob of CRC values for high–order byte
const auchCRCHi = "\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40";
// blob of CRC values for low–order byte
const auchCRCLo = "\x00\xC0\xC1\x01\xC3\x03\x02\xC2\xC6\x06\x07\xC7\x05\xC5\xC4\x04\xCC\x0C\x0D\xCD\x0F\xCF\xCE\x0E\x0A\xCA\xCB\x0B\xC9\x09\x08\xC8\xD8\x18\x19\xD9\x1B\xDB\xDA\x1A\x1E\xDE\xDF\x1F\xDD\x1D\x1C\xDC\x14\xD4\xD5\x15\xD7\x17\x16\xD6\xD2\x12\x13\xD3\x11\xD1\xD0\x10\xF0\x30\x31\xF1\x33\xF3\xF2\x32\x36\xF6\xF7\x37\xF5\x35\x34\xF4\x3C\xFC\xFD\x3D\xFF\x3F\x3E\xFE\xFA\x3A\x3B\xFB\x39\xF9\xF8\x38\x28\xE8\xE9\x29\xEB\x2B\x2A\xEA\xEE\x2E\x2F\xEF\x2D\xED\xEC\x2C\xE4\x24\x25\xE5\x27\xE7\xE6\x26\x22\xE2\xE3\x23\xE1\x21\x20\xE0\xA0\x60\x61\xA1\x63\xA3\xA2\x62\x66\xA6\xA7\x67\xA5\x65\x64\xA4\x6C\xAC\xAD\x6D\xAF\x6F\x6E\xAE\xAA\x6A\x6B\xAB\x69\xA9\xA8\x68\x78\xB8\xB9\x79\xBB\x7B\x7A\xBA\xBE\x7E\x7F\xBF\x7D\xBD\xBC\x7C\xB4\x74\x75\xB5\x77\xB7\xB6\x76\x72\xB2\xB3\x73\xB1\x71\x70\xB0\x50\x90\x91\x51\x93\x53\x52\x92\x96\x56\x57\x97\x55\x95\x94\x54\x9C\x5C\x5D\x9D\x5F\x9F\x9E\x5E\x5A\x9A\x9B\x5B\x99\x59\x58\x98\x88\x48\x49\x89\x4B\x8B\x8A\x4A\x4E\x8E\x8F\x4F\x8D\x4D\x4C\x8C\x44\x84\x85\x45\x87\x47\x46\x86\x82\x42\x43\x83\x41\x81\x80\x40";
function CRC16 ( puchMsg, usDataLen ){
//unsigned char *puchMsg ; // message to calculate CRC upon
//unsigned short usDataLen ; // quantity of bytes in message
local uchCRCHi = 0xFF ; // high byte of CRC initialized
local uchCRCLo = 0xFF ; // low byte of CRC initialized
local uIndex ; // will index into CRC lookup table
local i = 0;
while (usDataLen--){ // pass through message buffer
uIndex = uchCRCLo ^ puchMsg[i] ; // calculate the CRC
uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex] ;
uchCRCHi = auchCRCLo[uIndex] ;
i++
}
return (uchCRCHi << 8 | uchCRCLo) ;
}
server.log("Example 2 calculated CRC = 0x" + hexConvert(CRC16(u8ModbusADU, 2),2)); //Example 2
server.log("============ EOF =============")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment