Modbus Protocol Explained: Architecture, RTU/TCP, and Function Codes
A plain-English primer on the industrial communication protocol that has refused to die — its architecture, transmission modes, function…
Modbus Protocol Explained: Architecture, RTU/TCP, and Function Codes
A plain-English primer on the industrial communication protocol that has refused to die — its architecture, transmission modes, function codes, and data model.
What Is Modbus?
Modbus is a serial communication protocol developed in 1979 by Modicon (now Schneider Electric) for industrial automation. It uses a master-slave architecture to exchange data between devices over serial (RTU/ASCII) or Ethernet (TCP) connections, making it one of the most widely adopted protocols in IoT and industrial control systems.
In most modern factories, water treatment plants, and building-automation systems, the devices on the other end of the serial cable are speaking Modbus. Not OPC UA, not MQTT, not some newer industrial IoT standard — Modbus, a specification drafted in 1979 for programmable logic controllers that predate the IBM PC.
The protocol has persisted because it solved the right problem the right way. A microcontroller, a serial line, and a few dozen lines of code are enough to make two devices communicate — a design that was practical four decades ago and remains the path of least resistance for embedded developers today. When a communication standard is this lightweight to implement, it tends to stick around.
This article is a working primer on how the protocol actually works — the architecture, the three transmission modes, the function codes, and the data model. If you’re an embedded developer, IoT engineer, or automation specialist who needs to understand Modbus before building on top of it (or debugging someone else’s implementation), read on.
How Modbus Works: The Master-Slave Architecture

Modbus uses a master-slave communication model with the following characteristics:
- Only the master initiates communication by sending a request to a specific slave address.
- Slaves respond only when addressed — they cannot initiate messages on their own.
- One master can address up to 247 slaves (addresses 1–247) on a single bus; address 0 is reserved for broadcast.
- Communication is always request-response — the master asks, the slave answers.
- Modbus TCP uses client-server terminology but follows the same pattern.
This is a deliberate design choice. On a shared serial line where two devices talking at once would corrupt the entire frame, making one device the sole initiator keeps arbitration trivial and the protocol deterministic.
Master Device vs. Slave Device
- Master (Client) — the device that initiates communication. It sends a request and waits for a response.
- Slave (Server) — the device that responds. It never speaks unless spoken to.
A quick note on terminology: in the codebase of lightweight implementations such as nanoMODBUS, “Client” means master and “Server” means slave. We’ll use these terms interchangeably — they describe the same role.
How Communication Happens (Request-Response Cycle)
Every transaction follows a simple cycle: the master sends a request to a specific slave address, the addressed slave processes it and replies, and the master moves on. No slave ever sends unsolicited data. If a slave doesn’t respond within a timeout period, the master treats it as a communication failure and can retry or move to the next device.
This poll-response model is what makes the protocol predictable. There’s no collision detection, no backoff algorithm, no token passing — just a single talker and many listeners, taking turns.
Modbus Transmission Modes: RTU vs ASCII vs TCP

The protocol supports three transmission modes that share the same request logic but differ in how bits hit the wire. The PDU — the actual request payload — is identical across all three. What changes is the framing, the checksum, and the physical layer.

Modbus RTU
Modbus RTU (Remote Terminal Unit) is a binary serial transmission mode that uses RS-232 or RS-485 physical layers. It encodes data in compact binary format, uses CRC-16 for error checking, and relies on silent intervals (3.5 character times) to delimit frames. RTU is the most common mode for industrial serial communication due to its efficiency and reliability.
Key characteristics:

