Part II · Chapter 8
Function Codes in Depth
A function code is the verb of a Modbus request. Eight of them do nearly all the everyday work, and they follow a pattern simple enough that you never need to memorize them as a list.
By the end of this chapter you can
- Pick the right function code for any read or write, straight from the data model.
- Lay out the request and response for the register reads, the bit reads, and the single and multiple writes.
- Unpack coil bits from a response byte, and use the 0xFF00 / 0x0000 rule for single coils.
- Recognize the rarer codes when a device manual mentions them.
The eight that matter
The working set falls into an obvious pattern: four codes read the four data tables, and four write the two writable tables. Every readable table has a read function, and every writable table has both a single-item and a multiple-item write. Each code is just "read this table" or "write that table," and its data field follows from the data model of Chapter 2.
| Code | Name | Acts on | Max per request |
|---|---|---|---|
| 0x01 | Read Coils | Coils (bits, read) | 2000 bits |
| 0x02 | Read Discrete Inputs | Discrete inputs (bits, read) | 2000 bits |
| 0x03 | Read Holding Registers | Holding registers (read) | 125 registers |
| 0x04 | Read Input Registers | Input registers (read) | 125 registers |
| 0x05 | Write Single Coil | One coil (bit, write) | 1 coil |
| 0x06 | Write Single Register | One holding register (write) | 1 register |
| 0x0F | Write Multiple Coils | Many coils (bits, write) | 1968 bits |
| 0x10 | Write Multiple Registers | Many holding registers (write) | 123 registers |
The per-request limits come from the 253-byte PDU ceiling of Chapter 4. A client that needs more simply sends several requests. You'll also see 0x0F and 0x10 written in decimal as FC15 and FC16.
Reading registers (0x03 and 0x04)
Read Holding Registers (0x03) and Read Input Registers (0x04) are the codes you'll use most. They're identical in shape and differ only in the table they touch. After the function code, the request carries a two-byte starting address and a two-byte quantity, up to 125 registers.
The response echoes the function code, then a one-byte byte count, then the values, two bytes per register in big-endian order. The byte count is always twice the number of registers. Here is the running example, four holding registers from address 0:
| Direction | Bytes | Field |
|---|---|---|
| Request | 03 | Function code |
| Request | 00 00 | Starting address |
| Request | 00 04 | Quantity (4 registers) |
| Response | 03 | Function code (echoed) |
| Response | 08 | Byte count (4 × 2) |
| Response | xx xx xx xx xx xx xx xx | Four register values |
Wrapped in an RTU frame for server 1, with the registers holding 100, 200, 300 and 400:
Notice that the response doesn't repeat the starting address. The client has to remember what it asked for and match the values up itself. The Modbus specification's own example reads three registers from server 17 (0x11), starting at address 107 (reference 40108):
Change the 03 to 04 and the same exchange reads input registers instead. Same shape, different table.
Reading bits (0x01 and 0x02)
Read Coils (0x01) and Read Discrete Inputs (0x02) use the same request shape: function code, starting address, and a quantity, this time a count of bits up to 2000. The response again echoes the function code and gives a byte count, but the bits are packed eight to a byte rather than wasting seven-eighths of the space sending each bit in its own byte.
The packing rule surprises newcomers: within each byte, the first requested coil is the least significant bit. Read eight coils with the first, third, and fourth ON, and the byte is not what you'd write left to right. It's 0x0D, because bits 0, 2, and 3 are set. Bytes fill from the low coil upward: coils 0–7 in the first byte, 8–15 in the next, and unused high bits of the last byte are sent as zero.
The book's example as complete RTU frames, reading coils 0–7 from server 1:
When the count isn't a multiple of eight, the last byte is padded. Reading 10 coils from address 19 needs two bytes: CD holds coils 19–26 and 01 holds coils 27–28 in its two low bits, with bits 2–7 sent as zero.
CD is 1100 1101. Read right to left: coil 19 ON, 20 off, 21 and 22 ON, 23 and 24 off, 25 and 26 ON. Read Discrete Inputs (0x02) packs its bits exactly the same way.
Writing one thing (0x05 and 0x06)
To change a single value, use Write Single Coil (0x05) or Write Single Register (0x06). The request carries the function code, the two-byte address of the item, and a two-byte value. Both have a pleasing property: the response is an exact echo of the request, confirming the precise value was written.
Write Single Register is the obvious one: the value bytes are the 16-bit number to store. Write Single Coil has a quirk. A coil is one bit, but the value field is two bytes, and rather than 0x0001 for on, the protocol uses 0xFF00 for ON and 0x0000 for OFF. No other value is valid; a server answers anything else with exception 03, Illegal Data Value. Turning coil 5 on:
| Direction | Bytes | Field |
|---|---|---|
| Request | 05 | Function code |
| Request | 00 05 | Coil address (5) |
| Request | FF 00 | Value = ON |
| Response | 05 00 05 FF 00 | Exact echo of the request |
Write Single Register works the same way. Setting register 1 to 3 on server 1, which the server echoes back unchanged:
Writing many things (0x0F and 0x10)
To set a run of items in one shot, use Write Multiple Coils (0x0F) or Write Multiple Registers (0x10). After the function code come the starting address and the quantity, then a one-byte byte count, then the values: packed bits for coils, two bytes per register for registers. The response is short: it echoes the function code, starting address and quantity, confirming how many items were written without repeating the data.
Write Multiple Registers is the one you'll reach for constantly, both to set several parameters at once and, as Chapter 14 shows, to write values too wide for one register. Writing 0x000A and 0x0102 starting at address 16:
| Direction | Bytes | Field |
|---|---|---|
| Request | 10 | Function code |
| Request | 00 10 | Starting address (16) |
| Request | 00 02 | Quantity (2 registers) |
| Request | 04 | Byte count (2 × 2) |
| Request | 00 0A 01 02 | The two values |
| Response | 10 00 10 00 02 | Echo: function, address, quantity |
Write Multiple Coils (0x0F) has the same shape, with the bits packed exactly as 0x01 returns them. Writing the ten coil states from the read example above back to coils 19–28:
A note on the rarer codes
The specification defines a handful of less common codes you may meet occasionally. Treat them as special cases: when you need one, the device manual will show its exact layout, and by then reading a layout will be second nature. Appendix A lists them all.
| Code | Name | What it does |
|---|---|---|
| 0x07 | Read Exception Status | Returns one device-defined status byte (serial only; Chapter 9) |
| 0x08 | Diagnostics | Serial-line tests and counters, chosen by a sub-function (Chapter 9) |
| 0x0B | Get Comm Event Counter | A status word and a count of successful messages (serial) |
| 0x0C | Get Comm Event Log | The counter plus a short log of recent events (serial) |
| 0x11 | Report Server ID | Device-specific identification and run status (serial) |
| 0x14 / 0x15 | Read / Write File Record | Access to grouped "file" records of registers |
| 0x16 | Mask Write Register | Changes selected bits of one holding register in place, using AND and OR masks |
| 0x17 | Read/Write Multiple Registers | A write and a read in one transaction (the write is performed first) |
| 0x18 | Read FIFO Queue | Reads a queue of registers from a device FIFO |
| 0x2B / 0x0E | Read Device Identification | Vendor name, product code, and revision, as text objects |
These can be set aside while learning because the great majority of real integration work (reading measurements, checking status bits, changing settings, commanding outputs) is fully served by the eight core codes.
Request builder
Address: a zero-based number (107, 0x6B) or a 5- or 6-digit reference (40108, 400108, 00012), which is converted for you.
PDU (function code + data)
RTU request frame
Expected response
Check your understanding
1. A setpoint is listed at reference 40021. Which function code and address read it?
4xxxx means holding register, read with 0x03. Drop the leading 4 and subtract one: 40021 → address 20.
2. You read 8 coils from address 0 and the data byte is 0x0D. Which coils are ON?
0x0D = 0000 1101. Bits 0, 2 and 3 are set, and the first coil requested sits in bit 0.
3. A Write Single Coil request carries the value 00 01. What does a compliant server do?
Only 0xFF00 (ON) and 0x0000 (OFF) are valid for 0x05. Anything else breaks the request's rules, which is exactly what exception 03 reports.
4. What does a successful Write Multiple Registers (0x10) response contain?
Multiple writes get a short echo confirming where and how many items were written; the data isn't repeated.