Source: Modbus Chinese Network (modbus. cn) - a leading Modbus communication protocol technology community in China
This article: Detection and Diagnosis of Modbus Communication Errors: A Complete System from Parity Check to Exception Code · Author: Modbus Technical Team · Published on July 1, 2026
Abstract: The error detection of Modbus protocol is divided into three levels - character level parity check, frame level LRC/CRC check, and application level exception response code and timeout mechanism. This article breaks down the working principle, algorithm implementation (including runnable C/Python code), and practical debugging purposes of each detection method one by one, and provides a complete exception code lookup table and troubleshooting process. Keywords: Modbus CRC, LRC checksum, parity check, Modbus exception code, Modbus error detection CRC16 Modbus。
Transmitting a Modbus frame on the RS-485 bus is like shouting in a noisy workshop - what's shouted out is01 03 00 00 00 01The possibility of receiving it from the other end has become01 03 00 00 00 03By flipping one bit, the temperature reading changes from 25 ° C to 26 ° C, or the reason why a certain valve is not moving is buried here.
Modbus was born in 1979 with a layered error detection mechanism: each character uses parity to block bit errors, the entire frame of data is backed by CRC (RTU mode) or LRC (ASCII mode), and the application layer then tells the master station through an exception response code that 'there is a problem with your request'. These three layers of mechanisms, combined with the timeout retransmission strategy, form the reliable foundation for Modbus to survive in the industrial field for nearly fifty years.
To be frank, Modbus error detection is not cryptographic level - CRC16 cannot be tamper proof, and LRC may miss consecutive even bit errors. But in a physical environment with 9600bps and several tens of meters of RS-485 bus, these mechanisms are already sufficient. Their value lies not in theoretical perfection, but in their simple implementation and low computational overhead - an 8-bit microcontroller can complete CRC16 calculations in less than 100 bytes of code.
1、 Three layer architecture for error detection
The error detection of Modbus serial communication is divided into three levels, covering the entire communication stack from top to bottom:
application layer:Abnormal response code + Timeout retransmission
↓
Frame layer :CRC-16(RTU)or LRC(ASCII)
↓
Character layer:parity check(Even/Odd/None)Character layerProtecting the transmission correctness of each byte - adding a checksum to 8 data bits in a UART frame, the hardware automatically completes the verification.
Frame layerProtect the integrity of the entire Modbus message - from the station address to the last data byte, all are involved in the calculation. If the frame check fails, the device silently discards this message and does not reply with any content.
application layerDealing with situations where the physical layer is fine, but there are logical issues - such as the feature code device you requested not being supported, the register address not being present, or the data value being out of range. These errors are reported to the main station through exception response codes.
Each layer has its own responsibilities, but during debugging, engineers are more likely to see exception codes in the application layer, while ignoring parity errors in the physical layer - because parity errors are discarded at the device hardware level and you cannot see them at all.
2、 Character layer: parity check
2.1 Principle
Parity check is the process of adding a check bit to each UART character frame, so that the total number of "1s" in the entire frame is odd (Odd check, Odd) or even (Even check, Even).
The character frame definition of Modbus varies depending on the mode:
| pattern | start position | data bit | check digit | stop bit | Total digits |
|---|---|---|---|---|---|
| RTU (with verification) | 1 | 8 | 1 | 1 | 11 |
| RTU (without verification) | 1 | 8 | 0 | 2 | 11 |
| ASCII | 1 | 7 | 1 | 1 | 10 |
Note that when there is no verification in RTU, use 2 stop bits to add up the total number of bits - this is a mandatory requirement. Many people choose No Parity when configuring serial port parameters but forget to change the stop bit from 1 to 2. As a result, communication is unstable but not completely disconnected, making it very difficult to check.
2.2 Calculation Example
Take a byte:11000101The number of 1s is 4 (even).
- Even check → check bit=0, keep the total number of 1s even (4)
- Odd check → check bit=1, making the total number of 1s odd (5)
The hardware UART automatically calculates and fills in the checksum when sending, and automatically verifies when receiving. If the receiver fails the verification, the UART hardware will mark a parity error, but it will not automatically discard the data - whether to discard it or not is determined by the software.
2.3 Limitations of Parity Check
Parity check can only detectOdd number of bit errorsIf exactly 2 bits are flipped during transmission, the parity remains unchanged, the check passes, but the data is already incorrect. On RS-485, the probability of single bit flipping caused by electromagnetic interference is much higher than that of multi bit flipping at the same time, so parity check is still useful in practice - but it is by no means omnipotent.
Debugging suggestionsIf you suspect there is a problem with the quality of the circuit, use a logic analyzer to capture UART frames and check the parity error flag for each character. Serial assistant (such as SSCOM) can display the number of parity errors. If this counter keeps rising, it indicates that there is electromagnetic interference in your physical circuit - it may be due to unshielded cables, being in the same bridge as the frequency converter, or signal reflection caused by unconnected terminal resistors.
3、 Frame layer (1): LRC verification - Modbus ASCII mode
3.1 What is LRC
Longitudinal Redundancy Check (LRC) is a frame check algorithm used in Modbus ASCII mode. It is an 8-bit (1-byte) checksum located at the end of the frame, with a checksum range of all bytes from the station address to the data area, excluding the frame header (colon):)And at the end of the frame (carriage return line break CR/LF).
3.2 Modbus ASCII Frame Structure
: 01 03 21 02 00 02 D7 CR LF
│ └─────────┬────────────┘ │
frame header LRC Verification scope LRCcodeA complete Modbus ASCII request frame:
:0103020002F8rn3.3 LRC algorithm
The algorithm is extremely simple - three steps:
- Add up all bytes from the address code to the data area and calculate the sum
- The lower 8 bits of the sum (modulo 256)
- Take its complement (subtract this value from 256, or take the bitwise inverse and add 1)
Example: Message: 01 03 21 02 00 02
summation:0x01 + 0x03 + 0x21 + 0x02 + 0x00 + 0x02 = 0x29
low 8 bit:0x29
two's complement:256 - 0x29 = 0xD7
LRC Verification code = D7The complete frame is:: 01 03 21 02 00 02 D7 rn
3.4 Implementation of LRC in C Language
/**
* 计算 Modbus ASCII LRC 校验码
* buf: 需要校验的数据(从地址码到数据区的所有字节)
* len: 字节数
* 返回值: 1 字节 LRC 校验码
*/
unsigned char LRC(unsigned char *buf, unsigned short len)
{
unsigned char lrc = 0;
while (len--) {
lrc += *buf++;
}
// 取补码:256 - lrc,等效于 (-lrc)
return (unsigned char)(-lrc);
}Verify with Python:
def calc_lrc(data: bytes) -> int:
"""Calculation Modbus ASCII LRC Verification code"""
return (256 - (sum(data) & 0xFF)) & 0xFF
# Test
msg = bytes([0x01, 0x03, 0x21, 0x02, 0x00, 0x02])
lrc = calc_lrc(msg)
print(f"LRC: 0x{lrc:02X}") # Output: LRC: 0xD73.5 Limitations of LRC
LRC can only detect a certain proportion of errors. If the same bit of two bytes is flipped simultaneously (for example, the 3rd bit of byte A changes from 0 to 1, and the 3rd bit of byte B changes from 1 to 0), the sum result remains unchanged, and the LRC check passes. That's also why Modbus RTU uses the stronger CRC-16 instead of LRC - RTU mode is used for binary data transmission with higher reliability requirements, while ASCII mode is mainly used for debugging and compatibility with older devices.
4、 Frame layer (2): CRC-16 verification - Modbus RTU mode
4.1 Mathematical Definition of CRC-16 Modbus
Modbus RTU uses CRC-16 algorithm with the following parameters:
| parameter | 值 |
|---|---|
| width | 16 bits |
| Generate polynomial | 0x8005(x¹⁶ + x¹⁵ + x² + 1) |
| Actual polynomial operation | 0xA001 (x805 bit reversed form) |
| initial value | 0xFFFF |
| Input byte reflection | 否 |
| Output CRC reflection | Yes (exchange of high and low bytes in the final result) |
| Output XOR value | 0x0000 |
The concept of 'bit reversal' here is easily confused in the CRC parameter system. The calculation of Modbus is actually processed bit by bit, shifted from LSB direction, using the inversion polynomial 0xA001, and the calculation result is naturally inverted - so there is no need to do a global inversion again in the end, onlyHigh low byte exchangeWhen sending, the low byte comes first and the high byte comes last.
4.2 CRC-16 Modbus Algorithm Flow (Bit by Bit Calculation Method)
Calculating bit by bit may be slow, but it allows people to see clearly what happens at each step:
- The preset 16 bit CRC register is
0xFFFF - XOR the first byte of the message with the lower 8 bits of the CRC register, and store the result back in the CRC register
- Move the CRC register to the right by 1 bit, add 0 to the highest bit, and check the removed lowest bit
- Move out bit=1 → XOR CRC register with 0xA001; Move out position=0 → No action taken
- Repeat steps 3-4 for a total of 8 times (processing 8 bits of one byte)
- Repeat steps 2-5 to process the next byte in the message
- After all byte processing is completed, the low byte of the CRC register comes first and the high byte comes last, which is the CRC-16 checksum
4.3 CRC-16 Modbus C Language Implementation
/**
* 计算 Modbus RTU CRC-16 校验码(逐位计算法)
* buf: 需要校验的数据(从地址码到数据区的所有字节)
* len: 字节数
* 返回值: 16 位 CRC 值(低字节在前)
*/
unsigned short CRC16_Modbus(unsigned char *buf, unsigned short len)
{
unsigned short crc = 0xFFFF;
unsigned short i, j;
for (i = 0; i < len; i++) {
crc ^= buf[i]; // 步骤 2
for (j = 0; j < 8; j++) { // 步骤 3~5 循环 8 次
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001; // 移出位为 1
} else {
crc >>= 1; // 移出位为 0
}
}
}
// 注意:Modbus CRC 发送时低字节在前
return crc;
}4.4 Table lookup method - standard implementation on embedded devices
Calculating each byte bit by bit requires 8 cycles, which is too costly for embedded MCUs. In engineering, the lookup table method is used, which calculates the CRC value of 256 bytes in advance, and only performs one lookup table, one XOR, and one shift per byte.
High level table lookup method(Most commonly used):
/* CRC 高位表 */
static const unsigned char auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
/* ... 完整 256 项,此处省略 */
};
/* CRC 低位表 */
static const unsigned char auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
/* ... 完整 256 项,此处省略 */
};
unsigned short CRC16_Modbus_Table(unsigned char *buf, unsigned short len)
{
unsigned char crcHi = 0xFF;
unsigned char crcLo = 0xFF;
unsigned short index;
while (len--) {
index = crcLo ^ *buf++;
crcLo = crcHi ^ auchCRCHi[index];
crcHi = auchCRCLo[index];
}
return (crcHi << 8) | crcLo;
}The complete high and low bit table consists of 512 bytes and can be directly copied from the Modbus protocol specification appendix. The complete example table is provided on page 40 of the Modbus.org V1.1b3 specification.
4.5 Verify Your CRC Implementation
Test with known messages:
message: 01 03 00 00 00 01
correct CRC: 84 0A(Low byte first)
Verification steps:
crc = 0xFFFF
crc ^= 0x01 → 0xFFFE
bit0=0, crc>>1 → 0x7FFF
bit1=1, (0x3FFF) ^ 0xA001 → 0x9FFE
...
finally crc = 0x0A84
Low byte before sending: 84 0AThe entire message sending sequence:01 03 00 00 00 01 84 0A
You can also use Modbus Poll or Modbus Mini Program to directly calculate CRC and implement cross validation with your code.
4.6 CRC's error detection capability
CRC-16 can detect the following types of errors:
- All single bit errors
- All double bit errors (under the condition that the message does not exceed 32767 bits)
- All odd numbered bits are incorrect
- All sudden errors, length ≤ 16 bits
- 99.998% of longer burst errors
Simply put, CRC-16 can capture almost all physical layer transmission errors on the premise that Modbus frames typically do not exceed 256 bytes. The data frames that pass the CRC check can be basically trusted.
5、 Application layer: Exception response code
The physical layer and frame checksum have both passed, and a complete and valid Modbus frame has been received from the device - but logically it is incorrect. At this point, the device is not silent, but returns an abnormal response, telling the main station 'I cannot do what you asked me to do'.
5.1 Frame format for abnormal response
The difference between normal response and abnormal response is only one:The highest digit of the function code。
- Normal response: Function code=Original function code (e.g. 0x03 read hold register)
- Exception response: Function code=original function code+0x80 (e.g. 0x83), followed by a byte of exception code
ExampleThe main station requests to read the register01 03 00 00 00 01 84 0A
Normal response:01 03 02 00 7B F9 8D(Read back 2-byte data)00 7B)
Abnormal response (assuming register does not exist):01 83 02 C0 F1
83=0x03 (original function code)+0x8002=Exception code, indicating 'illegal data address'
5.2 Standard Exception Code Quick Check Table
| Exception Code | Name | meaning | Common Causes |
|---|---|---|---|
| 0x01 | Illegal Function | Illegal function codes | The device does not support this function code (such as sending write commands to read-only devices) |
| 0x02 | Illegal Data Address | Illegal data address | Register address out of range, or starting address+quantity out of range |
| 0x03 | Illegal Data Value | Illegal data values | The value written exceeds the allowed range of the register |
| 0x04 | Slave Device Failure | From equipment malfunction | An unrecoverable error occurred while the device was performing an operation |
| 0x05 | Acknowledge | Confirmation (currently being processed) | The request has been accepted but will take a long time to process. The main station should wait |
| 0x06 | Slave Device Busy | Busy with devices | The device is processing another command and is temporarily unable to respond |
| 0x07 | Negative Acknowledge | Negative confirmation | The device is unable to perform this function (usually due to non-specific errors) |
| 0x08 | Memory Parity Error | Memory parity error | Extended file area consistency check failed |
0x01 to 0x04 are the easiest to encounter, while 0x05 to 0x08 are relatively rare on conventional Modbus devices - many device manufacturers only implement the first four exception codes.
5.3 Actual Debugging Usage of Exception Codes
Why isn't the device responding to data? "After ruling out physical layer and CRC issues, check the exception code:
Received 0x01 (illegal function)You sent a feature code that is not supported by the device. The most common scenario is when you use 0x03 (read hold register) to read an analog input that can only be accessed through 0x04 (read input register). Go to the register mapping table in the device manual and confirm the access function code corresponding to the address.
Received 0x02 (illegal address)Your starting address plus the number of requests exceeds the address range supported by the device. For example, if the device only has 10 hold registers (addresses 0-9), and you request 12 registers starting from address 0- crossing the boundary. Solution: Reduce the number of registers requested each time, or confirm the device type with 0x11 (report slave ID) before reading.
Received 0x03 (illegal data value)The value you want to write is meaningless to the device. For example, if the device supports a data range of 0-100, you have written 200. Or the number of data bytes written does not match the length required by the function code.
Completely unresponsiveIt's not an exception code, but nothing at all. Possible reasons: CRC error (silently dropped from device), incorrect implementation of frame interval (3.5 character time), device address mismatch. At this point, it is necessary to use a logic analyzer to capture the bus and confirm what has been received from the device and whether there are parity error marks on the UART hardware.
6、 Timeout mechanism: the last line of defense for the main station
The Modbus specification requires the master station to configure a timeout period. Timeout will be triggered in the following situations:
- After the master station sends a request, there is no response from the slave station within the specified time
- The slave station detected a frame error (CRC/LRC failure), silently dropped the frame, and the master station did not receive a reply
- The slave address does not exist - the message was sent to an empty address
There is a constraint on setting the timeout period:Must be greater than the longest possible response time from the deviceThe calculation method is:
timeout period > transmission delay × 2 + Processing time from the stationAt 9600bps, a typical Modbus RTU request (reading 1 register) is approximately 8 bytes=64 bits, with a transmission time of 64/9600 ≈ 6.7ms. The response is approximately 7 bytes=56 bits, with a transmission time of ≈ 5.8ms. Adding the slave processing time (assuming the slowest 50ms), the total bidirectional time is approximately 6.7+50+5.8 ≈ 62.5ms. It is reasonable to leave double the margin and set the timeout to 100-200ms.
If there are multiple slave stations on the bus, the slowest polling device (such as some old PLCs taking 100ms to process a request) should be taken into account. The default timeout recommended by the Modbus specification is 1 second - this value is relatively large for modern devices, but it is safe to start debugging as an initial value.
7、 Complete troubleshooting process
When faced with 'Modbus communication failure', troubleshoot layer by layer in this order:
| 层 | Checklist | Tool | judgment method |
|---|---|---|---|
| physical layer | RS-485 wiring (A/B, common ground, terminal resistance) | Multimeter | Conduction, bus idle level ≥ 200mV |
| Character layer | Serial port parameters (baud rate, data bits, parity bits, stop bits) | Logic Analyzer | Actual measured width=1/baud |
| Character layer | parity error | Logic analyzer/serial port assistant | Parity error count=0 |
| Frame layer | CRC verification | Modbus Mini Program/Self written Code | Receive CRC=Calculate CRC |
| Frame layer | Frame interval (≥ 3.5 character time) | Logic Analyzer | Inter frame idle ≥ 3.6ms @ 9600bps |
| application layer | slave address | Equipment manual/dip switch | Request address=actual address of the slave station |
| application layer | Function code+address range | Device Register Mapping Table | The function code and register address are within the supported range of the device |
| application layer | Abnormal response code | Serial port assistant/packet capture | Check for abnormal codes when the highest bit of the function code is 1 |
| application layer | timeout | Capture the package and check the timestamp | Response time<timeout configuration |
Special attentionWhen interacting with standard Modbus requests such as "01 03 00 00 01", do not directly send ASCII strings - binary frames must be sent. Beginners sent in ASCII mode in the serial assistant0x31 0x30 0x33 0x30 0x30 0x30 0x30 0x30 0x30 0x31(010300000001 for ASCII strings), instead of01 03 00 00 00 01These 6 bytes. Almost everyone who learns Modbus has made this mistake.
The correct calculation of CRC checksum is the cornerstone of reliable Modbus communication. But 90% of the problems on the construction site are not related to CRC itself - in wiring, parameters, address range violations, and incorrect selection of function codes. CRC is more like a safety net, giving you confidence when you say 'data should be right'. When the data is indeed incorrect, first check the first few layers.
Cross validate the code in this article in your project, don't expect to simply copy a CRC code online and use it directly - I have seen too many cases where CRC never passes due to byte order inversion. If you are interested, you can refer to the appendix section of the Modbus.org V1.1b3 specification, which contains complete data for the CRC lookup table and official examples of both high and low bit implementation methods.
Let's talk if there are any issues.
1