Modbus RTU — Industrial Software Protocol over RS-485
Modbus is the protocol that answers the question RS-485 leaves open: "The bus can carry bits — but what do those bits mean?"
Created by Modicon in 1979 for their PLCs, Modbus became the first truly open industrial communication standard. It is still the most widely deployed industrial protocol in the world, found in power meters, temperature controllers, variable frequency drives, solar inverters, water treatment systems, and building management systems.
Hardware vs Software — The Critical Distinction
This is the most important concept on this page. Understand this and everything else will make sense.
Analogy: RS-485 is the road. UART is the rule that vehicles drive on the left or right. Modbus is the language the drivers speak to each other.
You can run Modbus on RS-232 too (for point-to-point). You can also run Modbus over Ethernet (that becomes Modbus TCP). Modbus the protocol is independent of the physical medium.
Modbus Architecture — Master and Slaves
Modbus RTU is a strict master-slave protocol:
- There is exactly one master (a PLC, SCADA system, or Raspberry Pi)
- There can be up to 247 slaves (sensors, meters, drives)
- The master always initiates — slaves never speak unless spoken to
- Only one device transmits at a time (matches RS-485 half-duplex)
Address 0 is the broadcast address — the master can send to all slaves simultaneously, but no slave replies to a broadcast.
The Modbus RTU Frame
Every message — request and response — follows this binary frame format:
┌──────────┬───────────────┬──────────────────────┬────────────────┐
│ Slave │ Function │ Data │ CRC Check │
│ Address │ Code │ │ (Error check) │
│ 1 byte │ 1 byte │ 0 to 252 bytes │ 2 bytes │
└──────────┴───────────────┴──────────────────────┴────────────────┘
| Field | Size | Purpose |
|---|---|---|
| Slave Address | 1 byte | Which device should respond (1–247). 0 = broadcast. |
| Function Code | 1 byte | What operation to perform (read, write, etc.) |
| Data | Variable | Registers to read, values to write, count of registers |
| CRC | 2 bytes | 16-bit Cyclical Redundancy Check for error detection |
Frame Timing — How Modbus Knows Where a Frame Ends
Unlike protocols with a length field, Modbus RTU uses silence to mark frame boundaries. A gap of 3.5 character times on the bus signals the end of a frame. At 9600 baud, a character takes about 1.04 ms, so the gap is ~3.5 ms.
Function Codes — What You Can Do
Function codes define the operation. The most common ones:
| FC | Operation | Description |
|---|---|---|
| 01 | Read Coils | Read 1–2000 bits (digital outputs, ON/OFF) |
| 02 | Read Discrete Inputs | Read 1–2000 bits (digital inputs, read-only) |
| 03 | Read Holding Registers | Read 1–125 × 16-bit registers (most common) |
| 04 | Read Input Registers | Read 1–125 × 16-bit registers (read-only) |
| 05 | Write Single Coil | Set one bit ON (FF00) or OFF (0000) |
| 06 | Write Single Register | Write one 16-bit value |
| 15 | Write Multiple Coils | Set multiple bits at once |
| 16 | Write Multiple Registers | Write multiple 16-bit values |
Example: Reading Two Holding Registers from Slave 1
Request (master sends):
01 03 00 00 00 02 C4 0B
│ │ │────│ │────│ │──────│
│ │ Start Count CRC
│ FC 03 = Read Holding Registers
Slave address 01
Response (slave sends):
01 03 04 02 3A 01 F4 XX XX
│ │ │ │────│ │────│ │──────│
│ │ │ Reg 0 Reg 1 CRC
│ │ Byte count = 4 bytes (2 registers × 2 bytes)
│ FC 03 confirms
Slave address 01
Register 0 = 0x023A = 570 → voltage = 57.0 V (scale factor defined by device manual)
Register 1 = 0x01F4 = 500 → current = 5.00 A (scale factor defined by device manual)
The Register Map — Where to Find the Data
Each Modbus slave device has a register map defined in its datasheet. This tells you which register number holds which value. For example, a power meter might define:
| Register | Data | Scale |
|---|---|---|
| 0000 | Voltage (V × 10) | ÷10 to get volts |
| 0001 | Current (A × 100) | ÷100 to get amps |
| 0002 | Power (W) | direct |
| 0003 | Energy (Wh) | direct |
| 0100 | Baud rate setting | 0=9600, 1=19200 |
| 0101 | Device slave address | 1–247 |
There is no standard register map — every manufacturer defines their own. You must read the device datasheet.
Error Responses
If a slave receives a valid frame but cannot execute the request (wrong register address, value out of range, etc.), it returns an exception response:
01 83 02 XX XX
│ │ │ │──────│
│ │ │ CRC
│ │ Exception code 02 = Illegal data address
│ FC 03 + 0x80 = 0x83 (error flag)
Slave address 01
Common exception codes:
01— Illegal function code02— Illegal data address03— Illegal data value04— Slave device failure
Typical Baud Rates
Modbus RTU works at standard UART baud rates. The most common is 9600 baud in legacy systems, but 19200 and 115200 are common in newer installations. All devices on the bus must use the same baud rate.
| Baud rate | Bytes/sec | Typical use |
|---|---|---|
| 9600 | 960 | Legacy PLCs, slow meters |
| 19200 | 1920 | Common industrial default |
| 38400 | 3840 | Faster systems |
| 115200 | 11520 | Modern RTUs, gateways |
What Modbus RTU Cannot Do
Modbus RTU has known limitations that have shaped the need for Modbus TCP and other modern protocols:
| Limitation | Consequence |
|---|---|
| One master only | Cannot have two PLCs poll the same bus |
| Polling only | Slaves cannot push data — master must request |
| 247 slaves max | Limited bus population |
| No timestamp, no priority | Every slave waits its turn |
| Slow for large data | Not suitable for transferring large files |
| No native encryption | Data is plaintext |
For networks or higher device counts → Modbus TCP.
Key Takeaway
Modbus RTU is a software protocol that sits on top of RS-485 (or RS-232) and gives meaning to the bytes. It defines addresses (which device), function codes (what operation), registers (which data), and CRC (error check). RS-485 and UART carry those bytes electrically.
Understanding this separation — hardware layer vs software protocol — is what the next page makes even clearer by showing what happens when you take the same Modbus protocol and run it over Ethernet instead.