A Modbus register map lists the values that a device publishes and where to find them. For each value it should give the register table, the address, the data type, the word order, the scale and the unit. Most wrong Modbus readings come from one of those six fields, not from the connection. This guide explains each field and how to prove that you read it correctly.
This guide is part of the Modbus and RS-485 series. The same rules apply to Modbus RTU and Modbus TCP.
The four register tables
The Modbus application protocol defines four tables. Each table has its own function codes:
| Table | Size | Access | Read with | Write with | Classic reference |
|---|---|---|---|---|---|
| Coils | 1 bit | Read and write | 01 | 05, 15 | 0xxxx |
| Discrete inputs | 1 bit | Read only | 02 | None | 1xxxx |
| Input registers | 16 bits | Read only | 04 | None | 3xxxx |
| Holding registers | 16 bits | Read and write | 03 | 06, 16 | 4xxxx |
Energy meters usually publish measurements in input registers or holding registers, and settings in holding registers. Use the function code that the map names. Reading an input register with function 03 returns another value, or an exception.
Address conventions
Register maps write the same register in several ways. The request on the wire always carries a zero-based address:
| Written in the map | Meaning | Address in the request |
|---|---|---|
| 40001 | Classic five-digit reference: table 4, register 1 | 0 |
| 400001 | Six-digit extended reference | 0 |
| 1 (one-based) | Register 1 of the table named in the map | 0 |
| 0 or 0x0000 (zero-based) | Protocol address | 0 |
A map that mixes conventions, or a configuration tool that expects a different one, gives an off-by-one error: every value comes from the register next to the right one. Confirm the convention on one known value first. The Modbus address converter translates between the forms:
Data types
A register is 16 bits. The map gives the type that the bits represent:
| Type | Registers | Range or precision |
|---|---|---|
| uint16 | 1 | 0 to 65,535 |
| int16 | 1 | −32,768 to 32,767 |
| uint32, int32 | 2 | About ±2.1 billion (signed) or 0 to 4.29 billion |
| float32 (IEEE 754) | 2 | About 7 significant digits |
| uint64, int64 | 4 | Exact whole numbers to 18 or more digits |
| float64 | 4 | About 15 to 16 significant digits |
The same bits give different numbers in different types. The register value 0xFFF6 is 65,526 as uint16 and −10 as int16. Read the sign from the map, not from the value.
A float32 has about seven significant digits. An energy counter stored as float32 at 12,345,678.9 kWh can no longer show a change of 0.1 kWh. That is why many meters also publish energy as a 32-bit or 64-bit integer.
Word order in 32-bit and 64-bit values
The Modbus specification defines the byte order inside one register (high byte first). It does not define the order of the registers in a multi-register value, so manufacturers differ. Name the order by the bytes of the value, A being the most significant:
| Order | Registers as read | Common description |
|---|---|---|
| ABCD | high word, then low word | Big-endian, high word first |
| CDAB | low word, then high word | Word swapped |
| BADC | high word first, bytes swapped | Byte swapped |
| DCBA | low word first, bytes swapped | Little-endian |
A wrong order gives a number that looks random, not one that is slightly wrong. A uint32 counter of 100,000 reads as 0x0001 then 0x86A0 in ABCD order. Read in the wrong order, the same words give 2,258,632,705:
The Modbus register decoder shows all four orders side by side, and the IEEE 754 float converter shows how a float is encoded.
Scaling and units
Many meters send an integer and a scale. The map may give the scale in one of three ways:
- A fixed factor. "Voltage, uint16, 0.1 V": a raw value of 2,305 is 230.5 V.
- A power of ten. "Energy, int32, 10−2 kWh": a raw value of 1,234,567 is 12,345.67 kWh.
- A scale-factor register. The SunSpec models used by many inverters publish a separate register with the power of ten for a group of values. Read the scale factor in the same request as the value, because it can change.
Apply the steps in order: decode the type, apply the scale, then the unit. Record where the scaling happens. If the device, a gateway and the receiving platform all apply a factor, the value is scaled twice. A value 10 or 1,000 times too large is the usual sign.
For energy counters, also record the rollover value and what the device does at rollover or reset. The pulse meter guide covers the same problem for pulse counters.
Status words and bit fields
A status register packs flags into the 16 bits of one register. Bit 0 is the least significant bit. A status value of 0x0025 is binary 0000 0000 0010 0101, so bits 0, 2 and 5 are set. The map gives the meaning of each bit, and whether 1 means active or healthy.
Two rules keep bit fields safe:
- Read the meaning from the map. A bit position is not an alarm definition. Record the meaning of 0 and 1 for each bit that you use.
- Do not write a whole status or control word to change one bit. You overwrite the other bits with whatever your software last read. Use the device's documented method: a separate command register, function 22 (mask write) if the device supports it, or a read, change and write sequence approved by the equipment owner.
Not-available and invalid values
Many devices return a fixed code when a value is not available, for example 0xFFFF, 0x8000 or a float NaN. SunSpec defines these codes for its models, and other maps list their own. If the map lists them, handle them before scaling, and store the reading as missing, not as a number. A value of −32,768 V is a code, not a measurement.
Prove each point
A clean response proves the connection, not the meaning. For each point:
- Record the raw register words, the decoded value and the scaled value.
- Compare with the device display, or a reference instrument, at the same moment.
- Repeat at a second operating state: a load on and off, or a set point changed.
- Check a negative value if the point can go negative, such as export power.
- Keep all of it in the acceptance record.
The Modbus RS-485 commissioning guide gives the full sequence, and the Modbus troubleshooting guide covers exception responses and values that look plausible but are wrong.
Register maps in the Device Directory and Edge
The Device Directory collects register maps for common Modbus meters, with the data type and word order of each point. Edge reads Modbus TCP and Modbus RTU devices from the Gateway. For each point you set the function code, the zero-based address, a 16-bit or 32-bit data type, the byte and word order, and a multiplier and offset. Edge treats a float NaN as not available. An integer code such as 0xFFFF stays a number, so handle it with a calculated point if the map defines one. For a meter far from the Gateway, a ZMB Modbus interface reads up to 30 registers locally and sends them over the Zigbee mesh.
Common questions
What is the difference between holding registers and input registers?
Both hold 16-bit values. Input registers are read-only and are read with function 04. Holding registers can be read with function 03 and, where the device allows it, written with functions 06 and 16. Many meters put their measurements in input registers and their settings in holding registers, but some put everything in holding registers.
What does Modbus address 40001 mean?
It is the first holding register in the classic reference notation, where the leading 4 names the holding register table. The request on the wire sends address 0 with function 03. Some maps use a six-digit form (400001) or plain numbers starting at 0 or 1.
What is Modbus word order?
A 32-bit value takes two 16-bit registers. The Modbus specification does not say which register holds the high half, so manufacturers differ. If a value decodes to a nonsense number, try swapping the two words (ABCD to CDAB).
How many registers can I read in one request?
Up to 125 registers with function 03 or 04, according to the Modbus application protocol specification. Many devices accept fewer, and some return an exception if a block crosses a gap in their map.