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. For how documented addresses like 40001 map to wire addresses, see Modbus addressing explained.
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 flow meter might publish its measured flow rate as a 32-bit float in input registers 0 and 1 (documented as 30001). You read 2 registers starting at address 0 with FC04 and decode them as one float. Not every device follows the textbook split: the Schneider PM5560, for example, exposes its measurements as holding registers read with FC03. See the PM5560 register map guide.
Complete Function Code Reference
Common Pitfalls
- Using the wrong function code for the register type. FC03 reads holding registers and FC04 reads input registers. Some devices answer FC03 and FC04 from the same table, but a strict device returns an exception or no useful data if you use the wrong one. Check the device manual for which function code each value needs.
- 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. See Modbus floating-point byte order for the four orderings.
Test It Yourself
MacTools Modbus Poll reads all four register types (FC01 to FC04) and writes coils and holding registers (FC05, FC06, FC15, FC16). Discrete inputs and input registers are read-only in the protocol. Built-in device templates for PM5560, SMA inverters, and more auto-populate the correct registers. $19.99 one-time on Mac; there is also a Windows build, free with limits.
Get MacTools Modbus PollRelated: Full SCADA System
Need continuous monitoring with dashboards, alarms, and trending across your Modbus TCP devices? Voltrus SCADA supports Modbus TCP, OPC-UA, Siemens S7, EtherNet/IP, DNP3, BACnet and MQTT. The core is free and open source (AGPL-3.0).
Further Reading
- Modbus RTU vs TCP: Which Protocol Should You Use?
- DEIF AGC 150 register map: coils, discrete inputs, input registers and holding registers in one device
- Rosemount 8732EM register map, with its coil commands
- PM5560 Modbus Register Map: How to Read Power Meter Data
- Best Modbus Simulator for macOS (2026)