Modbus Function Codes Explained with Real Examples

By | April 5, 2026

Every Modbus message contains a function code. It is a single byte that tells the slave device what operation to perform — read coils, write registers, or diagnose communication.

The Modbus specification defines multiple function codes, but in practice you will use about six of them for 95% of your tasks. The rest are either rarely implemented, vendor-specific, or reserved for legacy use.

This guide explains each commonly used function code with real hex frame examples. For every function code, you will see the request, the response, and what each byte means — so you can read raw Modbus frames in Wireshark, a serial analyzer, or any debugging tool.

1. How Function Codes Work

Every Modbus RTU transaction follows the same frame structure:

  1. The master sends a request: [Slave ID] [Function Code] [Data] [CRC-16]
  2. The slave processes the request.
  3. The slave sends a response: [Slave ID] [Function Code] [Data] [CRC-16]

If the slave cannot process the request, it sends an exception response with the function code + 0x80 and an exception code explaining the error.

The Slave ID (1 byte) identifies which device on the bus should respond. The function code (1 byte) tells the slave what to do. The CRC-16 (2 bytes) provides error checking. All examples in this guide show the complete Modbus RTU frame including Slave ID and CRC.

2. Modbus Register Types and Matching Function Codes

Each function code operates on a specific register type. Using the wrong function code for a register type is one of the most common Modbus errors.

Register TypeLegacy Address RangeAccessRead FCWrite FC
Coils (digital outputs)0xxxxRead/WriteFC 01FC 05 (single) / FC 15 (multiple)
Discrete Inputs (digital inputs)1xxxxRead-OnlyFC 02
Input Registers (analog inputs)3xxxxRead-OnlyFC 04
Holding Registers (analog outputs/config)4xxxxRead/WriteFC 03FC 06 (single) / FC 16 (multiple)

💡 Key rule: You cannot write to Discrete Inputs (1xxxx) or Input Registers (3xxxx). They are read-only. Attempting to write will return exception code 01 (Illegal Function).

3. FC 01 — Read Coils (0x01)

Purpose: Read the ON/OFF status of 1 to 2,000 coils (digital outputs).

Use case: Read the state of relay outputs, motor contactors, or valve solenoids.

Request Frame (Modbus RTU)

Read 19 coils starting at coil 20, from slave device 1:

FieldSizeExampleMeaning
Slave ID1 byte01Target slave address 1
Function Code1 byte01Read Coils
Starting Address2 bytes00 13Start at coil 20 (address 19 = 0x13)
Quantity2 bytes00 13Read 19 coils (20 through 38)
CRC2 bytes8C 02CRC-16 error check

Raw frame: 01 01 00 13 00 13 8C 02

Response Frame (Modbus RTU)

FieldSizeExampleMeaning
Slave ID1 byte01Response from slave 1
Function Code1 byte01Read Coils
Byte Count1 byte033 bytes of coil data follow
Coil Status3 bytesCD 6B 05Bit-packed status of coils 20–38
CRC2 bytes42 82CRC-16 error check

Raw frame: 01 01 03 CD 6B 05 42 82

Reading the Response

The coil status bytes are bit-packed, LSB first:

  • 0xCD = 1100 1101 → coils 27–20: ON ON OFF OFF ON ON OFF ON
  • 0x6B = 0110 1011 → coils 35–28: OFF ON ON OFF ON OFF ON ON
  • 0x05 = 0000 0101 → coils 38–36: OFF OFF OFF OFF OFF ON OFF ON (upper 5 bits are padding)

4. FC 02 — Read Discrete Inputs (0x02)

Purpose: Read the ON/OFF status of 1 to 2,000 discrete inputs (digital inputs).

Use case: Read limit switches, door contacts, level sensors, or alarm inputs.

Works exactly like FC 01, but reads from the discrete input table (1xxxx) instead of coils (0xxxx).

Example

Read 22 discrete inputs starting at input 197, from slave device 3:

Request: 03 02 00 C4 00 16 B9 DB

FieldExampleMeaning
Slave ID03Slave address 3
FC02Read Discrete Inputs
Start Address00 C4Input 197 (address 196 = 0xC4)
Quantity00 16Read 22 inputs

