Modbus Function Code Deep Dive: FC01–FC06, FC15–FC16, FC23

Detailed reference for the most commonly used Modbus function codes — request/response byte structure, parameter requirements, practical examples, and which function codes to use for each data type.

Categories:

Overview

Modbus function codes define the operations a master can perform on a slave device — reading registers, writing values, and diagnostic checks. While the specification defines over 20 function codes, only 9 are commonly used in building automation and industrial integration projects.

This guide provides the byte-level request and response structure for each function code, practical usage notes from Chipkin’s 437+ FSE project history, and guidance on choosing the right function code for each data type.

Function Code Summary

Data Access Function Codes

FCNameData TypeOperationMax Items Per Request
01Read CoilsCoils (bits)Read2,000
02Read Discrete InputsDiscrete Inputs (bits)Read2,000
03Read Holding RegistersHolding Registers (16-bit)Read125
04Read Input RegistersInput Registers (16-bit)Read125
05Write Single CoilCoil (bit)Write1
06Write Single RegisterHolding Register (16-bit)Write1
15Write Multiple CoilsCoils (bits)Write1,968
16Write Multiple RegistersHolding Registers (16-bit)Write123
23Read/Write Multiple RegistersHolding Registers (16-bit)Read + WriteRead: 125 / Write: 121

Choosing the Right Function Code

You Need To…Use FCNotes
Read a binary status (on/off, open/closed)01 or 02FC01 for read/write coils, FC02 for read-only inputs
Read analog values (temperature, pressure)03 or 04FC03 for read/write registers, FC04 for read-only inputs
Write a single setpoint06Simplest write — one register
Write a single command (on/off)05Single coil write
Write multiple values atomically16All registers written in one transaction
Read and write in one request23Reduces round trips — not universally supported

[!TIP] When a device’s documentation only says “registers” without specifying holding vs input, try FC03 first. If that returns exception code 01 or 02, try FC04. Most devices use holding registers (FC03) for both read/write and read-only data.

FC01: Read Coils

Reads the ON/OFF status of 1 to 2,000 coils (single-bit outputs).

Request

FieldSizeDescriptionExample
Slave Address1 byteTarget device0x01
Function Code1 byte0x010x01
Starting Address2 bytesFirst coil address (0-based)0x0000
Quantity2 bytesNumber of coils to read0x000A (10)
CRC/LRC2/1 bytesError check

Response

FieldSizeDescriptionExample
Slave Address1 byteResponding device0x01
Function Code1 byte0x010x01
Byte Count1 byteNumber of data bytes following0x02
Coil StatusN bytesBit-packed coil values (LSB = lowest address)0xCD 0x01
CRC/LRC2/1 bytesError check

Bit packing: Coils are packed into bytes with the lowest numbered coil in the least significant bit. For 10 coils starting at address 0:

  • Byte 1: 0xCD = 11001101 → Coils 7–0 (coil 0 = bit 0 = ON)
  • Byte 2: 0x01 = 00000001 → Coils 9–8 (coil 8 = bit 0 = ON, coil 9 = bit 1 = OFF)

FC02: Read Discrete Inputs

Identical structure to FC01, but reads discrete inputs — read-only bits typically connected to physical switches, sensors, or status contacts.

Difference from FC01Detail
Function code0x02 instead of 0x01
Data typeDiscrete inputs (read-only) instead of coils (read/write)
Address spaceSeparate from coils — address 0 in FC02 is a different point than address 0 in FC01

FC03: Read Holding Registers

The most commonly used function code. Reads 1 to 125 holding registers (16-bit read/write values).

Request

FieldSizeDescriptionExample
Slave Address1 byteTarget device0x01
Function Code1 byte0x030x03
Starting Address2 bytesFirst register address (0-based)0x0000
Quantity2 bytesNumber of registers to read (1–125)0x0002 (2)
CRC/LRC2/1 bytesError check

Response

FieldSizeDescriptionExample
Slave Address1 byteResponding device0x01
Function Code1 byte0x030x03
Byte Count1 byteNumber of data bytes (= quantity × 2)0x04
Register ValuesN × 2 bytesRegister data (high byte first per register)0x00 0x64 0x00 0xC8
CRC/LRC2/1 bytesError check

In this example, register 0 = 0x0064 (100 decimal) and register 1 = 0x00C8 (200 decimal).

[!NOTE] Each register is 16 bits (2 bytes) transmitted high byte first (big-endian) within that register. However, for 32-bit values spanning two registers, the register order varies by manufacturer — see Modbus Data Types & Byte Order Reference.

FC04: Read Input Registers

Identical structure to FC03, but reads input registers — read-only 16-bit values typically representing measured/monitored data (sensor readings, status values).

Difference from FC03Detail
Function code0x04 instead of 0x03
Data typeInput registers (read-only) instead of holding registers (read/write)
Address spaceSeparate from holding registers

[!TIP] Many devices (especially building automation controllers) map all data to holding registers (FC03) and don’t use input registers (FC04) at all. If FC04 returns exception 01, try FC03 for the same address.

