Modbus RTU Frame Builder & Parser
Decode a captured Modbus RTU frame field by field, or build a request from a function code and address. Exception responses and CRC errors are called out.
Paste straight from a serial sniffer. Separators and 0x prefixes are ignored.
CRC valid
Slave 1, function 3 (Read Holding Registers)
| Field | Bytes | Meaning |
|---|---|---|
| Slave address | 01 | 1 |
| Function code | 03 | 3 — Read Holding Registers |
| Start address | 00 00 | 0 (0x0000) |
| Quantity | 00 0A | 10 |
| CRC-16 (low byte first) | C5 CD | 0xCDC5 — valid |
The structure of an RTU frame
Every Modbus RTU frame has the same shape: a one-byte slave address, a one-byte function code, a variable data section, and a two-byte CRC. There is no length field and no start delimiter. Frames are separated by silence on the line — at least 3.5 character times — which is why RTU is sensitive to timing and why USB serial adapters with large buffers sometimes cause trouble.
| Field | Size | Notes |
|---|---|---|
| Slave address | 1 byte | 1–247; 0 is a broadcast that gets no reply |
| Function code | 1 byte | High bit set marks an exception response |
| Data | 0–252 bytes | Layout depends on the function and direction |
| CRC-16 | 2 bytes | Low byte first, unlike every other field |
Function codes you will actually meet
| Code | Name | Operates on |
|---|---|---|
| 0x01 | Read Coils | Writable single bits |
| 0x02 | Read Discrete Inputs | Read-only single bits |
| 0x03 | Read Holding Registers | Writable 16-bit registers |
| 0x04 | Read Input Registers | Read-only 16-bit registers |
| 0x05 | Write Single Coil | 0xFF00 for on, 0x0000 for off |
| 0x06 | Write Single Register | One 16-bit value |
| 0x0F | Write Multiple Coils | Bits packed low bit first |
| 0x10 | Write Multiple Registers | Preceded by a byte count |
Functions 0x03 and 0x04 are the ones that cause the most confusion, because many devices expose the same physical data through both, and documentation is often unclear about which one a given register map uses. If a read returns an illegal data address exception, trying the other function code is a reasonable next step.
Exception responses
When a device understands a frame but cannot serve it, it replies with the function code plus 0x80 and one exception byte. The three you will see in practice:
- 0x01 Illegal Function — the device does not implement that function code at all.
- 0x02 Illegal Data Address — the register does not exist, or the requested range runs past the end of a block. Check the 40001 offset before assuming the map is wrong.
- 0x03 Illegal Data Value — the value is outside the range the device accepts, or the quantity field is invalid. Note that this refers to the value in the request, not to a value stored in the device.
Debugging a link that does not respond
Silence carries no diagnostic information, so work through the layers in order. Confirm the CRC on the frame you are sending. Confirm the slave address matches the device, since many default to 1 but plenty ship with something else. Confirm baud rate, parity, and stop bits — RTU commonly runs 8E1, and a mismatch on parity alone produces framing errors that look identical to a dead device. Only then start questioning the register map.
Frequently asked questions
How do I tell a request from a response?
A frame does not label itself. For read functions, a request always has exactly four data bytes (address and quantity), while a response starts with a byte count. This tool infers the direction from the length the same way a protocol analyser does.
What does a function code with the high bit set mean?
It is an exception response. The device takes the original function code, adds 0x80, and follows it with a single exception code. Function 0x83 is an error reply to a read holding registers request.
What causes exception code 2, illegal data address?
The requested register does not exist on that device, or the request crosses the end of a valid block. It is frequently an off-by-one from the 40001-style documentation offset rather than a genuinely wrong address.
Why does my device not reply at all?
Silence usually means the frame never passed validation. A bad CRC, a wrong slave address, or a broken inter-frame gap all cause the device to discard the frame without an error. Paste the frame above to check the CRC first.