In industrial automation systems, monitoring binary digital inputs—such as emergency stop buttons, inductive proximity sensors, motor overload contacts, and liquid level float switches—relies directly on Modbus Function Code 02 (Read Discrete Inputs / 0x02). Defined under the official Modbus Application Protocol Specification V1.1b3, Function Code 02 enables a client/master to poll between 1 and 2,000 contiguous 1-bit read-only inputs from a remote server/slave in a single request frame.

Whether you are commissioning a new SCADA polling driver, programming a PLC gateway, or debugging communication timeouts over RS-485 serial buses, understanding the exact bit-packing logic, zero-based wire addressing, and protocol exception handling of Function Code 02 is essential. This engineering guide breaks down the protocol specification, analyzes raw hexadecimal packet traces for Modbus RTU and Modbus TCP, provides working Python code, and demonstrates how to simulate discrete inputs in ModbusSimulator.

1. The Modbus Memory Model: Coils vs Discrete Inputs

The Modbus protocol defines four distinct register tables. Discrete Inputs occupy a specialized role as read-only physical status points:

Data Table Object Type Read/Write Access Modicon 1-Based Address Wire Address Offset Standard Function Codes
Discrete Inputs 1-bit binary flag Read-Only 10001 – 19999 (or 165536) 0x0000 – 0xFFFF FC02 (0x02)
Coils (Outputs) 1-bit binary flag Read / Write 00001 – 09999 (or 065536) 0x0000 – 0xFFFF FC01 (Read), FC05 (Write 1), FC15 (Write N)
Input Registers 16-bit word Read-Only 30001 – 39999 (or 365536) 0x0000 – 0xFFFF FC04 (0x04)
Holding Registers 16-bit word Read / Write 40001 – 49999 (or 465536) 0x0000 – 0xFFFF FC03 (Read), FC06 (Write 1), FC16 (Write N)

Key Architectural Distinction: While both Coils (FC01) and Discrete Inputs (FC02) return binary 1 or 0 values, Discrete Inputs are strictly read-only from the network. They directly mirror the state of physical opto-isolated digital inputs on PLC terminal strips or RTU expansion racks. If a master attempts to issue a write command to an address mapped in the discrete input table, an industrial slave must respond with an error.

2. Protocol Data Unit (PDU) Specification

Under the Modbus standard, the Protocol Data Unit (PDU) is independent of the underlying physical transmission layer (whether RS-485 serial, RS-232, or Ethernet TCP/IP).

Request PDU Format (Client → Server)

The request PDU consists of exactly 5 bytes:

Field Name Length Hex Value Range Description
Function Code 1 Byte 0x02 Command identifier for Read Discrete Inputs
Starting Address 2 Bytes (Big-Endian) 0x0000 – 0xFFFF 0-based offset of the first discrete input requested
Quantity of Inputs 2 Bytes (Big-Endian) 0x0001 – 0x07D0 Number of contiguous inputs to read (1 to 2,000)

Response PDU Format (Server → Client)

The normal response PDU contains a byte count followed by the packed input data bytes:

Field Name Length Hex Value Range Description
Function Code 1 Byte 0x02 Echoes the requested function code
Byte Count (N) 1 Byte 0x01 – 0xFA Number of data bytes following (computed as ceil(Quantity / 8))
Input Status N Bytes N Bytes Packed binary values, 8 inputs per byte (LSB-first)

3. Bit-Packing Algorithm & Hex Frame Analysis

Because discrete inputs are 1-bit values, Modbus packs up to 8 inputs into each payload byte to optimize industrial transmission bandwidth. The lowest-addressed input is placed into the Least Significant Bit (Bit 0) of the first data byte. If the requested quantity is not an exact multiple of 8, the unused high-order bits in the final byte are padded with zeros.

Worked Example: Reading 12 Discrete Inputs in Modbus RTU

Suppose an automation client wants to read 12 discrete inputs starting at PLC address 10197 from Slave ID 1.

Request Frame (Modbus RTU Hex):

01 02 00 C4 00 0C B9 D6
Byte Hex Protocol Field Description
101Slave AddressTarget Slave Device ID 1
202Function CodeFC02 Read Discrete Inputs
3-400 C4Starting AddressOffset 196 (Address 10197)
5-600 0CQuantity of Inputs12 inputs requested
7-8B9 D6CRC-16Cyclic Redundancy Check (Low byte first)

Simulated Input States:

Assume the 12 inputs on the server have the following states:

Response Frame (Modbus RTU Hex):

01 02 02 AD 05 78 8B
Byte Hex Protocol Field Description
101Slave AddressEchoes Slave ID 1
202Function CodeEchoes Function Code 02
302Byte Count2 data bytes follow (ceil(12/8) = 2)
4ADInput Status (Byte 1)Binary 10101101 (Inputs 10197 to 10204)
505Input Status (Byte 2)Binary 00000101 (Inputs 10205 to 10208 + padding)
6-778 8BCRC-16Calculated frame checksum

