LearnSCADA

Part I · Chapter 2

The Modbus Data Model

When a client reaches into a server for a value, what is it reaching into? Four small tables. Once you can picture them, most function codes read like plain English: they just move data into or out of these tables.

By the end of this chapter you can

  • Name the four tables and say which hold bits, which hold registers, and which are read-only.
  • Convert a reference number like 40013 to the zero-based address on the wire.
  • Read a register map, and explain why Modbus itself assigns no meaning to the data.

Four tables, two questions

Every Modbus server organizes its data into exactly four tables. That isn't a teaching simplification; it's the model the protocol defines. Each table is a numbered list of storage slots, and the four differ along just two questions:

  1. Is each slot a single bit (on or off) or a sixteen-bit register (a number)?
  2. May the client only read the slot, or also write it?

Two questions with two answers each give four combinations, and those are the four tables.

The Modbus data model as a two by two grid. Columns are bit and register; rows are read-only and read/write. Read-only bits are discrete inputs; read-only registers are input registers; read/write bits are coils; read/write registers are holding registers. Input values change on their own as the field changes; a client writes a new value, 1750, into a holding register. BIT · 1 bit REGISTER · 16 bits READ- ONLY READ / WRITE Discrete inputs 1 bit · read-only · 1xxxx R a switch or status the device senses Input registers 16 bits · read-only · 3xxxx R 235 241 228 612 609 a measured value the device reports Coils 1 bit · read/write · 0xxxx R / W write ON ↓ an output you can turn on or off Holding registers 16 bits · read/write · 4xxxx R / W 60 1500 1750 a setting or value you can change
The whole data model on one page: the cross-product of bit or register, and read-only or read/write. Inputs change because the world changes; coils and holding registers also change when a client writes them.

Commit these four names to memory; they appear constantly in device manuals:

TableSlot sizeAccessTypical use
Discrete Inputs1 bitRead-onlyA switch or status the device senses
Coils1 bitRead/writeAn output you can turn on or off
Input Registers16 bitsRead-onlyA measured value the device reports
Holding Registers16 bitsRead/writeA setting or value you can change

A pattern jumps out. The two input tables are read-only: they reflect what the device measures or senses, so you can't change them. Coils and holding registers are read/write: they hold things you're allowed to set. The names are historical. A "coil" comes from the relay coils early controllers switched on and off, so it's a one-bit output you command. A "discrete input" is a one-bit reading from the world, like whether a limit switch is pressed. An input register is a number the device produces, like a temperature; a holding register is a number you can read and write, like a setpoint.

Bits and registers

Almost every Modbus operation is about one or the other. A bit is the smallest piece of data: 1 or 0, on or off. A relay is closed or open; a pump is running or stopped. Reading a coil returns a single yes-or-no; writing one commands a single yes-or-no.

A register is a sixteen-bit word that holds a whole number from 0 to 65535. A temperature sensor might report 235 to mean 23.5 degrees; a drive might accept 1750 to mean 1750 RPM. Sixteen bits is the native unit of Modbus, a legacy of the sixteen-bit controllers it was born on. When a value needs more (a large counter, or a fractional number) a device uses two registers together, which Chapter 14 covers in detail.

A coil holds one bit that switches between on and off. A register holds sixteen bits, shown as sixteen cells. The register steps through the values 0, 235, 1750, and 65535, with the matching bit patterns lit. Coil 1 bit 1 0 ON OFF Register 16 bits · 0 to 65535 bit 15 bit 0 0 235 → e.g. 23.5 °C 1750 → e.g. 1750 RPM 65535 (all ones, the maximum) 0x0000 0x00EB 0x06D6 0xFFFF
A coil holds one bit, a single on/off state. A register holds sixteen bits, a whole number from 0 to 65535. Every Modbus value is built from one of these two units.

Addresses within a table

Each table is a numbered list, and a slot's position in its table is its address. On the wire, Modbus addresses are zero-based: the first slot is address 0, the next is 1, and so on up to 65535, so a table can hold up to 65,536 slots.

The four tables are addressed independently. Holding register 0, input register 0, and coil 0 are three different slots. There's never confusion about which "address 0" you mean, because every request names an operation, and the operation implies the table. So the on-the-wire model is simple: the function picks the table, a zero-based address picks the slot. If that were the whole story, addressing would trouble nobody. Unfortunately, an older way of writing addresses grew up alongside it.

The addressing trap: reference numbers

Long before the modern specification settled on zero-based addresses, device makers wrote register locations as reference numbers (also called conventional addressing). Each is a five-digit (or six-digit) number: the leading digit names the table, and the rest give the position counting from one.

Leading digitTableReference rangeProtocol address
0Coils00001–099990–9998
1Discrete Inputs10001–199990–9998
3Input Registers30001–399990–9998
4Holding Registers40001–499990–9998

That's why holding registers so often appear in the forty-thousands. When a meter's manual says voltage is at register 40013, the leading 4 means "holding register" and 0013 means "the thirteenth one, counting from one." On the wire, that same slot is address 12.