Response: 03 02 03 AC DB 35 23 6A

FieldExampleMeaning
Slave ID03From slave 3
FC02Read Discrete Inputs
Byte Count033 bytes follow
Input StatusAC DB 35Bit-packed status of inputs 197–218

5. FC 03 — Read Holding Registers (0x03)

Purpose: Read 1 to 125 contiguous holding registers (16-bit words).

Use case: Read setpoints, configuration parameters, energy values, PID outputs — this is the most frequently used function code in Modbus.

Request Frame (Modbus RTU)

Read 3 holding registers starting at register 108, from slave device 6:

FieldSizeExampleMeaning
Slave ID1 byte06Target slave address 6
Function Code1 byte03Read Holding Registers
Starting Address2 bytes00 6BRegister 108 (address 107 = 0x6B)
Quantity2 bytes00 03Read 3 registers (108, 109, 110)
CRC2 bytes75 A0CRC-16 error check

Raw frame: 06 03 00 6B 00 03 75 A0

Response Frame (Modbus RTU)

FieldSizeExampleMeaning
Slave ID1 byte06Response from slave 6
Function Code1 byte03Read Holding Registers
Byte Count1 byte066 bytes follow (3 registers × 2 bytes)
Register 1082 bytes02 2BValue = 555 decimal
Register 1092 bytes00 00Value = 0
Register 1102 bytes00 64Value = 100 decimal
CRC2 bytes23 4ACRC-16 error check

Raw frame: 06 03 06 02 2B 00 00 00 64 23 4A

Practical Notes

  • Maximum 125 registers per request (250 bytes of data).
  • Data is big-endian — high byte first, then low byte.
  • For 32-bit values (floats, long integers), two consecutive registers are used. Check the device manual for byte order — some devices use AB CD (big-endian), others use CD AB (word-swapped).

6. FC 04 — Read Input Registers (0x04)

Purpose: Read 1 to 125 contiguous input registers (16-bit words, read-only).

Use case: Read live measurements — voltage, current, temperature, pressure, flow rate.

Works identically to FC 03 in frame structure. The only difference is the register table it reads from (3xxxx instead of 4xxxx).

Example

Read 1 input register (register 9) from slave device 2:

Request: 02 04 00 08 00 01 B0 3B

FieldExampleMeaning
Slave ID02Slave address 2
FC04Read Input Registers
Start Address00 08Register 9 (address 8 = 0x08)
Quantity00 01Read 1 register

Response: 02 04 02 00 0A 7D 37

FieldExampleMeaning
Slave ID02From slave 2
FC04Read Input Registers
Byte Count022 bytes follow
Register 900 0AValue = 10 decimal

⚠️ Common mistake: Using FC 03 to read input registers or FC 04 to read holding registers. Some devices map everything to holding registers and respond to both. Others are strict and will return exception code 02 (Illegal Data Address). Always check the device documentation.

7. FC 05 — Write Single Coil (0x05)

Purpose: Turn a single coil ON or OFF.

Use case: Control a relay, start/stop a motor, open/close a valve.

Important

The value to write is not 0 or 1. It is:

  • 0xFF00 = ON
  • 0x0000 = OFF
  • All other values are illegal and will be rejected.

Request Frame (Modbus RTU)

Turn ON coil 173 on slave device 5:

FieldSizeExampleMeaning
Slave ID1 byte05Target slave address 5
Function Code1 byte05Write Single Coil
Coil Address2 bytes00 ACCoil 173 (address 172 = 0xAC)
Value2 bytesFF 00Turn ON
CRC2 bytes4D 9FCRC-16 error check

Raw frame: 05 05 00 AC FF 00 4D 9F

Response Frame (Modbus RTU)

The response is an exact echo of the request — confirming the write was successful.

Raw frame: 05 05 00 AC FF 00 4D 9F

8. FC 06 — Write Single Register (0x06)

Purpose: Write a single 16-bit value to one holding register.

Use case: Change a setpoint, write a configuration parameter, set an analog output value.

Request Frame (Modbus RTU)

Write value 3 to holding register 2 on slave device 1:

