Modbus TCP Protocol
Introduction
The Modbus protocol is a messaging structure which was developed by Modicon in 1979, and later released as an open and free-to-use standard. The full standards documents can be downloaded from modbus.org for reference.
There are several variants of the protocol, which use the same basic messages encapsulated in different ways for transfer over serial lines (Modbus RTU and Modbus ASCII) or TCP/IP networks (Modbus TCP).
Modbus is a query-response protocol. Master devices send out query messages, and slave devices send back a response message for each query addressed to them. In the case of Modbus TCP, the slave device is a TCP/IP server which waits for a connection to be made to it (e.g. a Brainboxes ED device) and the master is the device which initiates the TCP connection (e.g. a PLC, HMI or PC).
Data Tables
Modbus organises the data to be transferred between devices into four address spaces or "data tables", each of which has 65536 addressable entries:
| Data Table | Description |
|---|---|
| Discrete inputs | Single-bit (Boolean) values which can only be read |
| Coils | Single-bit (Boolean) values which can be written as well as read |
| Input registers | 16-bit values which can only be read |
| Holding registers | 16-bit values which can be written as well as read |
The Modbus standard does not specify how inputs and outputs should be related to addresses in these data tables, or how the values inside the 16-bit registers should be structured. These are up to each manufacturer to decide.
Supported Function Codes
| Address Space | Read | Write Single | Write Multiple |
|---|---|---|---|
| Discrete inputs | 2 | - | - |
| Coils | 1 | 5 | 15 |
| Input registers | 4 | - | - |
| Holding registers | 3 | 6 | 16 |
Slave ID
As well as the addresses for the inputs, coils, and registers of a device, there is also an "address" to identify a particular Modbus slave, known as the Slave ID or Unit Identifier. In Modbus TCP the Slave ID is somewhat redundant as the destination of the message is already defined by the IP address of the TCP packet. Brainboxes devices can be configured to either:
- Respond to Slave IDs 0 and 255 only (as required by the Modbus TCP specification)
- Respond to any valid Slave ID (0 to 247, and 255) for convenience
Addressing Notations
The long history of Modbus has resulted in several common ways for data addresses to be written. When setting up other devices or software to communicate with Brainboxes Modbus TCP products, you will need to identify the type of address notation being used.
Logical Addressing
Within Modbus messages, addresses are 16-bit values (0 to 65535). The Logical address is this number expressed in hexadecimal. Each type of addressable object has its own independent address space. When using logical addressing, the type of object always needs to be stated as well. Logical addresses are written as hexadecimal with a '0x' prefix.
984 Style Addressing
This notation (named after an early Modicon controller model) is widely used. The address is written in decimal with an offset of 1 from the logical address, padded to 4 digits, then a prefix digit indicates the address space:
| 984 Addresses | Type | Logical Addresses |
|---|---|---|
| 00001-09999 | Coil | 0-9998 (0x0000-0x270E) |
| 10001-19999 | Discrete input | 0-9998 (0x0000-0x270E) |
| 30001-39999 | Input register | 0-9998 (0x0000-0x270E) |
| 40001-49999 | Holding register | 0-9998 (0x0000-0x270E) |
The prefix is sometimes written as shorthand: '0x' for coils, '1x' for discrete inputs, '3x' for input registers, '4x' for holding registers.
IEC 61131 Addressing
Some PLCs and HMIs use IEC 61131 notation. %M addresses refer to coils, %MW addresses refer to holding registers. This format cannot represent read-only types.
| IEC 61131 Addresses | Type | Logical Addresses |
|---|---|---|
| %M0-%M65535 | Coil | 0-65535 |
| %MW0-%MW65535 | Holding register | 0-65535 |
Modbus 1.1b3 Standard Addressing
The latest Modbus standard uses addresses starting at 1 (logical address plus 1). The object type must be stated separately.
ED-549 Data Tables
| Function | Modbus Type | Function Codes | Logical Address | 984 Address | IEC 61131 |
|---|---|---|---|---|---|
| Analogue inputs (integer) | Holding register | 3 | 0x0000-7 | 40001-8 | %MW0-7 |
| Analogue inputs (integer) | Input register | 4 | 0x0000-7 | 30001-8 | N/A |
| Analogue inputs (float) | Holding register | 3 | 0x0020-7 | 40033-40 | %MF32-39 |
| Analogue inputs (float) | Input register | 4 | 0x0020-7 | 30033-40 | N/A |
| Input error flags | Discrete input | 2 | 0x0400-7 | 11025-1032 | N/A |
| Input error flags | Input register | 4 | 0x0400 | 31025 | N/A |
| Input error flags | Holding register | 3 | 0x0400 | 41025 | %MW1024 |
| Input channel enable | Holding register | 3, 6, 16 | 0x0040 | 40065 | %MW64 |
| Input channel enable | Coil | 1, 5, 15 | 0x0040-7 | 00065-72 | %M64-71 |
| Input type/range | Holding register | 3, 6, 16 | 0x0060-7 | 40097-104 | %MW96-103 |
| Integer format | Holding register | 3, 6, 16 | 0x0080 | 40129 | %MW128 |
| Integer format | Coil | 1, 5, 15 | 0x0080 | 00129 | %M128 |
ED-549 Integer Value Encoding
Integer values are encoded in one of two formats:
Hexadecimal format (integer format register = 0, coil OFF):
- Input range scaled to fill 16-bit integer range
- 2's complement for bipolar ranges
- Unsigned for unipolar ranges
Engineering units format (integer format register = 1, coil ON):
- Measurement in mA, mV or V scaled by power of 10
- Scaled as high as possible while fitting in 16-bit register
ED-549 Floating-Point Values
- Encoded as IEEE 754 32-bit floating-point
- Uses two sequential 16-bit registers
- Least-significant bits in lower register address (little-endian)
- Both registers must be read in the same Modbus request
- Units are Volts or milliAmps
ED-549 Range Codes and Data Ranges
| Type Code | Input Type | Float +FS | Float -FS | Int Hex +FS | Int Hex -FS | Int Eng +FS | Int Eng -FS |
|---|---|---|---|---|---|---|---|
| 05 | +/-2.5V | +2.5 | -2.5 | 32767 | -32768 | 25000 | -25000 |
| 06/0D | +/-20mA | +20.0 | -20.0 | 32767 | -32768 | 20000 | -20000 |
| 07 | +4 to +20mA | +20.0 | +4.0 | 65535 | 0 | 20000 | 4000 |
| 08 | +/-10V | +10.0 | -10.0 | 32767 | -32768 | 10000 | -10000 |
| 09 | +/-5V | +5.0 | -5.0 | 32767 | -32768 | 5000 | -5000 |
| 04/0A | +/-1V | +1.0 | -1.0 | 32767 | -32768 | 10000 | -10000 |
| 03/0B | +/-500mV | +500.0 | -500.0 | 32767 | -32768 | 5000 | -5000 |
| 0C | +/-150mV | +150.0 | -150.0 | 32767 | -32768 | 15000 | -15000 |
| 1A | 0 to +20mA | +20.0 | +0.0 | 65535 | 0 | 20000 | 0 |
| 3A | +/-75mV | +75.0 | -75.0 | 32767 | -32768 | 7500 | -7500 |
| 3B | +/-250mV | +250.0 | -250.0 | 32767 | -32768 | 25000 | -25000 |
Under-range inputs result in a reading equal to the -Full Scale value. Over-range inputs result in a reading equal to the +Full Scale value.
ED-560 Data Tables
| Function | Modbus Type | Function Codes | Logical Address | 984 Address | IEC 61131 |
|---|---|---|---|---|---|
| Analogue outputs (integer) | Holding register | 3, 6, 16 | 0x0000-3 | 40001-4 | %MW0-3 |
| Analogue outputs (float) | Holding register | 3, 16 | 0x0020-7 | 40033-40 | %MF32-39 |
| Analogue type/range | Holding register | 3, 6, 16 | 0x0060-3 | 40097-100 | %MW96-99 |
| Integer format | Holding register | 3, 6, 16 | 0x0080 | 40129 | %MW128 |
| Integer format | Coil | 1, 5, 15 | 0x0080 | 00129 | %M128 |
ED-560 Integer Value Encoding
Hexadecimal format (integer format register = 0, coil OFF):
- Output range scaled to 0-16383 (0x3FFF)
Engineering units format (integer format register = 1, coil ON):
- Output in mA or V scaled by power of 10
ED-560 Floating-Point Values
- Same encoding as ED-549 (IEEE 754 32-bit, little-endian)
- Both registers must be written/read in same request
- Units are Volts or milliAmps
ED-560 Range Codes and Data Ranges
| Type Code | Output Type | Float +FS | Float Min | Int Hex +FS | Int Hex Min | Int Eng +FS | Int Eng Min |
|---|---|---|---|---|---|---|---|
| 30 | 0 to +20mA | 20.0 | 0.0 | 16383 | 0 | 20000 | 0 |
| 31 | +4 to +20mA | 20.0 | 4.0 | 16383 | 0 | 20000 | 4000 |
| 32 | 0 to +10V | 10.0 | 0.0 | 16383 | 0 | 10000 | 0 |
Writing values below the minimum results in the minimum output. Writing values above the maximum results in the maximum output.