Why Is My Modbus Value Wrong?
Why Is My Modbus Value Wrong?
A common Modbus troubleshooting situation is this:
The device responds correctly, but the value shown in the PLC, SCADA, BMS, or commissioning tool is wrong.
This usually means that the communication itself is working, but the raw register data is being interpreted incorrectly.
In other words:
A valid Modbus response does not automatically mean that the displayed value is correct.
The request can be valid, the response can be valid, and the CRC can be correct. The final value can still be wrong if the client uses the wrong data type, byte order, word order, scaling, offset, unit, or register address.
Modbus transfers raw data
Modbus does not know whether a register contains temperature, pressure, power, energy, humidity, a status value, or an alarm code.
It only transfers bits and 16-bit registers.
A Modbus register is:
1 register = 16 bits = 2 bytes = 4 hex digits
Larger values are formed from several consecutive registers:
1 register = 16 bits
2 registers = 32 bits
4 registers = 64 bits
Common data types include:
| Data type | Size | Register count |
|---|---|---|
UINT16 | 16 bits | 1 register |
INT16 | 16 bits | 1 register |
UINT32 | 32 bits | 2 registers |
INT32 | 32 bits | 2 registers |
FLOAT32 | 32 bits | 2 registers |
UINT64 | 64 bits | 4 registers |
INT64 | 64 bits | 4 registers |
FLOAT64 / DOUBLE | 64 bits | 4 registers |
If the documentation says that a value is FLOAT32, the client must read two consecutive 16-bit registers and combine them correctly.
Reading only one register will give the wrong value.
Signed and unsigned values
The same raw 16-bit register can produce very different values depending on whether it is interpreted as signed or unsigned.
Example:
Raw register = 0xFF9C
| Data type | Result |
|---|---|
UINT16 | 65436 |
INT16 | -100 |
As an unsigned value, 0xFF9C means 65436.
As a signed 16-bit value, using two’s complement, it means -100.
This is important for values that can go below zero, such as:
- outdoor temperature
- pressure difference
- calibration offset
- control correction
- power import/export
If the scale factor is 0.1, the final value is:
-100 x 0.1 = -10.0 °C
So a value that first appears as 65436 may actually mean -10.0 °C.
32-bit values use two registers
A 32-bit value is built from two 16-bit registers.
Example:
Register 1 = 0x42F6
Register 2 = 0x0000
The raw bytes are:
42 F6 00 00
Those same bytes can be interpreted in several ways:
| Interpretation | Result |
|---|---|
UINT32 | 1123418112 |
INT32 | 1123418112 |
FLOAT32 | 123.0 |
The raw data is identical. Only the interpretation changes.
If the value is supposed to be a normal measured value, FLOAT32 = 123.0 may make sense. The integer values probably do not.
Byte order and word order
A 32-bit value consists of four bytes. These are often described as:
A B C D
Because Modbus registers are 16-bit, the value is split into two registers:
Register 1 = A B
Register 2 = C D
Common 32-bit byte and word orders are:
| Order | Meaning | Byte sequence |
|---|---|---|
ABCD | normal big-endian order | A B C D |
CDAB | word swapped | C D A B |
BADC | bytes swapped inside each word | B A D C |
DCBA | bytes and words swapped | D C B A |
Using the example registers:
Register 1 = 0x42F6
Register 2 = 0x0000
The possible byte sequences are:
| Order | Byte sequence | FLOAT32 result |
|---|---|---|
ABCD | 42 F6 00 00 | 123.0 |
CDAB | 00 00 42 F6 | very small value |
BADC | F6 42 00 00 | unrealistic value |
DCBA | 00 00 F6 42 | very small value |
This is one of the most common reasons why a Modbus value looks wrong even though the request and response are valid.
Scaling and offset
Many devices do not send the final engineering value directly. Instead, the device sends a raw integer value that must be scaled.
Engineering value = raw value x scale factor
Example:
Raw value = 234
Scale factor = 0.1
Engineering value = 234 x 0.1 = 23.4 °C
Some devices also use an offset:
Engineering value = raw value x scale factor + offset
Example:
Raw value = 234
Scale factor = 0.1
Offset = -50
Engineering value = 234 x 0.1 - 50 = -26.6
The scale factor, offset, and unit must be checked from the device-specific register map.
Register address problems
Wrong values can also come from reading the wrong register.
Some manuals document holding registers as:
40001
40002
40003
But the actual Modbus request may use zero-based addresses:
0
1
2
This means that a register documented as 40001 may need to be requested as address 0.
A register documented as 40008 may need to be requested as address 7.
If the client reads one register too early or one register too late, the device may still respond, but the returned value belongs to another register.
Wrong register type or function code
Modbus has different register areas:
| Register type | Typical function code | Access | Size |
|---|---|---|---|
| Coil | 01 / 05 / 15 | read/write | 1 bit |
| Discrete Input | 02 | read only | 1 bit |
| Input Register | 04 | read only | 16 bits |
| Holding Register | 03 / 06 / 16 | read/write | 16 bits |
Reading address 10 with Function Code 03 is not the same as reading address 10 with Function Code 04.
One reads Holding Registers. The other reads Input Registers.
Troubleshooting checklist
When a Modbus value looks wrong, check these items:
- Is the register address correct?
- Is the device documentation using 0-based or 1-based addressing?
- Is the correct register type being read?
- Is the correct function code being used?
- Is the value signed or unsigned?
- Is the value 16-bit, 32-bit, or 64-bit?
- Are enough registers being read?
- Are the two 16-bit words in the correct order?
- Are bytes inside each word in the correct order?
- Is a scale factor required?
- Is an offset required?
- Is the displayed unit correct?
A good troubleshooting method
Start with the raw register values before converting them into engineering units.
For one-register values, compare:
| Raw register | UINT16 | INT16 |
|---|---|---|
0xFF9C | 65436 | -100 |
For two-register values, compare:
| Interpretation | What it checks |
|---|---|
UINT32 ABCD | normal unsigned 32-bit value |
INT32 ABCD | normal signed 32-bit value |
FLOAT32 ABCD | normal floating-point value |
FLOAT32 CDAB | word-swapped floating-point value |
FLOAT32 BADC | byte-swapped floating-point value |
FLOAT32 DCBA | byte- and word-swapped floating-point value |
If one interpretation gives a realistic value and the others produce impossible values, the realistic one is often the intended format. Confirm it from the device register map before final commissioning.
Conclusion
If a Modbus device responds but the value is wrong, do not immediately assume that the communication is broken.
First check how the raw register data is being interpreted.
Most wrong-value problems are caused by one of these:
- wrong register address
- 0-based vs 1-based address confusion
- wrong register type
- wrong data type
- signed/unsigned mismatch
- byte order mismatch
- word order mismatch
- missing scale factor
- missing offset
- wrong unit
A useful approach is to decode the same raw registers as several possible data types and byte orders. This quickly shows whether the problem is in the communication or in the value conversion.