RTU frame format:
+----------+-----------+----------+--------+
| Address | Function | Data | CRC |
| (1 byte) | (1 byte) | (N bytes)| (2 B) |
+----------+-----------+----------+--------+
- Address — the target slave (1–247). The master fills in the destination when requesting; the slave echoes its own address when replying.
- Function code — what the slave should do (read coils, write registers, etc.).
- Data — the parameters for that function code (start address, quantity, values to write).
- CRC — covers the entire message (address + function code + data), protecting against line noise.
The timing rule that frames everything. RTU has no fixed header to mark the start of a message. Instead, it relies on silence: if the gap between two bytes exceeds 3.5 character times, the receiver treats whatever comes next as a new frame. This is RTU’s framing mechanism and a common source of implementation bugs.
At 9600 baud (8 data bits, 1 stop bit, no parity), one character is roughly 1.04 ms — so 3.5 characters is about 3.64 ms. Exceed that gap mid-message and your frame gets split in two.
Modbus ASCII
Modbus ASCII is a text-based serial transmission mode that represents each byte as two hexadecimal ASCII characters. It uses the same RS-232 or RS-485 physical layers as RTU but relies on LRC (Longitudinal Redundancy Check) for error checking and frames messages with a colon (:) start and CRLF end. ASCII mode is primarily used for debugging and legacy systems where human-readable traffic is an advantage.
ASCII frame format:
+------+----------+----------+----------+--------+------+
| ':' | Address | Function | Data | LRC | CRLF |
| (1B) | (2 chars)|(2 chars) | (N chars)|(2 chars)| |
+------+----------+----------+----------+--------+------+
- Start — a colon
:(0x3A). - End — CRLF (0x0D 0x0A).
- Checksum — LRC (Longitudinal Redundancy Check), 1 byte.
- Pro — human-readable in a terminal or serial monitor.
- Con — half the throughput of RTU, since one byte costs two characters on the wire.
ASCII is largely a debugging and legacy concern today. Some lightweight implementations (e.g., nanoMODBUS) support only RTU and TCP.
Modbus TCP
Modbus TCP is an Ethernet-based variant that operates over TCP/IP on port 502. It replaces serial framing with an MBAP (Modbus Application Protocol) header, eliminates the need for CRC error checking (handled by the TCP layer), and supports multiple clients on the same network. TCP is the preferred mode for modern IoT and industrial Ethernet applications.
TCP frame format:
+-------------+-----------+--------------+
| MBAP Header | Function | Data |
| (7 bytes) | (1 byte) | (N bytes) |
+-------------+-----------+--------------+
The MBAP header replaces RTU’s address byte and CRC:

The real-world differentiator is multi-master support. RTU buses are single-master by nature — one talker per wire. TCP lets several clients hit the same server simultaneously, which is why it tends to win in modern architectures that need SCADA, gateways, and historians all talking to one device.
Modbus Function Codes Explained
Every request carries a function code — a single byte telling the slave what operation to perform. The table below covers the 12 function codes supported by common lightweight implementations such as nanoMODBUS:

Read Function Codes (01–04)
The first four codes cover all read operations. Codes 01 and 02 read single-bit data (coils and discrete inputs), while codes 03 and 04 read 16-bit data (holding and input registers). The distinction isn’t just about data size — it’s about which data table the slave looks up, since each type has its own independent address space.
In practice, codes 01–04 generate the overwhelming majority of real-world traffic, since polling sensor states and register values is what most masters do, most of the time.
Write Function Codes (05, 06, 15, 16)
Write operations come in single and multiple variants. Codes 05 and 06 write a single coil or register, respectively, while codes 15 and 16 batch multiple writes into one request. If you need to update ten setpoints at once, code 16 (Write Multiple Registers) is far more efficient than sending ten separate code-06 requests.
Other Common Function Codes
Beyond reads and writes, the protocol defines several advanced operations:
- Code 20/21 (File Records) — read and write file-based data, useful for transferring configuration blocks or logs.
- Code 23 (Read/Write Multiple Registers) — performs a read and a write in a single atomic transaction, critical when you need to read a value and update a related register without another master intervening.
- Code 43/14 (Read Device Identification) — retrieves vendor name, product code, and firmware version, useful for auto-discovery and asset management.
These codes are less common but appear in SCADA integration, gateway applications, and device-management workflows.
Modbus Data Model: Four Types of Data Objects
The data model defines four types of data objects, each with different access permissions and sizes:

