Learning Goals 5 min
Real factories — power plants, HVAC, water treatment — still run protocols designed in the 1970s. RS-485 is the most widely deployed industrial wiring; Modbus is the most widely deployed protocol on top of it. By the end of this lesson you will:
- Explain RS-485 vs RS-232 / TTL UART: differential signalling, longer cables, multi-drop.
- Wire a MAX485 transceiver to an Arduino, two devices on a single twisted pair.
- Use the
ModbusMasterlibrary to read a register from a Modbus RTU slave (a real industrial sensor, or a second Arduino playing slave).
Warm-Up 10 min
Hardware:
- 2 × Arduino UNO (or any board with UART).
- 2 × MAX485 transceiver modules.
- A twisted pair (Ethernet cable's blue/blue-white works fine for short runs).
- 120 Ω terminating resistor (optional for short cable, recommended for long).
Why industry uses RS-485 instead of UART
| Property | UART (TTL / RS-232) | RS-485 |
|---|---|---|
| Signalling | Single-ended (each wire vs GND) | Differential (A vs B) |
| Max cable length | ~15 m at 9600 baud | ~1200 m at 9600 baud |
| Noise immunity | Poor | Excellent (common-mode rejection) |
| Devices per bus | 2 (point-to-point) | Up to 32 (multi-drop) |
| Half / full duplex | Full | Half (typically) |
The trade-off: half-duplex (one talker at a time) and you need to control RE/DE (receive/driver enable) pins to switch direction.
New Concept · MAX485 + Modbus RTU 25 min
The MAX485 transceiver
A tiny chip + breakout board that converts UART signals (TX/RX, single-ended) to RS-485 (A/B, differential). Five connections:
| MAX485 pin | Connect to |
|---|---|
| VCC | 5 V |
| GND | GND |
| DI (driver input) | Arduino TX (D1 on UNO, or any SoftwareSerial TX) |
| RO (receiver output) | Arduino RX (D0 on UNO, or any SoftwareSerial RX) |
| RE/DE | Tied together → one Arduino GPIO (digital). HIGH = transmit, LOW = receive. |
| A, B | Twisted pair, connected across the bus (all devices' A together, all B together) |
The RE/DE direction wire
Standard half-duplex RS-485 needs a control wire to switch the transceiver between TX and RX. Some smart MAX485 modules (with auto-direction) skip this — they sense activity on DI and flip automatically. Either way:
const int DE_RE = 8;
void beforeTransmit() { digitalWrite(DE_RE, HIGH); delayMicroseconds(50); }
void afterTransmit() { Serial.flush(); digitalWrite(DE_RE, LOW); }Modbus RTU
The simplest Modbus variant. Frame format:
- 1 byte slave address.
- 1 byte function code (e.g. 0x03 = read holding registers).
- Function-specific data (start register, count, etc.).
- 2 byte CRC.
Common function codes:
| Code | Meaning |
|---|---|
| 0x01 | Read coils (binary outputs) |
| 0x02 | Read discrete inputs (binary inputs) |
| 0x03 | Read holding registers (16-bit read-write) |
| 0x04 | Read input registers (16-bit read-only) |
| 0x05 | Write single coil |
| 0x06 | Write single register |
| 0x10 | Write multiple registers |
Master / slave architecture
Modbus is strictly master/slave (now also called "client/server" in modern docs). The master initiates every transaction. Slaves only respond when asked. Multiple slaves on one bus; only one master.
The ModbusMaster library
Library Manager → search "ModbusMaster" (by Doc Walker). Install. Provides a simple API to query slaves.
#include <ModbusMaster.h>
ModbusMaster node;
const int DE_RE = 8;
void preTx() { digitalWrite(DE_RE, HIGH); }
void postTx() { digitalWrite(DE_RE, LOW); }
void setup() {
pinMode(DE_RE, OUTPUT);
postTx();
Serial.begin(9600); // RS-485 bus
node.begin(1, Serial); // slave address 1
node.preTransmission(preTx);
node.postTransmission(postTx);
}
void loop() {
// Read holding registers 0..2 from slave 1
uint8_t result = node.readHoldingRegisters(0, 2);
if (result == node.ku8MBSuccess) {
Serial.print("R0="); Serial.print(node.getResponseBuffer(0));
Serial.print(" R1="); Serial.println(node.getResponseBuffer(1));
} else {
Serial.print("err="); Serial.println(result);
}
delay(2000);
}(Note: on a UNO, the same Serial port is used for both USB upload AND the RS-485 bus. Switch to SoftwareSerial or Hardware Serial1 on a Mega / ESP32 for real production use.)
Worked Example · Two Arduinos talking Modbus 25 min
Setup
Master + slave, each with a MAX485, connected over A and B (twisted pair).
Slave sketch (simulates a sensor)
#include <ModbusSlave.h> // simplified; alternative library
uint16_t holdingRegisters[2] = {0, 0};
const int DE_RE = 8;
// (Library calls: register 0..1 readable. Library handles framing + CRC.)
// On request from master, library replies with holdingRegisters[].For a real slave, see the SimpleModbusSlave or ModbusRTUSlave examples — they take care of framing and CRC.
Master sketch (from §3)
Polls registers 0 and 1 every 2 s.
Verify
Master prints "R0=0 R1=0" etc. Modify the slave to update registers from a pot or a sensor; master sees the values.
Range test
Use a long twisted-pair cable (15 m, 50 m if you have one) between master and slave. Modbus + RS-485 still works at 9600 baud over > 100 m without retransmissions.
Why this matters
Almost every commercial energy meter, HVAC sensor, factory I/O block, motor controller speaks Modbus over RS-485. Knowing this protocol means you can read data from real industrial equipment with an Arduino — invaluable for maker-style monitoring of real systems (solar panels, energy meters, etc.).
Try It Yourself 15 min
Goal: Add a third register to the slave for a pot reading. Master reads register 2 = current pot value.
Goal: The master writes a register on the slave: writing register 0 = 1 turns on an LED on the slave. Use function code 0x06.
Goal: Two slaves on the same bus (addresses 1 and 2). Master polls both. Practise the multi-drop pattern.
Mini-Challenge · Read a real Modbus device 10 min
If your school / home has any Modbus device — energy meter, solar inverter, HVAC controller — try reading its register map. Many manufacturers publish their register list. With an Arduino + MAX485 + the right baud / address, you can monitor real industrial data.
If not, this remains a powerful capability to know: when you encounter a Modbus device, you're ready.
Recap 5 min
RS-485 = differential, long-distance, multi-drop wiring. MAX485 module bridges Arduino UART to RS-485. Modbus RTU = master/slave protocol over RS-485, dating from 1979, still in every factory. ModbusMaster library handles framing + CRC. Tomorrow: CAN bus, the in-vehicle equivalent.
- RS-485
- Differential serial wiring spec. Two wires (A/B), up to 1200 m, multi-drop, half-duplex.
- Differential signalling
- Two wires carrying opposite polarities of the signal. Common-mode noise cancels on receive. Allows long cables.
- MAX485
- The classic RS-485 transceiver chip. Module form has 4 logic pins + 2 bus pins.
- RE/DE
- Receive Enable / Driver Enable. Tied together, controlled by a GPIO. HIGH = transmit, LOW = receive.
- Modbus RTU
- The serial flavour of Modbus. Master/slave, function codes, CRC.
- Holding register
- A 16-bit value on a slave that the master can read and write. The most-used data type in Modbus.
- Multi-drop
- One bus, many devices. Each has a unique address. Only one talks at a time.
- Termination resistor
- 120 Ω across A and B at each end of a long bus. Prevents signal reflections.
Homework 5 min
- If you have MAX485 modules: build the two-Arduino bus and read one register.
- Look up the register map of one Modbus device near you. Bookmark.
- Read ahead to ARD-L04-21 (CAN Bus Basics).