MODBUS CRC Calculator and Frame Parser (RTU, ASCII, TCP)
Paste a MODBUS frame in any hex notation and see at once whether its checksum is right, what every byte means and what the registers hold. The calculator recognises MODBUS RTU, ASCII and TCP on its own, checks the RTU CRC in both byte orders and the ASCII LRC, and adds the checksum to data that has none. It runs in your browser; nothing is sent anywhere.
MODBUS frames or data
How the calculator reads a frame
Every line is tried as each MODBUS variant; the first one whose structure holds wins:
| Variant | How it is recognised | Checksum |
|---|---|---|
| MODBUS TCP | Bytes 3 and 4 are 00 00 (protocol ID) and bytes 5 and 6 give the number of bytes that follow | None: the MBAP header replaces it |
| MODBUS ASCII | The line starts with a colon and holds hex digits only, as text or as the bytes 3A 30 31 ... | LRC, the last byte |
| MODBUS RTU | The last two bytes are the CRC of the bytes before them, low byte first or swapped | CRC-16, the last two bytes |
| Data without a checksum | None of the above, and the length fits a request or response without a checksum | The calculator shows the CRC and LRC to add |
The direction is being detected from the length. A request to read registers is always 6 bytes plus the checksum; a response carries a byte count. When a response to function 01 to 04 follows its request on the next line, the calculator names the registers by their numbers (40001 ...) and checks that the count matches. Register values of 03 and 04 responses are shown in every type: 32-bit and 64-bit floats and integers, text, and BCD date and time are recognised automatically, in any byte and word order.
How the MODBUS CRC is calculated
MODBUS RTU uses CRC-16/MODBUS: the polynomial 0x8005 in reflected form (0xA001), start value 0xFFFF, no final XOR. The CRC covers every byte of the frame from the slave ID to the last data byte and is sent low byte first. For the request 01 03 00 00 00 0A the CRC is 0xCDC5, so the complete frame is 01 03 00 00 00 0A C5 CD.
uint16_t modbus_crc(const uint8_t *buf, size_t len)
{
uint16_t crc = 0xFFFF;
for (size_t i = 0; i < len; i++) {
crc ^= buf[i];
for (int b = 0; b < 8; b++)
crc = (crc & 1) ? (crc >> 1) ^ 0xA001 : crc >> 1;
}
return crc; /* send crc & 0xFF first, then crc >> 8 */
}
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 # 01 03 00 00 00 0A -> 0xCDC5, sent as C5 CD
A few devices send the two CRC bytes the other way round, high byte first. That is not standard MODBUS, but the frame is otherwise fine; the calculator marks it CRC swapped, and software that talks to such a device has to accept that order. The MODBUS tester can send requests with a swapped CRC as well.
MODBUS ASCII: the LRC
A MODBUS ASCII frame is text: a colon, every byte as two hex characters, the LRC as two more characters, and CR LF. The LRC is the two's complement of the 8-bit sum of the bytes (not the characters) between the colon and the LRC. For 01 03 00 00 00 0A the sum is 0x0E, so the LRC is F2 and the frame reads :01030000000AF2 followed by CR LF.
MODBUS TCP: no checksum
A MODBUS TCP frame carries no CRC; TCP protects the data. Instead it starts with the 7-byte MBAP header: a transaction ID that the response repeats, the protocol ID 0, the number of bytes that follow, and the unit ID, which a gateway uses as the slave ID of the device behind it. The request above reads 00 01 00 00 00 06 01 03 00 00 00 0A over TCP. For every frame the calculator also shows its RTU, ASCII and TCP form, ready to copy.
When the CRC is wrong
| Cause | What points to it |
|---|---|
| Noise on the line | Errors come and go; long cables, no terminators, no common ground |
| Port settings close to the device's | Most answers fail; a wrong parity or baud rate turns every byte |
| Two devices with the same slave ID | Answers collide on the bus |
| A frame copied incompletely | A byte is missing or doubled; compare the length with the byte count |
| A non-standard device | The CRC is right but swapped: the calculator says so |
More causes are on the garbled serial data and COM port errors pages.
Input formats
Hex bytes may be separated by spaces, commas, semicolons, dashes or colons, or written without separators: 01 03 00 0A, 0103000A, 01-03-00-0A. Prefixes and suffixes such as 0x01, #01, $01, \x01 and 01h are accepted, and so is a C array such as {0x01, 0x03, 0x00, 0x0A}. A MODBUS ASCII frame can be pasted as text, with or without CR LF at the end. Each line is one frame; up to 20 lines are read, so a request and its response can be pasted together. Paste puts the text on your clipboard into the field in one click; the browser may ask for permission the first time.
Test a device or capture the traffic
The calculator works with frames you already have. To get them from a device:
- Send requests to a device from the browser and see every answer byte by byte: the online MODBUS tester. To find the slave ID first, use the MODBUS scanner.
- Watch the traffic between a master and its devices, act as a master or a slave, and decode frames on the fly: Advanced Serial Port Monitor with its MODBUS plugin.
- Poll devices around the clock and log the values to files, Excel or a database: Advanced Serial Data Logger with the MODBUS plugin.
Frequently asked questions
How is the MODBUS CRC calculated?
MODBUS RTU uses CRC-16/MODBUS: start with 0xFFFF, XOR each byte into the low byte, then shift right 8 times, XOR with 0xA001 whenever the bit shifted out is 1. The result is appended low byte first. For 01 03 00 00 00 0A the CRC is 0xCDC5, sent as C5 CD.
Which CRC byte comes first in MODBUS RTU?
The low byte. A few devices send the high byte first; this calculator recognises that swapped order and says so.
Does MODBUS TCP use a CRC?
No. A MODBUS TCP frame starts with a 7-byte MBAP header instead (transaction ID, protocol ID 0, length, unit ID) and has no checksum, because TCP protects the data itself.
How is the MODBUS ASCII LRC calculated?
Add up all bytes between the colon and the LRC (slave ID, function and data, as bytes, not characters), keep the low 8 bits and take the two's complement. For 01 03 00 00 00 0A the sum is 0x0E and the LRC is F2.
Why does the CRC of my frame not match?
A byte changed on the way (noise, a missing ground or terminator), the port settings are close but not equal to the device's settings, two devices answer at once (interferences on the RS485 bus), or the frame was copied incompletely. If the calculator reports the CRC as swapped, the device uses a non-standard byte order.
Does the calculator send my data anywhere?
No. Everything is calculated in your browser. The page only records which buttons are used to collect overall anonymous usage stats, without the frames.