What CRC does Modbus RTU use?
CRC-16/MODBUS: polynomial 0x8005, init 0xFFFF, input and output reflected, no final XOR. Its check value is 0x4B37. The specification sends the low byte first, so a CRC of 0x1241 appears on the wire as 41 12.
With 34 standard algorithms built in, or your own polynomial, this CRC calculator computes CRC-8, CRC-16, CRC-32 and CRC-64 checksums of text or hex bytes. Copy C code for the exact CRC you selected, as a lookup table or a bit-by-bit loop.
Hashed exactly as typed, including any line break at the end.
CRC-16/MODBUS
0x4B37
Sent as 37 4B (low byte first)
Modbus RTU.
#include <stddef.h>
#include <stdint.h>
/* CRC-16/MODBUS: width=16 poly=0x8005 init=0xFFFF
* refin=true refout=true xorout=0x0000 check=0x4B37
* check is the CRC of the nine ASCII bytes "123456789". */
static const uint16_t crc16_modbus_table[256] = {
0x0000u, 0xC0C1u, 0xC181u, 0x0140u, 0xC301u, 0x03C0u, 0x0280u, 0xC241u,
0xC601u, 0x06C0u, 0x0780u, 0xC741u, 0x0500u, 0xC5C1u, 0xC481u, 0x0440u,
0xCC01u, 0x0CC0u, 0x0D80u, 0xCD41u, 0x0F00u, 0xCFC1u, 0xCE81u, 0x0E40u,
0x0A00u, 0xCAC1u, 0xCB81u, 0x0B40u, 0xC901u, 0x09C0u, 0x0880u, 0xC841u,
0xD801u, 0x18C0u, 0x1980u, 0xD941u, 0x1B00u, 0xDBC1u, 0xDA81u, 0x1A40u,
0x1E00u, 0xDEC1u, 0xDF81u, 0x1F40u, 0xDD01u, 0x1DC0u, 0x1C80u, 0xDC41u,
0x1400u, 0xD4C1u, 0xD581u, 0x1540u, 0xD701u, 0x17C0u, 0x1680u, 0xD641u,
0xD201u, 0x12C0u, 0x1380u, 0xD341u, 0x1100u, 0xD1C1u, 0xD081u, 0x1040u,
0xF001u, 0x30C0u, 0x3180u, 0xF141u, 0x3300u, 0xF3C1u, 0xF281u, 0x3240u,
0x3600u, 0xF6C1u, 0xF781u, 0x3740u, 0xF501u, 0x35C0u, 0x3480u, 0xF441u,
0x3C00u, 0xFCC1u, 0xFD81u, 0x3D40u, 0xFF01u, 0x3FC0u, 0x3E80u, 0xFE41u,
0xFA01u, 0x3AC0u, 0x3B80u, 0xFB41u, 0x3900u, 0xF9C1u, 0xF881u, 0x3840u,
0x2800u, 0xE8C1u, 0xE981u, 0x2940u, 0xEB01u, 0x2BC0u, 0x2A80u, 0xEA41u,
0xEE01u, 0x2EC0u, 0x2F80u, 0xEF41u, 0x2D00u, 0xEDC1u, 0xEC81u, 0x2C40u,
0xE401u, 0x24C0u, 0x2580u, 0xE541u, 0x2700u, 0xE7C1u, 0xE681u, 0x2640u,
0x2200u, 0xE2C1u, 0xE381u, 0x2340u, 0xE101u, 0x21C0u, 0x2080u, 0xE041u,
0xA001u, 0x60C0u, 0x6180u, 0xA141u, 0x6300u, 0xA3C1u, 0xA281u, 0x6240u,
0x6600u, 0xA6C1u, 0xA781u, 0x6740u, 0xA501u, 0x65C0u, 0x6480u, 0xA441u,
0x6C00u, 0xACC1u, 0xAD81u, 0x6D40u, 0xAF01u, 0x6FC0u, 0x6E80u, 0xAE41u,
0xAA01u, 0x6AC0u, 0x6B80u, 0xAB41u, 0x6900u, 0xA9C1u, 0xA881u, 0x6840u,
0x7800u, 0xB8C1u, 0xB981u, 0x7940u, 0xBB01u, 0x7BC0u, 0x7A80u, 0xBA41u,
0xBE01u, 0x7EC0u, 0x7F80u, 0xBF41u, 0x7D00u, 0xBDC1u, 0xBC81u, 0x7C40u,
0xB401u, 0x74C0u, 0x7580u, 0xB541u, 0x7700u, 0xB7C1u, 0xB681u, 0x7640u,
0x7200u, 0xB2C1u, 0xB381u, 0x7340u, 0xB101u, 0x71C0u, 0x7080u, 0xB041u,
0x5000u, 0x90C1u, 0x9181u, 0x5140u, 0x9301u, 0x53C0u, 0x5280u, 0x9241u,
0x9601u, 0x56C0u, 0x5780u, 0x9741u, 0x5500u, 0x95C1u, 0x9481u, 0x5440u,
0x9C01u, 0x5CC0u, 0x5D80u, 0x9D41u, 0x5F00u, 0x9FC1u, 0x9E81u, 0x5E40u,
0x5A00u, 0x9AC1u, 0x9B81u, 0x5B40u, 0x9901u, 0x59C0u, 0x5880u, 0x9841u,
0x8801u, 0x48C0u, 0x4980u, 0x8941u, 0x4B00u, 0x8BC1u, 0x8A81u, 0x4A40u,
0x4E00u, 0x8EC1u, 0x8F81u, 0x4F40u, 0x8D01u, 0x4DC0u, 0x4C80u, 0x8C41u,
0x4400u, 0x84C1u, 0x8581u, 0x4540u, 0x8701u, 0x47C0u, 0x4680u, 0x8641u,
0x8201u, 0x42C0u, 0x4380u, 0x8341u, 0x4100u, 0x81C1u, 0x8081u, 0x4040u,
};
uint16_t crc16_modbus(const void *data, size_t length)
{
const uint8_t *bytes = (const uint8_t *)data;
uint16_t crc = 0xFFFFu;
while (length--) {
crc = (uint16_t)(crc16_modbus_table[(crc ^ *bytes++) & 0xFFu] ^ (crc >> 8));
}
return crc;
}
The table costs 512 bytes of flash and handles one byte per lookup.
Treat the message as a long binary number and divide it by a generator polynomial using XOR instead of subtraction; the remainder is the CRC. Six parameters pin down the exact variant. For the string 123456789, CRC-16/MODBUS gives 0x4B37 and the zip and PNG CRC-32 gives 0xCBF43926.
A CRC is the remainder of a polynomial division over GF(2), where addition and subtraction are both XOR. In hardware it is a shift register with XOR taps at the polynomial’s terms.
Real algorithms add a starting value, bit reversal and a final mask. Ross Williams’s Rocksoft model captures these in six parameters, and the calculator uses the same model as the RevEng catalogue:
For each message bit, the register shifts one place, and the polynomial is XORed in when the bit leaving the top differs from the incoming data bit:
SMBus defines its packet error code with C(x) = x⁸ + x² + x + 1, so the polynomial is 0x07, and init is 0. XOR the byte into the register, then shift eight times, XORing 0x07 whenever a 1 falls off the top:
| Shift | Top bit before the shift | Register after |
|---|---|---|
| 1 | 1 (XOR 0x07) | 1000 0011 (0x83) |
| 2 | 1 (XOR 0x07) | 0000 0001 (0x01) |
| 3 | 0 | 0000 0010 (0x02) |
| 4 | 0 | 0000 0100 (0x04) |
| 5 | 0 | 0000 1000 (0x08) |
| 6 | 0 | 0001 0000 (0x10) |
| 7 | 0 | 0010 0000 (0x20) |
| 8 | 0 | 0100 0000 (0x40) |
The result is 0x40.
Appendix B of the Modbus serial line specification computes the CRC of the two bytes 02 07. CRC-16/MODBUS gives 0x1241. The low byte goes first, so the bytes on the wire are 41 12, and a receiver running the same CRC over all four bytes ends at zero.
The datasheet specifies polynomial 0x31, init 0xFF, no reflection and no final XOR, which are the parameters of the CRC-8/NRSC-5 preset. For the 16-bit word 0xBEEF, the CRC is 0x92, the value the datasheet gives as its example. A 1-Wire ROM works the same way with CRC-8/MAXIM-DOW: the seven bytes 02 1C B8 01 00 00 00 give 0xA2, and running the CRC over all eight bytes gives 0x00.
Parameters from the RevEng catalogue. Each row is a preset in the tool above. If a CRC-16 calculator or CRC-32 calculator elsewhere gives a different answer, compare its parameters with this table. The check column is computed by this calculator over the ASCII string "123456789" and matches the published values.
| Algorithm | Poly | Init | Reflected | XorOut | Check | Used in |
|---|---|---|---|---|---|---|
| CRC-8/SMBUS | 0x07 | 0x00 | none | 0x00 | 0xF4 | SMBus packet error checking (PEC) |
| CRC-8/MAXIM-DOW | 0x31 | 0x00 | in and out | 0x00 | 0xA1 | 1-Wire ROM codes |
| CRC-8/NRSC-5 | 0x31 | 0xFF | none | 0x00 | 0xF7 | HD Radio; same parameters as the Sensirion SHT3x I2C CRC |
| CRC-8/SAE-J1850 | 0x1D | 0xFF | none | 0xFF | 0x4B | SAE J1850 vehicle bus, AUTOSAR CRC routines |
| CRC-8/AUTOSAR | 0x2F | 0xFF | none | 0xFF | 0xDF | AUTOSAR CRC routines (polynomial 0x2F) |
| CRC-8/BLUETOOTH | 0xA7 | 0x00 | in and out | 0x00 | 0x26 | Bluetooth header error check |
| CRC-8/I-432-1 | 0x07 | 0x00 | none | 0x55 | 0xA1 | ATM header error control (HEC) |
| CRC-8/ROHC | 0x07 | 0xFF | in and out | 0x00 | 0xD0 | Robust header compression (ROHC) |
| CRC-16/MODBUS | 0x8005 | 0xFFFF | in and out | 0x0000 | 0x4B37 | Modbus RTU |
| CRC-16/IBM-3740 | 0x1021 | 0xFFFF | none | 0x0000 | 0x29B1 | Floppy disk formats, AUTOSAR; often mislabeled CRC-CCITT |
| CRC-16/XMODEM | 0x1021 | 0x0000 | none | 0x0000 | 0x31C3 | XMODEM, ZMODEM, MultiMediaCard data |
| CRC-16/KERMIT | 0x1021 | 0x0000 | in and out | 0x0000 | 0x2189 | Kermit, Bluetooth, ITU-T V.41 sent LSB first |
| CRC-16/ARC | 0x8005 | 0x0000 | in and out | 0x0000 | 0xBB3D | ARC and LHA archives, AUTOSAR |
| CRC-16/USB | 0x8005 | 0xFFFF | in and out | 0xFFFF | 0xB4C8 | USB data packets |
| CRC-16/IBM-SDLC | 0x1021 | 0xFFFF | in and out | 0xFFFF | 0x906E | HDLC, X.25, ISO/IEC 14443 Type B |
| CRC-16/GENIBUS | 0x1021 | 0xFFFF | none | 0xFFFF | 0xD64E | EPC Gen2 RFID tags |
| CRC-16/MAXIM-DOW | 0x8005 | 0x0000 | in and out | 0xFFFF | 0x44C2 | 1-Wire and iButton memory records |
| CRC-16/DNP | 0x3D65 | 0x0000 | in and out | 0xFFFF | 0xEA82 | DNP3 |
| CRC-16/MCRF4XX | 0x1021 | 0xFFFF | in and out | 0x0000 | 0x6F91 | Microchip MCRF45x RFID |
| CRC-16/UMTS | 0x8005 | 0x0000 | none | 0x0000 | 0xFEE8 | 3GPP UMTS (TS 25.427) |
| CRC-16/SPI-FUJITSU | 0x1021 | 0x1D0F | none | 0x0000 | 0xE5CC | Fujitsu FlexRay SPI |
| CRC-32/ISO-HDLC | 0x04C11DB7 | 0xFFFFFFFF | in and out | 0xFFFFFFFF | 0xCBF43926 | HDLC, V.42, zip, PNG, XZ, AUTOSAR |
| CRC-32/ISCSI | 0x1EDC6F41 | 0xFFFFFFFF | in and out | 0xFFFFFFFF | 0xE3069283 | iSCSI, NVMe over TCP |
| CRC-32/MPEG-2 | 0x04C11DB7 | 0xFFFFFFFF | none | 0x00000000 | 0x0376E6E7 | MPEG-2 systems (ISO/IEC 13818-1) |
| CRC-32/BZIP2 | 0x04C11DB7 | 0xFFFFFFFF | none | 0xFFFFFFFF | 0xFC891918 | ATM AAL5, DECT B-field, bzip2 |
| CRC-32/CKSUM | 0x04C11DB7 | 0x00000000 | none | 0xFFFFFFFF | 0x765E7680 | POSIX cksum polynomial (the tool also feeds in the length) |
| CRC-32/JAMCRC | 0x04C11DB7 | 0xFFFFFFFF | in and out | 0x00000000 | 0x340BC6D9 | CRC-32 without the final inversion |
| CRC-32/AUTOSAR | 0xF4ACFB13 | 0xFFFFFFFF | in and out | 0xFFFFFFFF | 0x1697D06A | AUTOSAR CRC routines (polynomial 0xF4ACFB13) |
| CRC-64/XZ | 0x42F0E1EBA9EA3693 | 0xFFFFFFFFFFFFFFFF | in and out | 0xFFFFFFFFFFFFFFFF | 0x995DC9BBDF1939FA | XZ, AUTOSAR; often mislabeled ECMA |
| CRC-64/ECMA-182 | 0x42F0E1EBA9EA3693 | 0x0000000000000000 | none | 0x0000000000000000 | 0x6C40DF5F0B497347 | ECMA-182, DLT-1 tape |
| CRC-7/MMC | 0x09 | 0x00 | none | 0x00 | 0x75 | MMC and SD card command frames |
| CRC-12/UMTS | 0x80F | 0x000 | out only | 0x000 | 0xDAF | 3GPP UMTS (TS 25.212); reflects the output only |
| CRC-24/BLE | 0x00065B | 0x555555 | in and out | 0x000000 | 0xC25A56 | Bluetooth Low Energy advertising and test packets |
| CRC-24/OPENPGP | 0x864CFB | 0xB704CE | none | 0x000000 | 0x21CF02 | OpenPGP ASCII armor (RFC 4880) |
Datasheets and code write the same polynomial in three ways. This calculator takes the normal form; reversed values such as 0xA001 appear in right-shifting code, and Koopman’s tables drop the x⁰ term instead of the top one.
| Polynomial | Normal | Reversed | Koopman |
|---|---|---|---|
| CRC-8 (SMBus, ATM) | 0x07 | 0xE0 | 0x83 |
| CRC-8 (Maxim 1-Wire, Sensirion) | 0x31 | 0x8C | 0x98 |
| CRC-8 (SAE J1850) | 0x1D | 0xB8 | 0x8E |
| CRC-16 (CCITT family) | 0x1021 | 0x8408 | 0x8810 |
| CRC-16 (IBM, Modbus, USB) | 0x8005 | 0xA001 | 0xC002 |
| CRC-32 (ISO-HDLC, MPEG-2) | 0x04C11DB7 | 0xEDB88320 | 0x82608EDB |
| CRC-32C (Castagnoli) | 0x1EDC6F41 | 0x82F63B78 | 0x8F6E37A0 |
| CRC-64 (XZ, ECMA-182) | 0x42F0E1EBA9EA3693 | 0xC96C5795D7870F42 | 0xA17870F5D4F51B49 |
CRC-16/MODBUS: polynomial 0x8005, init 0xFFFF, input and output reflected, no final XOR. Its check value is 0x4B37. The specification sends the low byte first, so a CRC of 0x1241 appears on the wire as 41 12.
Select CRC-16/MODBUS, enter the frame as hex bytes without its CRC, and read the result. The bytes 02 07 give 0x1241, sent low byte first as 41 12.
The CRC of the nine ASCII bytes "123456789". Catalogues publish it so you can test an implementation, and getting the listed value almost always means the six parameters are right. It is not proof: CRC-8/MAXIM-DOW and CRC-8/I-432-1 both give 0xA1, so try a second message as well.
The name is used for several algorithms that share polynomial 0x1021. CRC-16/IBM-3740, often called CCITT-FALSE, gives 0x29B1; CRC-16/XMODEM gives 0x31C3; CRC-16/KERMIT gives 0x2189. The RevEng catalogue treats KERMIT as the customary meaning of CRC-CCITT, so check the init and reflection rather than the name.
RefIn true means each input byte is processed least significant bit first. RefOut true means the finished register is bit-reversed before the final XOR. Serial links that send LSB first usually use both, which is why the code for those CRCs shifts right.
Usually one of four things: a different init or XorOut under the same name, the polynomial entered in reversed form, the CRC bytes compared in the wrong order, or a trailing line break hashed along with the text. Run every preset on your data to see which one gives the value you expect.
A W-bit CRC whose polynomial has an x⁰ term catches every burst of W bits or fewer, and misses about 1 in 2^W longer random corruptions. How many scattered bit errors it is guaranteed to catch depends on the polynomial and message length: Koopman publishes those Hamming distance tables.
They use different polynomials. In Koopman’s tables the Ethernet and zip polynomial 0x04C11DB7 keeps Hamming distance 6 up to 268 data bits and distance 4 up to 91,607 bits, while Castagnoli 0x1EDC6F41 keeps distance 6 up to 5,243 bits. CRC-32C is the better code at those lengths, and many CPUs compute it in hardware.
A table uses 256 bytes of flash for CRC-8, 512 for CRC-16 and 1,024 for CRC-32, and handles a byte in one lookup. The bitwise loop needs no table but runs eight shift steps per byte. Use the bitwise form on tiny parts with short messages and the table anywhere throughput matters.
Yes. Pick a preset or enter your own parameters, and the C output gives the table and the routine for that exact CRC. Switch the code style to a bit-by-bit loop if you would rather not spend the flash.
See all free electronics tools →
ProtoFlow is free AI PCB design software: describe a circuit and get a schematic with real parts, PCB layout with an autorouter, SPICE simulation and Gerber files. Native KiCad, Altium and EAGLE import and export. Free on macOS, Windows and Linux.
Free to start. No card required.