Modbus
Overview
Modbus is a communication protocol used to connect industrial electronic devices
This page briefly explains Modbus frames
At the end of this page there is a link to an application for communication testing
Type
- Modbus-ASCII
- Modbus-RTU
- Modbus-TCP
About Addresses
Modbus uses four kinds of addresses
| Type | Address range | Data type |
| Coil | 1-9999 | 1bit |
| Input Status | 10001-19999 | 1bit |
| Input Register | 30001-39999 | 16bit |
| Holding Register | 40001-49999 | 16bit |
Message Frames
Modbus-ASCII
Modbus-ASCII is a character string message communicated over RS-422 or RS-485
Message frame that reads 2 values starting at holding register 40001
Send message
| Header | Slave address | Function | Data | LRC | Footer |
| | | Address | Count | | |
| ":" | "01" | "03" | "0000" | "0002" | "FA" | CR+LF |
| 1 char | 2 chars | 2 chars | 4 chars | 4 chars | 2 chars | 2 chars |
Receive message
| Header | Slave address | Function | Number of bytes received |
Data 1 | Data 2 | LRC | Footer |
| | | | High | Low | High | Low | | |
| ":" | "01" | "03" | "06" | "00" | "01" | "00" | "02" | "F3" | CR+LF |
| 1 char | 2 chars | 2 chars | 2 chars | 2 chars | 2 chars | 2 chars | 2 chars | 2 chars | 2 chars |
LRC Calculation
Convert the characters from the slave address to the data into numbers (hex), sum them, and take the two's complement of the lower 2 digits (+1)
In the example above, 0+1+0+3+0+0+0+0+0+0+0+2=6, and its two's complement +1 should be "FA"
Example of reading 2 values from address 40017
The address is 4017-40001=16 (0x0010) and the count is 2 (0x0002), so
0+1+0+3+0+0+1+0+0+0+0+2=7 (0x07), and its two's complement +1 should be "F9"
(in hex: 0x00+0x01+0x00+0x03+0x00+0x00+0x01+0x00+0x00+0x00+0x00+0x02)
Example of reading 20 values from address 40201
The address is 40201-40001=200 (0x00C8) and the count is 20 (0x0014), so
0+1+0+3+0+0+12+8+0+0+1+4=29 (0x1D), and its two's complement +1 should be "E3"
(in hex: 0x00+0x01+0x00+0x03+0x00+0x00+0x0C+0x08+0x00+0x00+0x01+0x04)
Modbus-RTU
Modbus-RTU is a binary message communicated over RS-422 or RS-485
Send message
| Header | Slave address | Function | Data | CRC | Footer |
| | | Address | Count | | |
| (*1) | 0x01 | 0x03 | 0x00 0x00 | 0x00 0x02 | 0xC4 0x0B | (*1) |
| 1byte | 1byte | 2byte | 2byte | 2byte (*2) | |
Receive message
| Header | Slave address | Function | Number of bytes received | Data 1 |
Data 2 | CRC | Footer |
| | | | High | Low | High | Low | | |
| (*1) | 0x01 | 0x03 | 0x06 | 0x00 | 0x01 | 0x00 | 0x02 | 0x53 0xF2 | (*1) |
| 1byte | 1 | 1 | 1 | 1 | 1 | 1 | 2 | |
*1) Silent interval of 3.5 characters (no communication)
*2) Low byte is sent first
CRC Calculation
CRC16 with right shift, initial value 0xFFFF, apparently no inversion...
You can calculate it with this app
Modbus-TCP
Modbus-TCP is a binary message communicated over Ethernet
Send message
| Transaction ID | Protocol ID | Number of bytes transferred | Unit ID | Function | Data |
| | | | | Address | Count |
| 0x00 0x00 | 0x00 0x00 | 0x00 0x06 | 0x01 | 0x03 | 0x00 0x00 | 0x00 0x02 |
| 2byte | 2byte | 2byte | 1byte | 1byte | 2byte | 2byte |
Receive message
| Transaction ID | Protocol ID | Number of bytes transferred | Unit ID | Function |
|   | | | | |
| 0x00 0x00 | 0x00 0x00 | 0x00 0x07 | 0x01 | 0x03 |
| 2byte |
2byte | 2byte | 1byte | 1byte |
| Number of bytes received | Data 1 | Data 2 |
| High | Low | High | Low |
| 0x04 | 0x00 | 0x01 | 0x00 | 0x02 |
| 1byte | 1byte | 1byte | 1byte | 1byte |
Function
List
| Function | Name | Functions |
| 01 | Read Coil Status | Reading coils |
| 02 | Read Input Status | Read discrete inputs |
| 03 | Read Holding Register | Read holding registers |
| 04 | Read Input Register | Read input registers |
| 05 | Force Single Coil | Write coil |
| 06 | Preset Single Register | Write holding register |
| 08 | Diagnostics | Diagnostics |
| 11(0x0B) | Fetch Communication Event Counter | Get comm event counter |
| 12(0x0C) | Fetch Communication Event Log | Get comm event log |
| 15(0x0F) | Force Multiple Coils | Write multiple coils |
| 16(0x10) | Force Multiple Registers | Write multiple registers |
| 17(0x11) | Report Slave ID | Report slave ID |
About addresses
To specify coil address 20, specify 19 (0x13), which is 20 minus 1
Likewise, input status, holding register and input register addresses are specified as the number minus 1
(01) Read Coil Status
Example of reading 20 coils starting at coil 1
Send message
| Function | Address | Count |
| 0x01 | 0x00 0x00 | 0x00 0x14 |
Receive message
| Function | Number of bytes received | Data 1-8 | Data 9-16 | Data 17-24 |
| 0x01 | 0x03 | 0x01 | 0x00 | 0x08 |
Bit order
Data is filled from the LSB (bit 0), and the remainder is padded with 0
Example: if coils 0 and 20 are ON, data 1-8 is 0x01 and data 17-24 is 0x08
(02) Read Input Status
Example of reading 20 input statuses starting at input status 20
Send message
| Function | Address | Count |
| 0x02 | 0x00 0x13 | 0x00 0x14 |
Receive message
| Function | Number of bytes received | Data 1-8 | Data 9-16 | Data 17-24 |
| 0x02 | 0x03 | 0x01 | 0x00 | 0x08 |
(03) Read Holding Register
Example of reading 3 values starting at holding register 20
Send message
| Function | Address | Count |
| 0x03 | 0x00 0x13 | 0x00 0x03 |
Receive message
| Function | Number of bytes received | Data 1 | Data 2 | Data 3 |
| 0x03 | 0x06 | 0x00 0x00 | 0x00 0x01 | 0x00 0x02 |
(04) Read Input Register
Example of reading 3 values starting at input register 20
Send message
| Function | Address | Count |
| 0x04 | 0x00 0x13 | 0x00 0x03 |
Receive message
| Function | Number of bytes received | Data 1 | Data 2 | Data 3 |
| 0x04 | 0x06 | 0x00 0x00 | 0x00 0x01 | 0x00 0x02 |
(05) Force Single Coil
Example of turning coil 20 ON
Send message
| Function | Address | Count |
| 0x05 | 0x00 0x13 | 0xFF 0x00 |
Receive message
| Function | Address | Data |
| 0x05 | 0x00 0x13 | 0xFF 0x00 |
How to specify data
0x00 0x00 = OFF, 0xFF 0x00 = ON
(06) Preset Single Register
Example of setting holding register 20 to 0x1234
Send message
| Function | Address | Data |
| 0x06 | 0x00 0x13 | 0x12 0x34 |
Receive message
| Function | Address | Data |
| 0x06 | 0x00 0x13 | 0x12 0x34 |
(08) Diagnostics
Example of returning an echo
Send message
| Function | Diagnostic subcode | Data |
| 0x08 | 0x00 0x00 | 0x12 0x34 |
Receive message
| Function | Diagnostic subcode | Data |
| 0x08 | 0x00 0x00 | 0x12 0x34 |
Diagnostic subcode
| Diagnostic subcode | Data | Functions |
| 0x00 0x00 | 0x?? 0x?? | Echo |
| 0x00 0x01 | 0x00 0x00 | Initialization |
| 0xFF 0x00 | Also clears the event log |
| 0x00 0x02 | 0x00 0x00 | Read diagnostic register |
| 0x00 0x04 | 0x00 0x00 | Read-only mode |
| 0x00 0x0A | 0x00 0x00 | Clear counters and diagnostic register |
| 0x00 0x0B | 0x00 0x00 | Read total messages |
| 0x00 0x0C | 0x00 0x00 | Read CRC error count |
| 0x00 0x0D | 0x00 0x00 | Read exception response count |
| 0x00 0x0E | 0x00 0x00 | Read received message count |
| 0x00 0x0F | 0x00 0x00 | Number of messages with no response returned |
| 0x00 0x11 | 0x00 0x00 | Slave busy exception response count |
| 0x00 0x12 | 0x00 0x00 | Character overrun count |
(11) Fetch Communication Event Counter
Example of reading the status word and event counter
Send message
| Function |
| 0x0B |
Receive message
| Function | Status | Event counter |
| 0x0B | 0x00 0x00 | 0x12 0x34 |
(12) Fetch Communication Event Log
Example of returning an echo
Send message
| Function |
| 0x0C |
Receive message
| Function | Byte count | Status |
| 0x0C | 0x08 | 0x00 0x00 |
| Event counter | Message counter | Event 0 | Event 1 |
| 0x12 0x34 | 0x12 0x34 | 0x20 | 0x00 |
(15) Force Multiple Coils
Example of changing the values of 10 coils starting at coil 20
Write data (20-29) = 1100 0000 01
Send message
| Function | Address | Count | Byte count | Data |
| 0x0F | 0x00 0x13 | 0x00 0x0A | 0x02 | 0x03 0x02 |
Bit order in the data
(No. 20) 1100 0000 01 (No. 29) → data byte 1 (27) 0000 0011 (20), byte 2 (36) ---- --10 (28)
Receive message
| Function | Address | Count |
| 0x0F | 0x00 0x13 | 0x00 0x0A |
(16) Preset Multiple Registers
Example of changing the values of 3 holding registers starting at holding register 20
Write data (20-22) = 0x0001 0x0002 0x0003
Send message
| Function | Address | Count | Byte count | Data 1 | Data 2 | Data 3 |
| 0x10 | 0x00 0x13 | 0x00 0x03 | 0x06 | 0x00 0x01 | 0x00 0x02 | 0x00 0x03 |
Receive message
| Function | Address | Count |
| 0x10 | 0x00 0x13 | 0x00 0x03 |
(17) Report Slave ID
Example of reading slave information
Send message
| Function |
| 0x11 |
Receive message
| Function | The following varies by device |
| 0x11 | ... |
Exception Responses
(03) When the address does not exist when executing Read Holding Register
Receive message
| Function | Exception code |
| 0x83 | 0x02 |
Most significant bit of the function
In the received data for an error, the function is returned with its most significant bit ON
Exception code
| Exception code | Name |
| 01 | Illegal function |
| 02 | Illegal data address |
| 03 | Illegal data value |