4. Modbus TCP ADU Format (MBAP Header)

When transmitted over Ethernet networks using Modbus TCP (Port 502), the 2-byte CRC checksum is discarded. Instead, a 7-byte Modbus Application Protocol (MBAP) Header precedes the PDU:

[Transaction ID: 2B] [Protocol ID: 2B (0x0000)] [Length: 2B] [Unit ID: 1B] [PDU: 5B]

For the identical 12-input request over TCP with Transaction ID 0x0001:

00 01 00 00 00 06 01 02 00 C4 00 0C

5. Error Handling & Exception Codes

When a slave device cannot successfully process a Function Code 02 request, it responds with an Exception Response. The function code in the response has its most significant bit set (0x02 + 0x80 = 0x82), followed by a 1-byte Exception Code:

Exception Code Name Typical Cause with FC02 Troubleshooting & Fix
0x01 Illegal Function The target device does not support FC02 or has discrete inputs disabled in its firmware. Verify device documentation; poll as Holding Registers (FC03) or Coils (FC01) if inputs are mapped as words.
0x02 Illegal Data Address Starting address offset is out of range, or (Starting Address + Quantity) exceeds the device table limit. Check zero-based vs one-based offset (e.g. 10001 vs 0x0000). Ensure the highest address exists in the PLC memory map.
0x03 Illegal Data Value Quantity is 0 or exceeds 2,000 (0x07D0). Ensure 1 <= Quantity <= 2000 in your client polling configuration.
0x04 Slave Device Failure An unrecoverable error occurred in the slave controller while reading physical I/O expansion racks. Inspect physical PLC I/O rack communication, power supplies, and optocoupler module status lights.

6. Python Pymodbus Implementation Example

The following script demonstrates how to poll discrete inputs using the popular pymodbus library over Modbus TCP or RTU:

from pymodbus.client import ModbusTcpClient
import time

def read_discrete_sensors(host='127.0.0.1', port=502, slave_id=1):
    client = ModbusTcpClient(host=host, port=port)
    if not client.connect():
        print(f"[-] Connection failed to {host}:{port}")
        return

    try:
        # Read 16 discrete inputs starting at wire address 0 (PLC address 10001)
        response = client.read_discrete_inputs(address=0, count=16, slave=slave_id)

        if response.isError():
            print(f"[-] Modbus Error: {response}")
            return

        # response.bits is a list of booleans [True, False, True, ...]
        bits = response.bits[:16]
        print(f"[+] Successfully polled {len(bits)} Discrete Inputs from Slave {slave_id}:")
        for idx, state in enumerate(bits):
            wire_addr = idx
            plc_addr = 10001 + idx
            status_text = "ACTIVE (1)" if state else "INACTIVE (0)"
            print(f"    Input {plc_addr} [Wire 0x{wire_addr:04X}]: {status_text}")

    finally:
        client.close()

if __name__ == '__main__':
    read_discrete_sensors()

7. Simulating Discrete Inputs with ModbusSimulator

Testing SCADA dashboards and PLC communication routines before physical hardware is delivered is best accomplished using ModbusSimulator. You can configure multi-device virtual slaves with full discrete input table support:

Test Your Modbus Systems Today

Download ModbusSimulator to simulate virtual Modbus RTU and TCP slaves, script register values, and debug PLC networks without hardware.

Download ModbusSimulator Free →

Frequently Asked Questions (FAQs)

What is Modbus Function Code 02?

Modbus Function Code 02 (0x02) is the standard command used by a master/client to read the binary ON/OFF status of contiguous discrete inputs (1 to 2,000) from a remote slave/server.

What is the difference between Discrete Inputs (FC02) and Coils (FC01)?

Discrete Inputs (1xxxx) are read-only physical digital inputs (switches, sensors). Coils (0xxxx) are read/write entities representing physical output relays or internal control flags.

How are discrete inputs packed into bytes in the response?

Inputs are packed 8 per byte, starting with the least significant bit (LSB) representing the lowest address requested. Any remaining bits in the final byte are padded with zeros.

What is the difference between address 10001 and wire address 0x0000?

10001 is the 1-based documentation notation. On the communication wire, addresses are transmitted as zero-based 16-bit values, meaning 10001 is transmitted as 0x0000.

What causes Modbus Exception 02 with Function Code 02?

Exception 02 (Illegal Data Address) indicates the starting address does not exist on the slave, or the range requested exceeds the configured discrete input address space.

What causes Modbus Exception 03 with Function Code 02?

Exception 03 (Illegal Data Value) occurs when the requested quantity is 0 or greater than 2,000, violating the protocol limits.

Can a Modbus master write to Discrete Inputs?

No. Discrete Inputs are strictly read-only by specification. For read/write binary flags, use Coils with Function Codes 01, 05, and 15.