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.
- Slave address
- 1 (0x01)
- Function code
- 0x03 Read Holding Registers
CRC bytes to append low byte first
- 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 CDHow a Modbus RTU frame is put together
| Field | Size | Example | Notes |
|---|---|---|---|
| Slave address | 1 byte | 01 | 1–247; 0 is broadcast |
| Function code | 1 byte | 03 | Read Holding Registers |
| Data | 0–252 bytes | 00 00 00 0A | Start address 0, quantity 10 — big-endian |
| CRC | 2 bytes | C5 CD | CRC-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
- Load a 16-bit register with
0xFFFF. - XOR the next frame byte into the low byte of the register.
- Shift the register one bit to the right. If the bit shifted out was 1, XOR the register with
0xA001. - Repeat step 3 until eight shifts have been done.
- Repeat from step 2 for every byte of the frame.
- 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 CDTest frames
| Request | Frame without CRC | CRC bytes |
|---|---|---|
| Read 10 holding registers from address 0, slave 1 | 01 03 00 00 00 0A | C5 CD |
| Read 3 holding registers from address 107, slave 17 | 11 03 00 6B 00 03 | 76 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.