FieldSizeExampleMeaning
Slave ID1 byte01Target slave address 1
Function Code1 byte06Write Single Register
Register Address2 bytes00 01Register 2 (address 1 = 0x01)
Value2 bytes00 03Write value 3
CRC2 bytes98 0BCRC-16 error check

Raw frame: 01 06 00 01 00 03 98 0B

Response Frame (Modbus RTU)

The response is an exact echo of the request.

Raw frame: 01 06 00 01 00 03 98 0B

9. FC 15 — Write Multiple Coils (0x0F)

Purpose: Write the state of multiple consecutive coils in a single message.

Use case: Set a group of relay outputs at once, configure a bank of digital outputs.

Request Frame (Modbus RTU)

Write 10 coils starting at coil 20 on slave device 1:

FieldSizeExampleMeaning
Slave ID1 byte01Target slave address 1
Function Code1 byte0FWrite Multiple Coils
Starting Address2 bytes00 13Start at coil 20
Quantity2 bytes00 0AWrite 10 coils
Byte Count1 byte022 bytes of coil data follow
Coil Values2 bytesCD 01Bit-packed ON/OFF values
CRC2 bytes72 CBCRC-16 error check

Raw frame: 01 0F 00 13 00 0A 02 CD 01 72 CB

Response Frame (Modbus RTU)

FieldExampleMeaning
Slave ID01From slave 1
FC0FWrite Multiple Coils
Start Address00 13Starting at coil 20
Quantity00 0A10 coils written

Raw frame: 01 0F 00 13 00 0A 24 09

Note: Some devices only support FC 15 and do not support FC 05. In that case, configure your master to use FC 15 even for single coil writes.

10. FC 16 — Write Multiple Registers (0x10)

Purpose: Write values to multiple consecutive holding registers in a single message.

Use case: Write a batch of setpoints, download configuration, write 32-bit values that span two registers.

Request Frame (Modbus RTU)

Write 2 holding registers starting at register 2 on slave device 1:

FieldSizeExampleMeaning
Slave ID1 byte01Target slave address 1
Function Code1 byte10Write Multiple Registers
Starting Address2 bytes00 01Start at register 2
Quantity2 bytes00 02Write 2 registers
Byte Count1 byte044 bytes of data follow
Register 22 bytes00 0AValue = 10
Register 32 bytes01 02Value = 258
CRC2 bytes92 30CRC-16 error check

Raw frame: 01 10 00 01 00 02 04 00 0A 01 02 92 30

Response Frame (Modbus RTU)

FieldExampleMeaning
Slave ID01From slave 1
FC10Write Multiple Registers
Start Address00 01Starting at register 2
Quantity00 022 registers written

Raw frame: 01 10 00 01 00 02 10 08

Maximum: 123 registers per request (246 bytes of data).

11. FC 23 — Read/Write Multiple Registers (0x17)

Purpose: Perform a read and a write in a single transaction. The write is executed before the read.

Use case: Atomic read-modify-write operations. Less common but useful when you need to guarantee that a read and write happen together without another master interfering.

Request Frame

FieldSizeMeaning
Function Code1 byte0x17
Read Starting Address2 bytesFirst register to read
Read Quantity2 bytesNumber of registers to read (1–125)
Write Starting Address2 bytesFirst register to write
Write Quantity2 bytesNumber of registers to write (1–121)
Write Byte Count1 byte2 × Write Quantity
Write DataN bytesValues to write

Response Frame

The response contains only the read data — the write is confirmed by the absence of an exception.

12. FC 43/14 — Read Device Identification (0x2B/0x0E)

Purpose: Read vendor name, product code, firmware version, and other identification data from a device.

Use case: Device discovery, inventory management, verifying firmware versions during commissioning.

How It Works

This function code uses an MEI (Modbus Encapsulated Interface) with sub-function code 14 (0x0E). The request specifies which identification objects to read:

Object IDDescription
0x00Vendor Name
0x01Product Code
0x02Major/Minor Revision
0x03Vendor URL (optional)
0x04Product Name (optional)
0x05Model Name (optional)
0x06User Application Name (optional)

Not all devices support this function code. Many legacy devices only support FC 01–06 and FC 15–16.

13. Exception Responses — When Things Go Wrong

When a slave cannot process a request, it returns an exception response. The function code in the response is the original function code + 0x80.

