Last active
January 21, 2024 09:33
-
-
Save deldrid1/3839697 to your computer and use it in GitHub Desktop.
Two different Methods for calculating Modbus CRC's using the Electric Imp.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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