Modbus Register Types Explained: Coils, Discrete Inputs, Holding Registers, Input Registers
Every Modbus device exposes its data through four types of data tables. Understanding these register types — what they hold, how they are addressed, and which function codes read or write them — is the foundation of working with any Modbus device. If you get the register type wrong, your poll returns an exception code or garbage data. For broader context on how Modbus works as a protocol, see What Is Modbus? The Protocol That Runs Industrial Automation.
The Four Modbus Data Tables
The Modbus data model is organized into four separate tables, each with a distinct purpose, address range, and access permission:
Two types hold single bits (on/off, true/false). Two types hold 16-bit words (numeric values). Two are read-write. Two are read-only. The naming is consistent: "input" means read-only (data comes from the physical input of the device), and everything else is read-write.
Coils (FC01, FC05, FC15)
Coils represent boolean outputs — relays, solenoid valves, motor starters, LED indicators. A coil is either ON (1) or OFF (0). The name comes from the electromagnetic coil inside a relay.
Function Codes
- FC01 — Read Coils: Read the current state of one or more coils. The master sends the starting address and quantity; the slave responds with bit-packed data.
- FC05 — Write Single Coil: Set a single coil to ON (0xFF00) or OFF (0x0000).
- FC15 — Write Multiple Coils: Set multiple coils in a single request. Useful for toggling several outputs simultaneously.
Addressing
Coil addresses start at 0 in the protocol, but documentation often uses a 1-based convention with a leading 0 prefix: coil address 0 is documented as 00001, coil address 9 is 00010. The protocol frame always uses 0-based addressing.
Practical Example
A PLC with a Modbus interface exposes its digital outputs as coils. Coil 0 controls a pump start relay, coil 1 controls a valve, coil 2 controls a fan. To start the pump, the master writes 0xFF00 (ON) to coil address 0 using FC05.
Discrete Inputs (FC02)
Discrete inputs are read-only boolean values representing the state of physical digital inputs — limit switches, proximity sensors, push buttons, circuit breaker status contacts. The slave device reports their state but cannot be changed via Modbus.
Function Code
- FC02 — Read Discrete Inputs: Read the state of one or more discrete inputs. Same bit-packed format as FC01.
Addressing
Discrete inputs have their own address space, documented with a 1 prefix: address 0 is 10001, address 9 is 10010. Completely independent from coil addresses.
Practical Example
A circuit breaker with a Modbus module exposes its trip status as discrete input 0 (10001). Reading this input tells you if the breaker has tripped (1) or is closed (0). You cannot write to it — the breaker state changes only physically or through its own control circuit.
Holding Registers (FC03, FC06, FC16)
Holding registers are the workhorses of Modbus. Each register holds a 16-bit unsigned integer (0–65535). They store setpoints, configuration parameters, command values, and output values. This is where most of your read-write interaction happens.
Function Codes
- FC03 — Read Holding Registers: Read one or more consecutive holding registers. The most commonly used function code.
- FC06 — Write Single Register: Write a 16-bit value to a single holding register.
- FC16 — Write Multiple Registers: Write values to multiple consecutive holding registers in one request.
Addressing
Documented with a 4 prefix: address 0 is 40001, address 99 is 40100. Again, the protocol uses 0-based addressing.
Data Types Beyond 16-bit
Since a single register is only 16 bits, larger data types span multiple consecutive registers:
- 32-bit integer (INT32, UINT32): Stored in 2 consecutive registers. The byte order (big-endian vs little-endian, word swap) varies by manufacturer. Always check the device documentation.
- 32-bit float (REAL/IEEE 754): Also 2 registers. Common for process values like temperature (72.5°C), pressure (4.2 bar), or flow rate (150.3 m³/h).
- 64-bit float (DOUBLE): 4 consecutive registers. Used for high-precision metering values like totalized energy (kWh) in power meters.
- Strings: Packed as 2 ASCII characters per register across multiple registers.
Input Registers (FC04)
Input registers are the read-only counterpart to holding registers. They represent measured values from physical sensors — voltage, current, temperature, pressure, frequency. The device firmware writes sensor readings into these registers; external Modbus masters can only read them.
Function Code
- FC04 — Read Input Registers: Read one or more consecutive input registers.
Addressing
Documented with a 3 prefix: address 0 is 30001, address 29 is 30030.
Practical Example
A Schneider PM5560 power meter exposes its measurements as input registers: voltage L-N at register 0 (30001), current at register 2 (30003), active power at register 4 (30005). Each is a 32-bit float occupying two registers. You read 6 registers starting at address 0 using FC04 and parse the three float values.
Complete Function Code Reference
Common Pitfalls
- Using the wrong function code for the register type. FC03 only reads holding registers. If you try to read input registers with FC03, you will get an exception. Use FC04 for input registers.
- 1-based vs 0-based addressing. Documentation says register
40100, but the Modbus frame requires address 99. Always subtract 1 from the documented address when building the request. - Register gaps. Not all addresses are valid. A device might expose registers 0-9 and 20-29, with nothing at addresses 10-19. Reading non-existent registers returns exception code 2 (illegal data address).
- Byte order mismatch. When reading 32-bit values across two registers, the byte order must match what the device expects. If your values look wrong (e.g., temperature reads as -6.2×10³⁰), swap the word order.
Frequently Asked Questions
What is the difference between holding registers and input registers?
Holding registers (4x prefix) are read/write 16-bit values accessed with function codes FC03, FC06, and FC16. They store configuration parameters, setpoints, and control commands. Input registers (3x prefix) are read-only 16-bit values accessed with FC04. They represent measured sensor data like voltage, current, and temperature that the device firmware writes but external Modbus masters can only read.
What is the difference between coils and discrete inputs?
Coils (0x prefix) are read/write single-bit values representing binary outputs like relays, valves, and motor starters. You read them with FC01 and write them with FC05 or FC15. Discrete inputs (1x prefix) are read-only single-bit values representing binary inputs like limit switches, proximity sensors, and alarm flags. You can only read them with FC02 — you cannot write to discrete inputs.
Why does Modbus documentation say register 40001 but the protocol uses address 0?
Modbus documentation uses a 1-based convention with a leading prefix that identifies the register type. The "4" in 40001 means "holding register," and 001 means the first register. The actual Modbus protocol frame uses 0-based addressing, so register 40001 is accessed at address 0, register 40100 at address 99, and so on. Always subtract 1 from the documented number when building your request.
How are 32-bit floats stored in Modbus registers?
A 32-bit IEEE 754 float occupies two consecutive 16-bit Modbus registers. The 32-bit value is split into a high word and a low word, but the byte order (endianness) varies between manufacturers. There are four possible byte orderings: Big-Endian (AB CD), Little-Endian (CD AB), Big-Endian Byte-Swap (BA DC), and Little-Endian Byte-Swap (DC BA). Always check your device manual for the correct byte order.
Test It Yourself
MacTools Modbus Poll lets you read and write all four register types with FC01-FC06, FC15, FC16. Built-in device templates for PM5560, SMA inverters, and more auto-populate the correct registers. $9.99 one-time.
Get MacTools Modbus PollRelated: Full SCADA System
Need continuous monitoring with dashboards, alarms, and trending across all your Modbus devices? Voltrus SCADA supports Modbus TCP, Modbus RTU, OPC-UA, Siemens S7, MQTT, and more. Lifetime license from $249.