Free tool · nothing leaves your machine

Modbus CRC-16 calculator

Type the bytes of a Modbus RTU frame and the CRC-16/MODBUS appears as you go — as a 16-bit number and, more usefully, in the low-byte-first order it actually goes on the wire. There is no Calculate button. Everything runs in this page.

1Your bytes

Spaces, commas, colons, 0x prefixes and line breaks are all fine — paste a Wireshark dump if you like. A trailing single digit is treated as half a typed byte, not an error.

Byte by byte

2The CRC

On the wire

C4 0B

as sent on the wire, low byte first

As a 16-bit number

0x0BC4

what a CRC library hands back. Swap the two bytes to get the wire order above.

The complete frame

01 03 00 00 00 02 C4 0B

Decode it

3The other CRC-16s

Every one of these is called “CRC-16” by somebody. If your code disagrees with the wire, the value you are producing is almost always one of the rows below.

Same bytes, four algorithms
VariantHexOn the wireWho uses it

4Build a request

Fill in what you want to ask a slave and the frame is written for you, CRC included.

The address above is written as

The frame

01 03 00 00 00 02 C4 0B

How the Modbus CRC actually works

Modbus RTU puts a 16-bit CRC on the end of every frame. The algorithm is CRC-16/MODBUS, and it is fully described by four facts:

So a read of two holding registers from slave 1 — 01 03 00 00 00 02 — has a CRC of 0x0BC4, and the frame that goes on the bus ends C4 0B. The CRC covers the slave address and everything after it, and nothing else: no start byte, no length, and never the CRC bytes themselves.

A receiver has a shortcut available. Run the same CRC over the whole received frame, CRC bytes included, and a good frame gives exactly 0x0000. That is a check, not a value to transmit.

Why yours does not match

In rough order of how often each one turns out to be the answer:

  1. The two bytes are swapped. Your library returned 0x0BC4 and you wrote 0B C4. The wire wants C4 0B. The slave will not answer and will not tell you why.
  2. You started at 0 instead of 0xFFFF. That is CRC-16/ARC, the row directly under MODBUS in the table above — same polynomial, different seed. It is the single most common mix-up, because a lot of sample code is written for ARC.
  3. The CRC bytes went into the calculation. If you are recomputing the CRC of a frame you captured, strip the last two bytes first. Feeding them back in gives you the CRC of a CRC.
  4. The bytes are decimal, not hex. A datasheet that says “register 40010” and a capture that says 0A are talking about different notations. Everything this page accepts is hex.
  5. It is not a CRC at all. Modbus ASCII — the frames that start with a colon — ends with an LRC, the two's complement of the byte sum, followed by CR LF. Modbus TCP has no checksum of its own at all; it carries an MBAP header instead and leaves integrity to TCP.

Modbus CRC questions

Everything people ask after the first frame still does not work.

How is the Modbus CRC calculated?

CRC-16/MODBUS uses the polynomial 0x8005 in its reflected form, 0xA001. The register starts at 0xFFFF, every byte of the frame from the slave address onwards is folded in least-significant-bit first, and there is no final XOR. The 16-bit result is appended to the frame low byte first, which is the opposite order to everything else in Modbus.

Why is my CRC the other way round?

Because Modbus sends the CRC low byte first while addresses, quantities and register values are all big-endian. A CRC of 0x0BC4 goes on the wire as C4 0B. Most libraries hand you the 16-bit number, so if you write it out as-is the two bytes are swapped and every slave on the bus drops the frame in silence. This page shows both, so you can see which one you have.

Do the CRC bytes themselves go into the calculation?

No. The CRC covers everything before it: the slave address, the function code and the data, and nothing else. Running the CRC over a complete frame including its own CRC bytes gives 0x0000, which is a valid way to check a received frame but is not the value you transmit. If you paste a complete frame here, the tool notices and offers to drop the last two bytes.

Does Modbus TCP have a CRC?

No. Modbus TCP replaces the CRC with a seven-byte MBAP header — transaction id, protocol id, length and unit id — and lets TCP itself handle the integrity check. If you are building a TCP frame, take an RTU frame, drop the two CRC bytes and put the MBAP header in front. The frame decoder converts between the two.

Does Modbus ASCII use this CRC?

No. Modbus ASCII frames start with a colon, carry each byte as two hex characters and end with an LRC, which is simply the two's complement of the sum of the payload bytes, followed by CR LF. If your frame starts with a colon you want an LRC, not a CRC — paste it into the frame decoder and it will check the LRC for you.

Does anything I type here leave my browser?

Nothing you type or read leaves your browser. The only network request the tool makes is one anonymous ping (a GET to /tools/_/…, no cookies, no identifiers) when a decode or read succeeds, so we know the tool is used. The CRC itself is a few lines of JavaScript running in this page; there is no server involved, and the frame you are working on stays in the URL fragment, which browsers never send.

You got the frame right. Now keep the readings.

A correct CRC is the first five minutes. Synacl is the rest: an ESP32 gateway polls the slave on a timer, the registers land on a dashboard with history, and a rule tells you when one of them moves.