Modbus RTU CRC calculation guide
Which CRC Modbus RTU uses, how the 2-byte CRC is appended to a frame in low-byte-first order, and how to compute it step by step with worked examples.
Which algorithm Modbus RTU uses
Modbus RTU frames are checksummed with CRC-16/MODBUS: width 16, polynomial 0x8005, initial value 0xFFFF, both input and output reflected, and no final XOR. This is a different model from CRC-16/CCITT-FALSE, so a Modbus master and a generic CRC-16 tool will disagree unless the CCITT preset is swapped for the MODBUS one.
The check value for the ASCII test string 123456789 is 0x4B37. Confirm any custom implementation against that value before trusting it on real serial traffic.
How the CRC is attached to the frame
A Modbus RTU frame is address byte, function code, data bytes, then a 2-byte CRC computed over every preceding byte in the frame (address through the last data byte).
The CRC field is transmitted low byte first, high byte second — the opposite of the big-endian byte order used by CRC-32/ISO-HDLC in Ethernet trailers. If a calculated CRC of 0x4B37 is being placed on the wire, the two bytes sent are 0x37 then 0x4B.
- Address (1 byte)
- Function code (1 byte)
- Data (N bytes)
- CRC low byte
- CRC high byte
Step-by-step calculation
Load the 16-bit register with 0xFFFF. For each byte in the frame, XOR the byte into the low 8 bits of the register, then shift the register right 8 times, XORing in the reflected polynomial (0xA001) whenever a 1 bit is shifted out.
After the last byte, the register holds the CRC in host order. Swap it to low-byte-first before appending it to the frame, or reuse the calculator preset directly instead of hand-rolling the loop.
01 03 00 00 00 0A → CRC-16/MODBUS = 0xCDC5 (wire bytes: C5 CD)Worked example: converting the result to wire order
The CRC register produces one 16-bit number, and that number is naturally written high byte first — the same order used everywhere else in this guide and by the calculator's hex output. Modbus RTU instead transmits the two CRC bytes low byte first, so the result has to be byte-swapped before it is appended to the frame; this swap is separate from, and happens after, the bit-level reflection already built into the CRC-16/MODBUS model itself.
Take the request 01 03 00 00 00 0A — slave address 1, function 3 (read holding registers), starting register 0x0000, quantity 10. CRC-16/MODBUS over those six bytes is 0xCDC5: high byte 0xCD, low byte 0xC5. Swapped to low-byte-first wire order, the two CRC bytes actually transmitted are C5 then CD, so the complete frame on the wire is 01 03 00 00 00 0A C5 CD.
A second, independently useful check: the Modbus Serial Line specification's own worked example uses the request 11 03 00 6B 00 03 (slave address 0x11, function 3, starting register 0x006B, quantity 3). CRC-16/MODBUS over those six bytes is 0x8776 — high byte 0x87, low byte 0x76 — so the wire order is 76 87 and the complete frame is 11 03 00 6B 00 03 76 87. Matching this exact byte sequence is a fast way to confirm a from-scratch implementation before trusting it against real hardware.
01 03 00 00 00 0A → CRC = 0xCDC5 → high 0xCD, low 0xC5 → wire: C5 CD → frame: 01 03 00 00 00 0A C5 CD
11 03 00 6B 00 03 → CRC = 0x8776 → high 0x87, low 0x76 → wire: 76 87 → frame: 11 03 00 6B 00 03 76 87Primary sources
This guide's frame layout and worked examples follow the Modbus Organization's "MODBUS over Serial Line Specification and Implementation Guide" (published at modbus.org), the specification that defines Modbus RTU framing and its CRC-16/MODBUS check.
The CRC-16/MODBUS parameter set itself — width, polynomial, initial value, reflection, and check value — is cross-referenced against the Catalogue of CRC Algorithms (reveng.sourceforge.io), the parameter reference used throughout this site.
Apply this reference
Change CRC parameters and compare standard algorithm results using the browser-based calculator.