Converting reference number 40013 to a protocol address in four steps. Step one, the manual says 40013. Step two, strip the leading 4, which means holding registers, leaving 0013. Step three, subtract one: 13 minus 1 equals 12. Step four, send address 12 on the wire as the bytes 00 0C. 1 · MANUAL SAYS 2 · STRIP TABLE DIGIT 3 · SUBTRACT ONE 4 · ON THE WIRE 40013 reference number 4 0013 4 = holding registers 13 − 1 = 12 count from zero 00 0C address 12 (0x000C)
Two ways of naming the same slot. Reference number 40013 and protocol address 12 point at the identical holding register; the leading 4 and the off-by-one are the whole difference.

The conversion has two steps, and forgetting either one is the classic beginner bug:

  1. Strip the leading digit that names the table.
  2. Subtract one to go from counting-from-one to the zero-based protocol address.

So 40001 is holding-register address 0, 40100 is address 99, and 30005 is input-register address 4. Get it wrong and you read a value that is "one off" from where you expected, or land in the wrong table entirely.

To make things worse, manuals aren't consistent. Some modern devices document registers directly as zero-based protocol addresses and never mention reference numbers. Others use the 4xxxx style. A few list "register 40001" but quietly mean address 40001 on the wire. The only safe habit: read each device's documentation carefully and confirm on a known value that you land where you expect. Software tools usually let you choose which convention you're typing, so know which one is selected.

Try it: reference number converter

Type a 5- or 6-digit reference such as 40001, 40100, 30005, 10001, or 400250.

The register map

A device tells you what lives at each address in a document called its register map (or memory map). Each row names an address, says which table it's in, gives the quantity stored there, and notes how to interpret the raw number. The register map is the single most important page of any Modbus device's manual: everything you do with the device starts by finding the right row.

Here's a small but realistic map for an imaginary temperature-and-humidity sensor. (The last column, the protocol address, isn't in the manual; it's the conversion you just learned.)

AddressTableQuantityNotesOn the wire
30001Input RegisterTemperatureValue / 10, in °CIR 0
30002Input RegisterHumidityValue / 10, in % RHIR 1
30003Input RegisterStatus flagsBitfield; bit 0 = faultIR 2
40001Holding RegisterSample periodSeconds, 1–3600HR 0
40002Holding RegisterModbus addressUnit ID, 1–247HR 1

Each row carries everything you need. The temperature is in an input register (read-only, because you can't dictate a measurement), while the sample period is in a holding register (a setting you're allowed to change). The raw value must be divided by ten: the sensor stores 235 to mean 23.5 °C, because registers hold whole numbers and that's how this device packs a fraction into one. That scaling rule is not part of Modbus. It's a convention this device chose and documented, so the same raw number can mean different things on different devices.

What Modbus does not define

It matters just as much what the data model leaves out. Modbus defines bits and sixteen-bit registers, and nothing more. It has no notion of a signed number, a decimal point, a temperature, or a name. It doesn't know that 30001 is a temperature or that it should be divided by ten. All that meaning lives in the register map and in the agreement between the people who built the device and the people reading it. The protocol moves raw bits and raw words faithfully; interpreting them is your job.

This minimalism is deliberate, and freeing. Because Modbus imposes no data types, any device can use plain registers to carry signed values, fractions, text, packed flags, or numbers wider than sixteen bits, each by its own documented convention. The cost is that you must always consult the map; the benefit is that the protocol never gets in the way. Chapter 14 shows how to read signed integers, 32-bit values, and floating-point numbers out of these same registers.

From the physical world to a register and back to meaning. A sensor measures 23.5 degrees Celsius; an analog-to-digital converter turns it into a raw count; the device scales it by ten to 235; the value waits in input register 30001, address 0; a client reads 235 over Modbus and divides by ten, per the register map, to get 23.5 degrees. A marker carries each new reading along the chain as the temperature changes to 24.1 and 22.8. INSIDE THE DEVICE YOUR CODE Sensor ADC Scale ×10 Input register Client physical value raw counts device firmware 30001 = address 0 ÷10 per the map 23.5 °C 24.1 °C 22.8 °C 1576 1591 1559 235 241 228 235 241 228 23.5 °C 24.1 °C 22.8 °C Modbus carries only the raw word
From the physical world to a register. A sensor measures, an analog-to-digital converter turns the measurement into a number, the device scales it, and the result waits in an input register for a client to read. Only the client's register map turns 235 back into 23.5 °C.

Putting the model to work

With the data model in hand, every Modbus operation becomes predictable:

To…you…
Read a measurementread an input register
Check a status bitread a discrete input
Flip an outputwrite a coil
Change a settingwrite a holding register

Each of these maps to a specific function code, the subject of Part II. But the data they move always lives in one of the four tables you now know.

You now know what Modbus data is and where it lives. The remaining question for Part I is how a client actually asks for it: the precise back-and-forth of request and response, including what happens when something goes wrong.

Check your understanding

1. Which two tables are read-only?

The two tables named "input" are read-only: they reflect the physical world. Coils and holding registers are read/write.

2. A meter's manual lists voltage at register 40013. What address goes on the wire?

Strip the leading 4 (holding registers) to get 0013, then subtract one: address 12.

3. Using the sensor's register map, input register 30002 reads 612. What is the humidity?

The map says "Value / 10, in % RH," so 612 / 10 = 61.2 % RH. The scaling comes from the map, not from Modbus.

4. Where does Modbus record that a register holds a temperature in tenths of a degree?

Modbus moves raw bits and sixteen-bit words with no meaning attached. Units, scaling, and data types come from the register map.