For example, if FC 03 (0x03) fails, the response contains FC 0x83.

Exception Codes

CodeNameMeaningCommon Cause
01Illegal FunctionThe slave does not support this function codeUsing FC 04 on a device that only supports FC 03
02Illegal Data AddressThe requested register address does not existWrong address, wrong offset, or register not mapped
03Illegal Data ValueThe value in the request is out of rangeWriting 0x0001 to a coil (must be 0xFF00 or 0x0000)
04Slave Device FailureInternal error in the slave deviceHardware fault, memory error, or processing failure
05AcknowledgeThe slave has accepted the request but needs time to processLong operations like firmware updates
06Slave Device BusyThe slave is processing another requestTry again later

Example

Master requests register at address 0x0500 from slave 1 (which does not exist on this device):

Request: 01 03 05 00 00 01 84 C6

FieldValueMeaning
Slave ID01Slave address 1
FC03Read Holding Registers
Address05 00Register address 1281
Quantity00 01Read 1 register

Exception Response: 01 83 02 C0 F1

FieldValueMeaning
Slave ID01From slave 1
FC83FC 03 + 0x80 = exception
Exception Code02Illegal Data Address — register does not exist

14. Function Code Quick Reference Table

FCHexNameRegistersDirectionMax Per Request
010x01Read Coils0xxxxRead2,000 coils
020x02Read Discrete Inputs1xxxxRead2,000 inputs
030x03Read Holding Registers4xxxxRead125 registers
040x04Read Input Registers3xxxxRead125 registers
050x05Write Single Coil0xxxxWrite1 coil
060x06Write Single Register4xxxxWrite1 register
150x0FWrite Multiple Coils0xxxxWrite1,968 coils
160x10Write Multiple Registers4xxxxWrite123 registers
230x17Read/Write Multiple Registers4xxxxRead + WriteRead 125 / Write 121
430x2BRead Device IdentificationRead

15. Common Mistakes with Function Codes

MistakeWhat HappensFix
Using FC 03 to read input registers (3xxxx)Some devices respond, others return exception 02Use FC 04 for input registers, FC 03 for holding registers
Writing 0x0001 to a coil instead of 0xFF00Exception 03 (Illegal Data Value)Use 0xFF00 for ON, 0x0000 for OFF
Requesting more than 125 registers in FC 03Exception 03 or no responseSplit into multiple requests, max 125 registers each
Forgetting the zero-based offsetReading the wrong register (off by one)Register 40001 = address 0x0000 in the PDU
Assuming all devices support FC 05Some devices only support FC 15 for coil writesCheck device documentation. Use FC 15 as fallback.
Not checking exception responsesMaster retries endlessly on an invalid requestParse the response. If FC ≥ 0x80, it is an exception — read the exception code.
Wrong byte order for 32-bit valuesFloat values read as garbageCheck device manual: big-endian (AB CD) vs word-swapped (CD AB) vs little-endian (DC BA)

Summary

Modbus function codes are simple by design. A one-byte code tells the slave exactly what to do. The six most important codes for daily work are:

  • FC 03 — Read Holding Registers (your most-used code)
  • FC 04 — Read Input Registers (live measurements)
  • FC 06 — Write Single Register (change a setpoint)
  • FC 16 — Write Multiple Registers (batch writes, 32-bit values)
  • FC 01 — Read Coils (digital output status)
  • FC 05 — Write Single Coil (control a relay)

Learn these six, understand the zero-based addressing offset, and know how to read exception responses — and you can debug any Modbus system.

Decode Any Modbus Frame Instantly

Want to verify your Modbus frames or decode raw bytes from Wireshark? Use our free Online Modbus Frame Decoder & Encoder Tool — paste any Modbus RTU or TCP frame and get a full byte-by-byte breakdown with CRC validation, register values, and function code explanation.

Author: Zakaria El Intissar

I'm an automation and industrial computing engineer with 12 years of experience in power system automation, SCADA communication protocols, and electrical protection. I build tools and write guides for Modbus, DNP3, IEC 101/103/104, and IEC 61850 on ScadaProtocols.com to help engineers decode, analyze, and troubleshoot real industrial communication systems.

Leave a Reply

Your email address will not be published. Required fields are marked *