FC05: Write Single Coil

Forces a single coil ON or OFF.

Request

FieldSizeDescriptionExample
Slave Address1 byteTarget device0x01
Function Code1 byte0x050x05
Coil Address2 bytesTarget coil (0-based)0x0000
Value2 bytes0xFF00 = ON, 0x0000 = OFF0xFF00
CRC/LRC2/1 bytesError check

Response

The response is an exact echo of the request (same address and value), confirming the write was accepted.

[!CAUTION] The ON value is 0xFF00, NOT 0x0001. Sending 0x0001 is technically an illegal data value (exception 03), though some devices accept it anyway.

FC06: Write Single Register

Writes a single 16-bit value to a holding register.

Request

FieldSizeDescriptionExample
Slave Address1 byteTarget device0x01
Function Code1 byte0x060x06
Register Address2 bytesTarget register (0-based)0x0001
Value2 bytes16-bit value to write0x0064 (100)
CRC/LRC2/1 bytesError check

Response

Exact echo of the request, confirming the write was accepted.

FC06 is the simplest write operation and the most widely supported. Use it for:

  • Setting individual setpoints (temperature, speed, pressure)
  • Writing configuration parameters one at a time
  • Sending single-value commands

FC15: Write Multiple Coils (0x0F)

Writes 1 to 1,968 coils in a single request. Coil values are bit-packed the same way as FC01 responses.

Request

FieldSizeDescriptionExample
Slave Address1 byteTarget device0x01
Function Code1 byte0x0F0x0F
Starting Address2 bytesFirst coil address0x0000
Quantity2 bytesNumber of coils to write0x000A (10)
Byte Count1 byteNumber of data bytes0x02
Coil ValuesN bytesBit-packed values (LSB first)0xCD 0x01
CRC/LRC2/1 bytesError check

Response

FieldSizeDescription
Slave Address1 byteResponding device
Function Code1 byte0x0F
Starting Address2 bytesEchoed from request
Quantity2 bytesEchoed from request
CRC/LRC2/1 bytesError check

FC16: Write Multiple Registers (0x10)

Writes 1 to 123 holding registers in a single request. This is the standard function code for writing 32-bit values (which span 2 registers) and for atomic multi-register writes.

Request

FieldSizeDescriptionExample
Slave Address1 byteTarget device0x01
Function Code1 byte0x100x10
Starting Address2 bytesFirst register address0x0000
Quantity2 bytesNumber of registers to write (1–123)0x0002
Byte Count1 byteNumber of data bytes (= quantity × 2)0x04
Register ValuesN × 2 bytesValues to write (high byte first per register)0x00 0x64 0x00 0xC8
CRC/LRC2/1 bytesError check

Response

FieldSizeDescription
Slave Address1 byteResponding device
Function Code1 byte0x10
Starting Address2 bytesEchoed from request
Quantity2 bytesEchoed from request
CRC/LRC2/1 bytesError check

[!TIP] When writing a 32-bit floating-point value, use FC16 to write both registers atomically. Using two separate FC06 writes risks the device reading the value between writes — getting half of the old value and half of the new value.

FC23: Read/Write Multiple Registers (0x17)

Reads and writes holding registers in a single transaction. The write operation is performed before the read operation.

Request

FieldSizeDescription
Slave Address1 byteTarget device
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 byteNumber of write data bytes
Write Register ValuesN × 2 bytesValues to write
CRC/LRC2/1 bytesError check

Response

Same format as an FC03 response — just the read data.

[!WARNING] FC23 is not widely supported by field devices. Many controllers, meters, and sensors return exception code 01 (Illegal Function) for this function code. Always verify support before relying on FC23 in a gateway configuration. If unsupported, use separate FC03 + FC16 requests instead.

Function Code vs Data Type Matrix

Data TypeRead FCWrite Single FCWrite Multiple FC
Coils (0xxxx)FC01FC05FC15
Discrete Inputs (1xxxx)FC02— (read-only)— (read-only)
Input Registers (3xxxx)FC04— (read-only)— (read-only)
Holding Registers (4xxxx)FC03FC06FC16

[!NOTE] The Modicon address prefixes (0xxxx, 1xxxx, 3xxxx, 4xxxx) are documentation conventions — they don’t appear on the wire. The function code determines which data type is accessed. See Modbus Register Addressing: Modicon, PDU, and Page-Based Conventions for details.

Diagnostic Function Codes (Less Common)

FCNamePurpose
07Read Exception StatusReads 8 predefined status coils — device-specific
08DiagnosticsLoopback test, clear counters, restart — various sub-function codes
11Get Comm Event CounterReturns event count and busy status
17Report Server IDReturns device identification string
43Read Device IdentificationReturns vendor name, product code, revision — structured ID data

These function codes are optional and rarely supported in building automation devices. They’re useful for advanced diagnostics but should not be relied upon for normal operation.

Chipkin Tools

Need more help?

If this page does not resolve the issue, contact Chipkin support with the product model, protocol details, and any diagnostics you have already captured.

Open Chipkin Support