Modbus Function Codes Explained: FC01–FC06, FC15, FC16
Modbus is a request/response protocol. The master sends a request that starts with a one-byte function code, and the slave answers with either the requested data or an exception. That single byte decides what the rest of the frame means, which data table to touch, whether it is a read or a write, and how many bytes of payload follow.
This is the reference most engineers keep open while commissioning. It covers the eight function codes you will see in 99% of real deployments, the exact request/response byte layout for each, and the gotchas that bite on the first project. For the broader protocol background, start with What Is Modbus? and the register types guide.
The Four Data Tables
Before the function codes, you need the four data tables they operate on. Every Modbus slave is modelled as four tables, each with a different data width and access level:
- Coils, 1-bit, read/write. Discrete outputs: relay states, lamp on/off. Addressed from
00001. - Discrete Inputs, 1-bit, read-only. Digital inputs: limit switches, push buttons. Addressed from
10001. - Input Registers, 16-bit, read-only. Measured values: live voltage, current, temperature. Addressed from
30001. - Holding Registers, 16-bit, read/write. Configuration and status: setpoints, energy totals, mode flags. Addressed from
40001.
The function code picks the table and the operation. That is all it does.
The Eight Function Codes You Will Actually Use
Codes 1–4 are reads. Codes 5 and 6 write a single value. Codes 15 and 16 write many values in one atomic frame. That is the entire working set for monitoring and basic control.
FC03: Read Holding Registers (the one you will use most)
FC03 is the workhorse of industrial monitoring. You send a start address and a quantity, the slave returns that many 16-bit registers. Reading three holding registers from address 40321 (protocol address 320):
unit fc start-hi start-lo qty-hi qty-lo
Response: 01 03 06 00 C8 01 2C 01 90 CRC
unit fc bytecount=6 reg1 reg2 reg3
The response carries a byte-count field (here 06 = six data bytes = three registers), then the register values high-byte first. The master already knows how many to expect because it asked for them.
FC04 vs FC03
The wire format of FC04 is byte-for-byte identical to FC03. The only difference is which table the slave reads from. FC04 reads input registers (read-only measured values); FC03 reads holding registers (read/write configuration). A Schneider PM5560 power meter exposes live phase voltage as input registers (FC04) and the demand-interval setpoint as a holding register (FC03). Try FC03 on an input register and you get an exception, see the exception codes guide.
FC01 and FC02: Reading Bits
FC01 reads coils (read/write bits) and FC02 reads discrete inputs (read-only bits). The response packs the bits eight to a byte, least-significant bit first. If you read 10 coils you get two bytes; the six unused bits in the second byte are zero-padded and must be ignored.
read 10 coils starting at coil 0020
Response: 01 01 02 03 01 CRC
bytecount=2 0x03=00000011 0x01=00000001
FC06: Write Single Register
FC06 writes one 16-bit holding register. It is the simplest write: address plus value. The response is an exact echo of the request, which the master uses as confirmation.
write 100 (0x0064) to register 40321
Response: 01 06 01 40 00 64 CRC (echo)
FC05: Write Single Coil
FC05 turns one coil on or off. The value is fixed: 0xFF00 means ON, 0x0000 means OFF. Any other value is illegal. Like FC06, the response echoes the request.
OFF: 01 05 00 13 00 00 CRC
FC16: Write Multiple Registers
When you need to set several registers, FC16 beats issuing many FC06 calls. It is also atomic on most devices, the slave applies all values in one transaction, so a control block is never left half-written. The request carries a byte-count, then the data.
write 10 and 20 to registers 40321–40322
Response: 01 10 01 40 00 02 CRC (addr + qty ack)
The response does not echo the data, only the start address and quantity. If those match the request, the write succeeded.
The Lesser Function Codes
You will occasionally meet the rest. You rarely need to issue them by hand:
- FC07 Read Exception Status, a legacy one-byte status read.
- FC08 Diagnostics, loopback, bus health, counters. Useful for commissioning a serial link.
- FC11 Get Comm Event Counter / FC12 Get Comm Event Log.
- FC17 Report Slave ID, returns vendor, model, and firmware. Handy to identify a mystery device.
- FC20/21 Read/Write File Records, block transfers to memory files.
- FC22 Mask Write Register, set/clear individual bits without a read-modify-write round trip.
- FC23 Read/Write Multiple Registers, atomic read-then-write in one frame. Rarely supported.
- FC43 Encapsulated Interface Transport, vendor extensions (e.g. Schneider's ION objects).
Reading 32-bit Values: It Is Still Two FC03 Registers
Modbus has no 32-bit or floating-point type. A 32-bit value is just two adjacent 16-bit registers read with a normal FC03. The catch: every vendor orders the two words, and the four bytes, differently. The four conventions are called ABCD, DCBA, BADC, and CDAB.
1.4e-39. The bytes are correct, your decoder is using the wrong swap. Cycle the four byte orders until it reads sane. See Modbus float byte order explained for the full walkthrough.
Choosing the Right Code
To read data:
- 16-bit measured value (voltage, current, temperature) → FC04 Input Register
- 16-bit configuration or status (setpoint, energy total) → FC03 Holding Register
- On/off state, read/write (relay output) → FC01 Coil
- On/off state, read-only (digital input) → FC02 Discrete Input
To write data:
- One register → FC06
- Two or more registers (or any atomic block) → FC16
- One coil → FC05
- Two or more coils → FC15
When in doubt, prefer FC16 over repeated FC06. The atomic multi-write is safer for anything a partial write could leave in a bad state, setpoint tables, scheduling blocks, calibration constants.
Quantity Limits and Batch Reads
The spec allows up to 2000 registers per request, but real devices and masters cap lower: typically 125 registers for FC03/FC04 and 1968 coils for FC01/FC02. Push past the device limit and you get an exception 03 (Illegal Data Value). Over a long RTU bus, huge frames also raise CRC risk and response timeouts. Batch reads in groups of 100–125 registers and you will never hit the limit.
TCP vs RTU: Same Codes, Different Framing
The function codes are identical over Modbus TCP and Modbus RTU. Only the transport framing differs. RTU wraps each frame with a 2-byte CRC and uses silent gaps to delimit frames; TCP prepends a 7-byte MBAP header (transaction ID, protocol ID, length, unit ID) and drops the CRC. The function-code byte and everything after it is the same. See Modbus RTU vs TCP for the transport details.
Frequently Asked Questions
What is the difference between FC03 and FC04 in Modbus?
FC03 reads holding registers (read/write storage, address range 40001–49999) and FC04 reads input registers (read-only measured values, address range 30001–39999). The wire format is identical, only the register type differs. A power meter exposes live voltage and current as input registers (FC04) and configuration thresholds as holding registers (FC03).
What is the most used Modbus function code?
FC03 (Read Holding Registers) is by far the most common function code. Most monitoring applications read configuration and status data from holding registers. FC04 (Read Input Registers) is second, used for live measured values. FC06 and FC16 handle writes; FC16 is preferred over FC06 when setting several registers at once because it is atomic on most devices.
What is the maximum number of registers in one Modbus request?
The Modbus specification allows up to 2000 registers per request, but in practice most devices and masters cap reads at 125 registers. Reading more risks buffer limits, response timeouts, or RTU CRC issues on long serial busses. Batch large reads in groups of 100–125 registers.
Why does my write succeed but the value reads back wrong?
The write almost certainly succeeded, but you are decoding the response with the wrong byte order. 32-bit floats and integers span two registers and every vendor picks a different word/byte swap (ABCD, DCBA, BADC, CDAB). Write 1000.0 and read back 0.0039? Swap the words or bytes until it decodes correctly.
Test Function Codes Without Hardware
MacTools Modbus Poll speaks every standard function code, FC01 through FC06, FC15, FC16, over TCP and RTU, with a built-in slave that responds like a real Schneider PM5560 or SMA inverter. Send the frame, see the hex response, and stop guessing at byte order.
Get Modbus PollFurther Reading
- What Is Modbus? The Protocol That Runs Industrial Automation
- Modbus Register Types Explained: Coils, Discrete Inputs, Holding & Input Registers
- Modbus Addressing Explained: PLC Address vs Protocol Address
- Modbus Exception Codes Explained: Illegal Function, Data, Address
- Modbus Float Byte Order Explained: ABCD, DCBA, BADC, CDAB