Modbus Addressing: 0-Based vs 1-Based (The 40001 Trap)
If you have ever typed 40001 into QModMaster’s Start Address field and gotten nothing back — no data, a timeout, or an “illegal data address” exception — you have hit the most common addressing mistake in Modbus. It is not a bug in QModMaster. It is two numbering systems colliding, and it bites almost every beginner.
QModMaster is a free, open-source (LGPLv3) Modbus RTU/TCP master simulator for Windows and Linux — grab it from the download page if you haven’t already. Its Start Address field always expects the protocol address, which is 0-based. Most device manuals print something else entirely.
Protocol address vs. register number
Modbus has two ways to refer to the same register. Confusing them is the entire trap:
- Protocol address (0-based): the number that actually goes on the wire inside the request frame. The first register of each type is address 0.
- Register number (1-based): the number printed in device manuals, following the old Modicon convention. The first holding register is 40001.
The Modicon scheme tags each register type with a leading digit:
| Register type | Number range | Read with | Write with |
|---|---|---|---|
| Coils | 00001–09999 | FC 01 | FC 05 / 15 |
| Discrete inputs | 10001–19999 | FC 02 | — (read-only) |
| Input registers | 30001–39999 | FC 04 | — (read-only) |
| Holding registers | 40001–49999 | FC 03 | FC 06 / 16 |
QModMaster uses 0-based addresses
The Start Address field in QModMaster always takes the protocol address. When your manual says “oil temperature is in holding register 40001“, you enter 0 — not 40001.
| Manual says | Enter in Start Address | Math |
|---|---|---|
| Holding Register 40001 | 0 | 40001 − 40001 |
| Holding Register 40002 | 1 | 40002 − 40001 |
| Holding Register 40010 | 9 | 40010 − 40001 |
| Input Register 30001 | 0 | 30001 − 30001 (use FC 04) |
| Coil 00001 | 0 | 1 − 1 (use FC 01) |
| Discrete Input 10001 | 0 | 10001 − 10001 (use FC 02) |
Some manuals — PLCs especially — use 6-digit numbering (400001 instead of 40001). Same rule: strip the leading type digit(s) and subtract, so 400001 becomes address 0.
The ±1 offset fix
Even with the conversion right, some devices are genuinely off by one — their firmware numbers the first register as 1, or the manual’s table is shifted. If reads return the wrong values, or fail with an illegal-data-address exception, do this:
- Pick one register whose value you know — a device ID, serial number, or firmware version straight from the manual.
- Read it at the converted address. If it fails or the value is wrong, add 1 to Start Address and read again.
- Still wrong? Subtract 1 from the original instead.
- The moment the known register reads correctly, the offset is confirmed — apply it to every address on that device.
This works identically on Modbus RTU and Modbus TCP. Addressing lives in the Modbus application layer; the transport only changes the framing.
Frequently asked questions
Why does my manual say register 40001 but QModMaster reads nothing at address 40001?
Because 40001 is the register number, not the protocol address. On the wire, holding registers live at addresses 0–9998, so a request for address 40001 points far outside the valid block. The device answers with exception code 02 (illegal data address) or simply times out. Enter 0 instead.
My manual uses 6-digit numbers like 400001. What do I enter?
The same rule with one more digit: protocol address = register number − 400001. So 400001 becomes 0, 400002 becomes 1. This extended numbering is common on PLCs with large register maps.
I get values back, but every value is shifted by one register. Why?
Classic off-by-one: the device’s first register is address 1 in its firmware, or the manual’s table starts counting at 1. Shift your Start Address by ±1 and re-read a known register until the values line up, then keep that offset for the whole device.
Does the 0-based vs 1-based issue apply to Modbus TCP too?
Yes. Addressing is part of the Modbus protocol itself, not the serial line. RTU and TCP use identical protocol addresses — only the framing differs (raw serial bytes vs. the MBAP header).
Related Guides
- QModMaster User Manual — every setting in the RTU/TCP dialogs explained
- QModMaster Tutorial: Your First Poll in 10 Minutes — from install to live data
- What Is a Modbus Master? — master/slave roles and function codes
- Download QModMaster — free, open-source (LGPLv3), Windows and Linux
