CRC Calculator

Modbus CRC Calculator

Paste a Modbus RTU frame as hex to get its CRC-16 in the order the bytes go on the wire, plus the complete frame ready to send. Switch to Verify to check a captured frame.

6 bytes
Slave address
1 (0x01)
Function code
0x03 Read Holding Registers

CRC bytes to append low byte first

C5 CD
Complete frame to send
01 03 00 00 00 0A C5 CD
CRC-16/MODBUS as a 16-bit number
0xCDC5

Build a request frame

Enter decimal numbers, or hex with a 0x prefix.

01 03 00 00 00 0A C5 CD

How a Modbus RTU frame is put together

FieldSizeExampleNotes
Slave address1 byte011–247; 0 is broadcast
Function code1 byte03Read Holding Registers
Data0–252 bytes00 00 00 0AStart address 0, quantity 10 — big-endian
CRC2 bytesC5 CDCRC-16/MODBUS, low byte first

The complete request is 01 03 00 00 00 0A C5 CD. The receiver runs the same calculation over the first six bytes and discards the frame silently if its result differs from the last two.

The Modbus CRC algorithm

  1. Load a 16-bit register with 0xFFFF.
  2. XOR the next frame byte into the low byte of the register.
  3. Shift the register one bit to the right. If the bit shifted out was 1, XOR the register with 0xA001.
  4. Repeat step 3 until eight shifts have been done.
  5. Repeat from step 2 for every byte of the frame.
  6. Append the register to the frame, low byte first.

C

uint16_t modbus_crc(const uint8_t *data, size_t len)
{
    uint16_t crc = 0xFFFF;
    while (len--) {
        crc ^= *data++;
        for (int i = 0; i < 8; i++)
            crc = (crc & 1) ? (crc >> 1) ^ 0xA001 : crc >> 1;
    }
    return crc;
}

/* frame[len] = crc & 0xFF; frame[len + 1] = crc >> 8; */

Python

def modbus_crc(data: bytes) -> int:
    crc = 0xFFFF
    for b in data:
        crc ^= b
        for _ in range(8):
            crc = (crc >> 1) ^ 0xA001 if crc & 1 else crc >> 1
    return crc

frame = bytes.fromhex("01 03 00 00 00 0A")
frame += modbus_crc(frame).to_bytes(2, "little")   # C5 CD

Test frames

RequestFrame without CRCCRC bytes
Read 10 holding registers from address 0, slave 101 03 00 00 00 0AC5 CD
Read 3 holding registers from address 107, slave 1711 03 00 6B 00 0376 87

A handy property for testing: running the CRC over a complete, valid frame including its two CRC bytes always gives zero.

Working with a different 16-bit CRC? The CRC16 calculator compares every variant side by side, and the CRC32 calculator accepts fully custom parameters.

Modbus ASCII frames end in a one-byte LRC instead of a CRC; the checksum calculator computes it. For 8-bit sensor checks see the CRC8 calculator, and for the theory, how a CRC is calculated.

Frequently asked questions

Which CRC does Modbus RTU use?

CRC-16/MODBUS: polynomial 0x8005 (0xA001 in reflected form), initial value 0xFFFF, input and output reflected, no final XOR. The CRC of the ASCII string "123456789" is 0x4B37.

In which order are the two Modbus CRC bytes sent?

Low byte first, then high byte. This is the opposite of every other 16-bit field in a Modbus frame, which are big-endian. For the request 01 03 00 00 00 0A the CRC value is 0xCDC5, so the bytes on the wire are C5 CD.

Which bytes does the Modbus CRC cover?

Everything in the frame before the CRC itself: the slave address, the function code and all data bytes. Start and stop bits, parity bits and the silent interval between frames are not included.

Does Modbus TCP use a CRC?

No. Modbus TCP drops the CRC and the slave address and adds a 7-byte MBAP header instead, relying on TCP and Ethernet for error detection. Modbus ASCII uses a one-byte LRC, not a CRC.

Why does my device reject a frame with a correct-looking CRC?

The most common cause is the two CRC bytes being swapped. Other causes are computing the CRC over the wrong range (for example including the CRC bytes, or leaving out the slave address), or using the CRC-16/ARC variant, which is identical except that it starts from 0x0000 instead of 0xFFFF.