Coils
A coil represents a single binary output — historically, the coil of a relay. Coils are read/write, meaning the master can both query and set their state. Function codes 01, 05, and 15 operate on them. A typical use case: turning a pump on or off by writing a 1 or 0 to coil address 0x0012.
Discrete Inputs
Discrete inputs are read-only binary values, typically representing the state of digital sensors — a door switch, a level detector, a fault flag. Function code 02 reads them. The read-only constraint is enforced by the slave device; the master simply cannot write to this data type.
Holding Registers
Holding registers are 16-bit read/write values used for configuration, setpoints, and general-purpose data storage. They’re the workhorse of Modbus — most control parameters live here. Function codes 03, 06, 16, and 23 all operate on holding registers. A PLC might store a temperature setpoint in holding register 0x0064, which a SCADA system reads and updates.
Input Registers
Input registers are 16-bit read-only values, typically holding analog measurements — temperature, pressure, voltage, current. Function code 04 reads them. Think of an input register as the digitized output of an ADC: the sensor measures a physical quantity, the device converts it to a 16-bit integer, and the master polls it.
Important: Each data object has its own independent address space spanning 0x0000–0xFFFF (65,536 addresses). Coil address 0 and holding-register address 0 are two completely different things — they never collide, because the function code determines which table is being addressed.
PDU and ADU: Understanding the Frame Structure
Two acronyms separate the protocol logic from the transport. Understanding this split makes reading any implementation far more straightforward, because you can see exactly where the protocol ends and the transport begins.

Protocol Data Unit (PDU)
The Protocol Data Unit (PDU) is the protocol-independent core of every Modbus message. It consists of a 1-byte function code followed by optional data fields (0–252 bytes). The PDU is identical across all variants (RTU, ASCII, TCP) — only the surrounding Application Data Unit (ADU) differs. For example, a read holding registers request has a PDU of: function code (0x03) + starting address + quantity.
+-------------+----------------+
| Function | Data |
| (1 byte) | (0–252 bytes) |
+-------------+----------------+
Whether you’re on RTU or TCP, the PDU is identical. That’s why a request means the same thing no matter how it’s delivered.
Application Data Unit (ADU)
The ADU wraps the PDU in whatever the transport layer needs — an address for routing and a checksum or header for integrity.
RTU’s ADU:
+----------+----------+--------+
| Address | PDU | CRC |
| (1 byte) | (above) | (2 B) |
+----------+----------+--------+
TCP’s ADU:
+-------------+----------+
| MBAP Header | PDU |
| (7 bytes) | (above) |
+-------------+----------+
In plain terms: the PDU is “what you want to do,” and the ADU is “what you want to do, packaged for the wire it’s traveling on.” RTU adds an address byte and a CRC; TCP adds an MBAP header. Once you internalize this split, reading any implementation — including the nanoMODBUS codebase we’ll dig into in a follow-up — becomes far more intuitive.
Modbus Exception Codes
When a slave receives a request it can’t honor, it replies with an exception response instead of a normal one. The function code is set to the original code plus 0x80, followed by a single exception-code byte that explains what went wrong:

If you’re debugging a link and the master keeps reporting errors, checking which exception code comes back is the fastest way to localize the fault. Code 02 means “you’re asking for an address that doesn’t exist.” Code 03 means “the address exists, but the value is out of bounds.” Codes 05 and 06 are transient — the master should retry after a short delay.
Conclusion: Why Modbus Still Matters in 2026
At this point, you have the mental model needed to work with the Modbus protocol:
- It’s master/slave — the master asks, the slave answers, and one bus serves up to 247 slaves.
- Three modes share one protocol — RTU (binary serial, efficient), ASCII (text serial, readable but slower), and TCP (Ethernet, multi-client).
- Twelve function codes operate on four data objects — coils, discrete inputs, holding registers, and input registers — each in its own address space.
- PDU vs. ADU separates the request logic from the transport framing, which is why the same request works over serial or Ethernet unchanged.
Modbus endures not because it’s sophisticated, but because it’s just enough protocol — deterministic, lightweight, and implementable on almost any hardware. When the next shiny industrial standard arrives, it’ll have to clear that bar to displace a specification that has run the factory floor for over four decades.
For the official specification, refer to the Modbus Application Protocol Specification from modbus.org.
Found this helpful? Give it a clap and follow for more industrial communication deep dives.
Which Modbus variant do you use most — RTU or TCP? Let me know in the comments.
메타데이터
- post_id
- 21f46bc29de2
- slug
- modbus-protocol-explained-architecture-rtu-tcp-and-function-codes-21f46bc29de2
- url
- https://medium.com/@enwebiot/modbus-protocol-explained-architecture-rtu-tcp-and-function-codes-21f46bc29de2
- canonical_url
- https://medium.com/@enwebiot/modbus-protocol-explained-architecture-rtu-tcp-and-function-codes-21f46bc29de2
- author_url
- https://medium.com/@enwebiot
- status
- ok
- fetched_at
- 2026-06-27 07:40:21