View all lessons
Part 1
Fundamentals
Part 2
Modbus RTU
- Lesson 5RS485 explained: A, B, common and termination20 min
- Lesson 6Baud rate and parity: why 8E1 is the default16 min
- Lesson 7The Modbus RTU frame byte by byte, plus CRC18 min
- Lesson 8Multiple Modbus devices on one RS485 bus16 min
- Lesson 9Read your first Modbus device with mbpoll22 min
- Lesson 10Modbus RTU troubleshooting: symptom to cause20 min
Part 3
Modbus TCP
Part 4
Advanced
- Lesson 16Writing to a Modbus device without breaking it18 min
- Lesson 17Word order and floats: same bytes, other value22 min
- Lesson 18Calculate your poll interval and bus load18 min
- Lesson 19Modbus security: the protocol will not help16 min
- Lesson 20Modbus integration: PLC, Home Assistant, cloud20 min
- Lesson 21Modbus commissioning checklist and cheat sheet18 min
The Modbus RTU frame byte by byte, plus CRC
Take a Modbus RTU frame apart byte by byte: address, function code, data and CRC-16. You also see why the CRC is the only field that goes low byte first.
What this lesson covers
- The four fields of an RTU frame, byte by byte
- Why the CRC is the only field that goes low byte first
- What a wrong CRC gives you: a timeout, not an error message
Read first: Reading exception codes and choosing a function code, Baud rate and parity: why 8E1 is the default
A Modbus RTU frame is four fields in a fixed order: server address, function code, data, and a CRC-16 checksum that closes it off. There is no start byte, no length field and no end marker, so once you can point at the field boundaries yourself you can read any capture on any bus. After this lesson you can take a frame apart on paper and tell a broken one from a valid one before you touch the wiring.
A real frame, byte by byte
Here is a complete request, eight bytes, nothing hidden: 01 03 00 6B 00 03 74 17.
| Byte | Hex | Field | What it says |
|---|---|---|---|
| 1 | 01 | Server address | Server 1 answers, every other device stays silent |
| 2 | 03 | Function code | FC03, read holding registers |
| 3 and 4 | 00 6B | Start address | PDU address 107, high byte first |
| 5 and 6 | 00 03 | Quantity | Three registers |
| 7 and 8 | 74 17 | CRC-16 | Checksum 0x1774, low byte first |
That PDU address 107 is the same register a datasheet would call 40108, which is the conversion covered in Modbus addressing explained.
Now the general shape. Every RTU frame is 1 address byte, 1 function code byte, 0 to 252 data bytes and 2 CRC bytes, which is why the maximum is 256 bytes on the wire.
Change one thing and the shape holds. 01 04 00 08 00 01 B0 08 is the same server, the same field order and the same length, but function code 04 reads one input register at PDU address 8. Only the data block changed meaning. Which code reads which block is the subject of the Modbus function codes reference.
The response to that same frame
The answer to the request above is eleven bytes: 01 03 06 02 2B 00 00 00 64 05 7A.
| Byte | Hex | Field | What it says |
|---|---|---|---|
| 1 | 01 | Server address | Server 1 is talking |
| 2 | 03 | Function code | Still FC03, so no error |
| 3 | 06 | Byte count | 6 data bytes follow |
| 4 and 5 | 02 2B | Register 1 | 555 |
| 6 and 7 | 00 00 | Register 2 | 0 |
| 8 and 9 | 00 64 | Register 3 | 100 |
| 10 and 11 | 05 7A | CRC-16 | Checksum 0x7A05 |
Two things are worth fixing in your head. The byte count is 6, not 3: it counts bytes, not registers, and three 16-bit registers are always six bytes. And the function code came back unchanged. Had the server refused, byte 2 would have been 83, which is 03 with the high bit set, followed by a single exception code byte.
The length of a read response therefore follows from the request: 5 bytes of frame plus 2 bytes per register.
Where does a frame begin and end?
Silence, and nothing else. An RTU frame carries no start character, no end character and no length field, so a receiver decides where a frame stops purely by listening for a gap.
Two intervals do that work, both measured in character times, and one RTU character is always 11 bits on the line. Those are the numbers from baud rate, parity and timing, now with a frame wrapped around them. A gap of at least 3.5 character times (t3,5) means the frame is finished. A gap of more than 1.5 character times (t1,5) in the middle of a frame means the frame is broken and gets discarded. At 19200 baud, the default the standard prescribes, that is 2.005 ms and 0.859 ms.
This is why a USB adapter that hands its buffer over in pieces can break traffic that is electrically perfect. The bytes all arrive, but not close enough together.
What the CRC is, and what it misses
The CRC-16 is a two-byte number calculated over every byte of the frame in front of it, and it exists to tell a receiver that the frame arrived exactly as it was sent.
The calculation is fixed by the standard: a 16-bit register preloaded with 0xFFFF, shifted bit by bit, with the polynomial 0xA001 (the reflected form) mixed in whenever a shifted-out bit was 1. It runs over the address byte, the function code and all data bytes. Start bits, stop bits and the parity bit are not part of it. You do not need to implement this to work on a bus, but you do need to know its reach.
That reach is what separates it from parity. Parity protects one character at a time and only catches an error when an odd number of bits in that character flip. The CRC checks the contents of the entire message, and it does that whether or not parity is switched on.
Why the CRC sits reversed in the frame
Because the standard says the low-order byte goes first, and only for this field. The CRC value in our example is 0x1774, and on the wire it appears as 74 17.
Everywhere else in the frame a 16-bit value goes high byte first: the start address 00 6B is 107, the quantity 00 03 is three, the register value 02 2B is 555. The CRC is the single little-endian field in a Modbus RTU frame.
The trick receivers use
A receiver does not have to calculate the CRC and then compare it. It can run the same calculation over the complete frame, the two CRC bytes included, and check that the result is 0x0000.
That works because of how the checksum is constructed: appending the correct CRC makes the whole message divide out cleanly. Both frames from this lesson behave that way, 01 03 00 00 00 0A C5 CD and 01 03 00 6B 00 03 74 17, and so does every valid frame you will ever see. It means a device can decide "valid or not" in one pass over the bytes it just received, without holding anything in memory to compare against.
What happens when the CRC does not match
Nothing comes back. The server drops the frame, builds no response and says nothing, so the client sits and waits until its own timeout expires.
That behaviour is deliberate. A frame with a broken CRC cannot be trusted to say who it was for, so answering it could mean two devices talking at once on the same pair. The practical consequence is the one that costs people afternoons: a timeout is not proof that a device is absent. Wrong address, wrong serial parameters, a bad connection and a line that flips the occasional bit all produce exactly the same silence, which is where Modbus RTU troubleshooting picks up.
Common mistakes
Swapping the two CRC bytes. The value 0x1774 belongs in the frame as 74 17. Written the other way round, every device discards the frame and you see timeouts on a bus where nothing is wrong. Addresses and quantities do go high byte first; the CRC is the exception.
Reading the byte count as a register count. Three registers give a byte count of 6. Take that 6 as "six registers" and every value after it lands one field too far along, which produces plausible but wrong numbers rather than an error.
Treating a CRC error as a protocol fault. A CRC error produces silence, so it looks identical to a device that is switched off. Never conclude from a timeout alone that the address is wrong.
Assuming a short pause inside a frame is harmless. A gap longer than 1.5 character times makes the frame invalid, even when every byte is correct. USB adapters that deliver their buffers in chunks do exactly this.
Get hands-on
Take the frame apart on paper first, then check yourself against the decoder.
- 1
Write down what each byte means
Use
01 03 00 00 00 0A C5 CDand fill in the blanks below before you look anything up. - 2
Name the four fields
Server address, function code, data and CRC. Say which bytes belong to which.
- 3
Work out how long the response will be
Ten registers is 20 data bytes, plus 1 address, 1 function code, 1 byte count and 2 CRC bytes. That is 25 bytes.
- 4
Paste the frame into the decoder and compare
Load the presets one at a time, including the exception and the broken CRC.
- 5
Change a single byte and look at the CRC line
Turn the
0Ainto a0Band read the value the decoder now expects. That is the same judgement a device makes in microseconds. - 6
Watch the bytes on your own bus
With hardware to hand, run mbpoll with the
-vswitch so it prints every frame it sends and receives, then compare those bytes with your own breakdown. mbpoll is free to use, including commercially. Or open the Protocol Analyzer in ModbusCloud Diagnostics, which colours the same bytes per frame field and prints a short description beside each frame.
01 03 00 00 00 0A C5 CD
01 -> server address 1
03 -> ______________________
00 00 -> ______________________
00 0A -> ______________________
C5 CD -> ______________________
CRC matches
- Server address
- Function code
- Data
- CRC-16
| Field | Hex | Decimal | Meaning |
|---|---|---|---|
| Server address | 01 | 1 | |
| Function code | 03 | 3 | Read Holding Registers |
| Start address | 00 6B | 107 | |
| Quantity | 00 03 | 3 | |
| CRC-16 | 74 17 | 6004 |
No hardware needed. Steps 1 to 5 need nothing but this page. Only step 6 needs a device and an RS485 adapter, and this is the command it takes:
mbpoll -m rtu -b 19200 -P even -a 1 -t 4 -r 108 -c 3 -v /dev/ttyUSB0
Expected result: a breakdown that matches the decoder field for field, and a frame with one altered byte where the decoder names the CRC it expected instead. Scanning a bus you know nothing about is covered in how to scan a Modbus network.
Summary
- A Modbus RTU frame is always server address, function code, data and CRC-16, with a maximum of 256 bytes on the wire.
- The byte count in a read response counts bytes and not registers, so three registers give a byte count of 6.
- Frame boundaries on RTU are silence: at least 3.5 character times between frames, and never more than 1.5 character times inside one.
- The CRC-16 is the only little-endian field in the frame, so the value 0x1774 travels as the bytes 74 17.
- A frame with a bad CRC is dropped without any reply, so the client sees a timeout and not an exception, exactly as Modbus RTU explained describes for the transport as a whole.
Check yourself
Four questions about this lesson. Every answer comes with an explanation.
Question 1 of 4
Want to see how it works?
The ModbusCloud Gateway reads the devices from this course without you programming a single register.