Resources Modbus Application Protocol

Describes function codes Modbus over Serial Line Specification and Implementation Guide

Register Addressing

The Modbus register number should really be thought of as an offset rather than an address, as different vendors can use different register addressing schemes.  Firstly registers may start from 0 for some devices and 1 for others. The register addressing always starts from 0 in the Modbus protocol, but for some devices such as PLC’s it may refer to address 1.  Modbus also uses tables to hold different values and the modbus address sent is an offset within the particular table:

Coil/Register Numbers   Data Addresses   Type           Table Name
1-9999                  0000 to 270E     Read-Write     Discrete Output Coils
10001-19999             0000 to 270E     Read-Only      Discrete Input Contacts
30001-39999             0000 to 270E     Read-Only      Analog Input Registers
40001-49999             0000 to 270E     Read-Write     Analog Output Holding Registers

So, using command which accesses Analog Output Holding Register 40001 is accomplished by specifying register number 0 in the modbus register number field.

A good way to specify register numbers to avoid potential for confusion:
  Register 99, Address 40100

Function Codes / Message Type

Message Type   Action           Table Name
0x01           Read             Discrete Output Coils
0x02           Read             Discrete Input Contacts
0x03           Read             Analog Output Holding Registers
0x04           Read             Analog Input Registers
0x05           Write single     Discrete Output Coil
0x06           Write single     Analog Output Holding Register
0x10           Write multiple   Analog Output Holding Registers
0x0F           Write multiple   Discrete Output Coils

Data Types

A register is 16 bits and can store the following:

A 16-bit unsigned integer
A 16-bit signed integer
A two character ASCII string
A discrete on/off value

To store larger values, for instance 32bit values, float values, ASCII strings, etc simply use successive registers.

Byte Ordering

The Modbus specification doesn’t define exactly how the data is stored in the registers. Some manufacturers use HighByte|LowByte and others use LowByte|HighByte.

Similarly when registers are combined to represent 32-bit data types some devices store the high 16 bits in the first register and the remaining low word in the second while others do the opposite.

CRC (Cyclic Redundancy Check)

If a slave receives a packet with an invalid CRC no response should be sent.

How to calculate the CRC:

const UINT16 CRCTable[] = {
   0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
   0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
   0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
   0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
   0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
   0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
   0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
   0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
   0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
   0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
   0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
   0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
   0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
   0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
   0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
   0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
   0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
   0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
   0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
   0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
   0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
   0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
   0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
   0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
   0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
   0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
   0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
   0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
   0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
   0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
   0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
   0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 };

UINT16 ModbusCalculateCrc (BYTE *pTxBuffer, WORD Length)
	unsigned char ucTemp;
	UINT16 CrcWord = 0xFFFF;

	while (Length--)
		ucTemp = (*pTxBuffer++) ^ (BYTE)(CrcWord & 0x00ff);
		CrcWord >>= 8;
		CrcWord  ^= CRCTable[ucTemp];

 Modbus RTU Exception Error Response

The function Code byte value is returned with bit 7 set to indicate exception.

Following this a exception code is sent:

0x01  Illegal Function (The function code received in the query is not an allowable action for the slave)
0x02  Illegal Data Address (The data address received in the query is not an allowable address for the slave)
0x03  Illegal Data Value (A value contained in the query data field is not an allowable value for the slave)
0x04  Slave Device Failure (An unrecoverable error occurred while the slave was attempting to perform the requested action)
0x05  Acknowledge
0x06  Slave Device Busy
0x07  Negative Acknowledge (the slave cannot perform the program function received in the query)
0x08  Memory Parity Error
0x0A  Gateway Path Unavailable
0x0B  Gateway Target Device Failed to Respond

For example for a failed read of a word (16 bits) from a register the following is sent:

Byte 1 Modbus Device Address (1 to 247)
Byte 2 Function Code / Message Type (0x03)
Byte 3 Register Number (high byte)
Byte 4 Register Number (low byte)
Byte 5 Data Length (high byte, specified in Words)
Byte 6 Data Length (low byte)
Byte 7 CRC of bytes 1 to 6 (high byte)
Byte 8 CRC of bytes 1 to 6 (low byte)

And this is returned

Byte 1 Modbus Device Address
Byte 2 Function Code / Message Type (0x83)
Byte 3 The Exception Code
Byte 4 CRC of bytes 1 to 5 (high byte)
Byte 5 CRC of bytes 1 to 5 (low byte)
We benefit hugely from resources on the web so we decided we should try and give back some of our knowledge and resources to the community by opening up many of our company’s internal notes and libraries through mini sites like this. We hope you find the site helpful.
Please feel free to comment if you can add help to this page or point out issues and solutions you have found, but please note that we do not provide support on this site. If you need help with a problem please use one of the many online forums.


Your email address will not be published.