Modbus RTU CRC-16 Calculator
Paste a Modbus RTU frame as hex bytes and get the CRC-16 checksum, in both register order and the low-byte-first order it’s actually sent on the wire.
CRC-16 result
Complete frame
How to use this tool
- Paste the frame bytes you want to check, as hex, in the order they appear on the wire before the CRC — slave address, function code, data, all of it.
- Spaces, commas, dashes or no separator at all are all accepted; the tool strips anything that isn’t a hex digit.
- Read the CRC-16 result both ways: the register value (what you’d compute in software) and the low-byte-first pair that actually goes out on the wire.
- Use the Complete frame panel to get your original bytes with the correct CRC bytes already appended, ready to compare against a capture or send as-is.
- Use the preset buttons to see three common Modbus function codes checked against this exact algorithm.
Every Modbus RTU frame ends with a two-byte CRC-16 checksum, and getting the algorithm even slightly wrong produces a CRC that looks plausible but is silently rejected by every real slave device on the bus — there is no partial credit. The algorithm itself is short: start with a 16-bit register initialized to 0xFFFF, XOR each input byte into the low byte of that register, then run eight shift-and-conditionally-XOR iterations per byte. If the least significant bit of the register is 1 after the XOR, shift right one bit and XOR the result with the fixed polynomial constant 0xA001; if it’s 0, just shift right. After all bytes and all iterations, whatever is left in the register is the CRC.
0xA001 is the detail that trips up from-scratch implementations, because it looks like an arbitrary constant but isn’t. Modbus’s CRC-16 is defined by the generator polynomial x^16 + x^15 + x^2 + 1, normally written in its standard (MSB-first) form as 0x8005. 0xA001 is that same polynomial bit-reversed, because the Modbus algorithm processes bits least-significant-bit first rather than most-significant-bit first. Implementations that use the “reflected” shift-right approach shown above need the reflected polynomial, 0xA001 — mixing the two conventions (say, shifting right while XORing with the un-reflected 0x8005) produces a CRC that is wrong for every input except the trivial all-zero case, and the bug can be very hard to spot by inspection.
Byte order is the second common mistake, and it happens after the CRC is computed correctly. The two-byte result is a single 16-bit value, but Modbus RTU transmits it low byte first, high byte second — the opposite of the big-endian, high-byte-first order most protocol fields use, including every data value inside a standard Modbus frame. A CRC of 0xCDC5 is sent as the byte sequence C5 then CD. Appending the bytes in the “natural” high-then-low order is a frequent bug in hand-rolled Modbus stacks, and it is a bug that a length check alone will never catch, since the frame is still the right size.
The reference test vector worth memorizing: the request frame 01 03 00 00 00 0A (slave address 1, function code 3 — read holding registers, starting address 0, quantity 10) has a CRC-16 of 0xCDC5, transmitted as C5 CD. Any correct Modbus CRC-16 implementation, in any language, must reproduce that exact value for that exact input — it’s one of the standard worked examples in the Modbus specification’s own application notes, and it’s the fastest way to sanity-check a new implementation before pointing it at real hardware.
One more subtlety worth knowing: Modbus RTU’s CRC-16 and the CRC-16/CCITT used by Modbus ASCII and a number of other protocols are not the same algorithm, despite both being called “CRC-16” and both processing 16 bits at a time. Different polynomial, different initial value in most variants, and not interchangeable — a checksum computed with one will not validate against the other. If a device’s documentation just says “CRC-16” without naming the variant, and it’s specifically an RTU (binary, not ASCII-framed) device, the algorithm on this page is almost always the right one.
Frequently asked questions
Why is the Modbus CRC polynomial written as 0xA001 instead of 0x8005?
They’re the same polynomial. 0x8005 is the standard, most-significant-bit-first form of the CRC-16 polynomial used by Modbus. 0xA001 is that polynomial bit-reversed, for use with the least-significant-bit-first, shift-right algorithm Modbus actually specifies. If your implementation shifts right, it needs 0xA001; mixing shift direction and polynomial form produces an incorrect CRC.
What order are the CRC bytes sent in on a Modbus RTU frame?
Low byte first, then high byte — the opposite of every data field inside the frame, which is big-endian. A CRC register value of 0xCDC5 is transmitted as the two bytes C5 then CD. Appending them in the wrong order is one of the most common bugs in a hand-written Modbus RTU stack.
What is the correct CRC-16 for 01 03 00 00 00 0A?
0xCDC5, sent on the wire as bytes C5 CD. This is a standard reference vector from the Modbus specification’s own examples (a read-holding-registers request for slave 1, address 0, quantity 10), and it’s a reliable way to check any new CRC implementation before trusting it against real devices.
Is Modbus CRC-16 the same as CRC-16/CCITT?
No. They are both called “CRC-16” but use different polynomials and initial values, and are not cross-compatible — a checksum valid under one will not validate under the other. Modbus RTU (binary framing) uses the algorithm on this page; Modbus ASCII uses a simple LRC checksum instead of a CRC entirely.
Do I include the CRC bytes when computing the CRC?
No. The CRC is computed over every byte of the frame except the CRC itself — typically the slave address, function code, and data bytes. The two CRC bytes are then appended to the end of that data as the final step, not fed into the calculation.