CRC-16/Modbus in one sentence
CRC-16/Modbus is the cyclic redundancy check that every Modbus RTU device computes over a message frame to detect transmission errors before acting on it.
How it works
The algorithm processes the message one byte at a time using the reflected generator polynomial 0xA001. The CRC register starts at 0xFFFF. For each input byte, the byte is XORed into the low byte of the register, and the register is shifted right eight times; whenever a bit shifted out is 1, the polynomial 0xA001 is XORed back in. Because the input and output are reflected, the calculation is done least-significant-bit first. There is no final XOR step, so the register value after the last byte is the CRC.
This tool uses the standard table-driven form: it precomputes a 256-entry lookup table from the polynomial, then folds each byte through the table. That produces the same result as the bitwise method but far faster.
Modbus RTU frame structure
Understanding where the CRC fits in a complete Modbus RTU frame helps when building or debugging messages. A standard Modbus RTU frame looks like this:
[Address: 1 byte] [Function Code: 1 byte] [Data: N bytes] [CRC-Low: 1 byte] [CRC-High: 1 byte]
The CRC is computed over the address, function code, and data bytes only — not over the CRC itself. The CRC is then split into its low byte (the least significant) and high byte (the most significant), with the low byte appended first. This byte-reversed order is a distinctive Modbus quirk: most multi-byte fields in Modbus are big-endian, but the CRC is little-endian. Getting that order wrong is the most common frame-construction mistake.
Common function codes you would CRC in practice
- 0x01 — Read Coils
- 0x03 — Read Holding Registers
- 0x06 — Write Single Register
- 0x10 — Write Multiple Registers
For example, to read two holding registers starting at address 0x006B from device address 0x11, the data to CRC (excluding the CRC itself) is: 11 03 00 6B 00 02. Paste that as hex bytes into this tool to verify or generate the CRC before comparing it against your hardware’s output.
Distinguishing CRC-16/Modbus from other CRC-16 variants
Several CRC-16 variants are in common use, and they are not interchangeable. Confusing them is a frequent source of integration bugs:
| Variant | Polynomial | Initial value | Check value (123456789) |
|---|---|---|---|
| CRC-16/Modbus | 0xA001 (reflected) | 0xFFFF | 0x4B37 |
| CRC-16/CCITT | 0x1021 | 0xFFFF | 0x29B1 |
| CRC-16/USB | 0xA001 (reflected) | 0xFFFF | 0xB4C8 |
| CRC-16/ARC | 0xA001 (reflected) | 0x0000 | 0xBB3D |
Note that CRC-16/Modbus and CRC-16/ARC share the same polynomial but differ in the initial register value (0xFFFF vs. 0x0000), producing different results for the same data.
Example and notes
The Modbus specification’s canonical test vector is the ASCII string 123456789, which must yield 0x4B37. You can paste either text or raw hex — for a real frame such as a read-holding-registers request, switch to Hex bytes and paste the address, function code, and data.
When you transmit the frame, remember Modbus RTU is unusual: it appends the CRC low byte first, then the high byte. The tool shows both the natural hex value and the on-the-wire byte order so you do not swap them by mistake. CRC checks catch accidental corruption only and are not a substitute for cryptographic integrity.