To build a reliable Arduino RS485 network, use an Arduino Uno R3 (ATmega328P) paired with a MAX485 TTL-to-RS485 transceiver module, wired with a 120Ω terminating resistor across the A and B differential lines, and driven by explicit DE/RE pin toggling with a post-transmit delay. Standard TTL serial (UART) fails past 15 meters or in electrically noisy environments like motor drives and relay panels. RS485 solves this by transmitting data as a differential voltage across a twisted pair, rejecting common-mode noise and allowing bus lengths up to 1,200 meters.
This guide provides the exact hardware decisions, fail-safe wiring practices, and compilable code needed to deploy a robust half-duplex RS485 master-node system.
The RS485 Decision Matrix: Which Transceiver Module to Buy?
Not all RS485 modules are identical. Picking the wrong transceiver for your voltage domain or noise environment is the leading cause of failed bench prototypes. Use this decision tree to select the correct module.
| Your Scenario | Module Pick | Logic Voltage | Max Nodes | 2026 Avg Cost |
|---|---|---|---|---|
| Indoor hobby project, 5V Arduino (Uno/Mega), short runs (<50m) | Generic MAX485 (HW-519) | 5V | 32 | $1.50 - $2.50 |
| 3.3V logic (ESP32, Raspberry Pi Pico), short to medium runs | MAX3485 Module | 3.3V | 32 | $3.00 - $4.50 |
| Industrial environment, near VFDs/motors, long runs, mixed voltages | Isolated RS485 (XY-017 / UCC12040) | 3.3V - 5V | 32 | $8.00 - $12.00 |
| Massive multi-drop sensor network (up to 256 devices on one bus) | MAX13487 / SP485 Module | 3.3V / 5V | 256 | $4.00 - $6.00 |
Hardware Build: Parts List and Pin Mapping
This build assumes a Master-Node topology where the Arduino Uno R3 acts as the Master, polling a remote Node (which can be another Arduino or a dedicated RS485 sensor).
Bill of Materials (Master Node)
- Microcontroller: Arduino Uno R3 (ATmega328P) or genuine clone with CH340/ATmega16U2.
- Transceiver: MAX485 TTL-to-RS485 module (HW-519 variant).
- Cable: 22 AWG twisted pair (Cat5e Ethernet cable works perfectly; use one pair for A/B, and reserve another pair for GND).
- Termination Resistor: 120Ω 1/4W carbon film (placed only at the physical ends of the bus).
- Bias Resistors: 560Ω 1/4W (one for pull-up, one for pull-down).
Pin Mapping Table: Arduino Uno R3 to MAX485
| MAX485 Module Pin | Arduino Uno R3 Pin | Function & Notes |
|---|---|---|
| VCC | 5V | Powers the transceiver IC. |
| GND | GND | Must share a common ground reference with the remote node. |
| RO (Receiver Out) | Pin 10 (SoftwareSerial RX) | Data from bus to Arduino. |
| DI (Driver In) | Pin 11 (SoftwareSerial TX) | Data from Arduino to bus. |
| DE (Driver Enable) | Pin 3 | HIGH = Transmit, LOW = Receive. (Jumpered with RE). |
| RE (Receiver Enable) | Pin 3 | Active LOW. Jumper DE and RE together for half-duplex control. |
| A (Non-Inverting) | Twisted Pair Wire 1 | Positive differential line. |
| B (Inverting) | Twisted Pair Wire 2 | Negative differential line. |
Step-by-Step Wiring with Bias and Termination
Most online tutorials skip bus biasing and termination, which works on a 1-meter breadboard but fails in the real world. Follow these steps to wire the physical layer correctly.
- Connect Logic Pins: Wire VCC to 5V, GND to GND, RO to Pin 10, DI to Pin 11. Jumper the DE and RE pins together, then connect them to Pin 3.
- Wire the Differential Pair: Connect the MAX485 'A' pin to one wire of your twisted pair, and 'B' to the other. Pro-tip: Standardize your wire colors (e.g., Orange/White-Orange for A/B). Swapping A and B will invert the signal and result in garbage data.
- Add Termination (Ends of Bus Only): Solder a 120Ω resistor directly across the A and B terminals on the Master module, and another 120Ω resistor across the A and B terminals on the furthest Node module. Do not place termination resistors on intermediate nodes.
- Add Failsafe Biasing (Master Only): RS485 buses float when no node is transmitting, making them susceptible to noise-induced phantom bytes. On the Master module, solder a 560Ω resistor from VCC (5V) to the 'A' line (pull-up), and a 560Ω resistor from GND to the 'B' line (pull-down). This biases the idle state to a logic HIGH.
- Connect Common Ground: RS485 is differential, but the transceiver ICs still require a shared ground reference to keep the common-mode voltage within the -7V to +12V spec. Run a dedicated ground wire alongside your twisted pair.
When transmitting, you must set DE/RE HIGH, send the data, and then set DE/RE LOW. However, the Arduino's UART hardware buffers the transmission. If you set DE/RE LOW immediately after
Serial.print(), the transceiver will switch to receive mode before the last byte finishes shifting out, corrupting the final byte. Always include a delayMicroseconds() or Serial.flush() before dropping the DE/RE pin LOW.
Complete Arduino RS485 Master/Node Code
This code targets the Arduino Uno R3 (ATmega328P). It uses the built-in SoftwareSerial library for the RS485 bus, reserving the hardware Serial (pins 0/1) for USB debugging via the Serial Monitor. The Master sends a framed packet with a simple checksum; the Node validates it and replies.
Master Code (Arduino Uno R3)
#include <SoftwareSerial.h>
// Pin Definitions
#define RS485_RX_PIN 10
#define RS485_TX_PIN 11
#define DE_RE_PIN 3
// RS485 Serial Instance
SoftwareSerial rs485(RS485_RX_PIN, RS485_TX_PIN);
const byte NODE_ADDRESS = 0x01;
const byte CMD_READ_TEMP = 0x10;
void setup() {
Serial.begin(115200); // USB Debugging
rs485.begin(9600); // RS485 Bus Speed
pinMode(DE_RE_PIN, OUTPUT);
digitalWrite(DE_RE_PIN, LOW); // Default to Receive mode
Serial.println("Master initialized. Polling node...");
}
void loop() {
// 1. Build Packet: [Address] [Command] [Checksum]
byte packet[3];
packet[0] = NODE_ADDRESS;
packet[1] = CMD_READ_TEMP;
packet[2] = packet[0] ^ packet[1]; // Simple XOR Checksum
// 2. Transmit
digitalWrite(DE_RE_PIN, HIGH); // Enable Driver (TX)
delayMicroseconds(50); // Allow transceiver to settle
rs485.write(packet, sizeof(packet));
rs485.flush(); // Wait for TX buffer to empty
delayMicroseconds(500); // Wait for last byte to shift out at 9600 baud
digitalWrite(DE_RE_PIN, LOW); // Enable Receiver (RX)
// 3. Listen for Response
unsigned long startTime = millis();
byte response[3];
byte index = 0;
while (millis() - startTime < 1000) { // 1 second timeout
if (rs485.available()) {
response[index++] = rs485.read();
if (index >= 3) break;
}
}
// 4. Validate Response
if (index == 3) {
byte expectedChecksum = response[0] ^ response[1];
if (response[2] == expectedChecksum) {
Serial.print("Node replied with value: ");
Serial.println(response[1]);
} else {
Serial.println("Error: Checksum mismatch on response.");
}
} else {
Serial.println("Error: Serial timeout. No response from node.");
}
delay(2000); // Poll every 2 seconds
}
Note: The Node code follows the inverse logic: it keeps DE/RE LOW to listen, calculates the checksum upon receipt, toggles DE/RE HIGH to send the payload, and applies the same post-transmit delay before returning to RX mode.
Debugging: "Garbage Characters" and Timeout Errors
RS485 debugging is notoriously frustrating because the physical layer issues manifest as software errors. If your Serial Monitor is throwing errors, follow this diagnostic path.
The First Three Things to Check When It Fails
- A/B Wire Swap: 50% of all RS485 failures are simply swapped A and B wires. Swap them at the module terminal block and test again.
- Missing Common Ground: If you only ran two wires (A and B) without a ground wire, the common-mode voltage will drift outside the transceiver's tolerance. Run a ground wire.
- Baud Rate Mismatch: Ensure both Master and Node are initialized to the exact same baud rate (e.g., 9600). SoftwareSerial is highly sensitive to timing interruptions; if your Node code uses heavy interrupts (like PWM or servo libraries), it will corrupt SoftwareSerial RX timing.
Ranked Causes for Specific Error Strings
| Exact Error String / Symptom | Ranked Causes (Most Likely First) | Fix / Measurement |
|---|---|---|
"Garbage characters on Serial Monitor" (e.g., squares, question marks) |
1. Baud rate mismatch between hardware Serial and Serial Monitor. 2. A/B lines swapped. 3. Missing failsafe bias resistors causing noise triggers. |
Verify Serial Monitor is set to 115200. Swap A/B. Add 560Ω bias resistors. |
"Error: Serial timeout. No response from node." |
1. DE/RE pin stuck HIGH (Master never switches to RX). 2. Node is unpowered or crashed. 3. Cable break. |
Measure DE/RE pin with a multimeter; it should pulse. Check Node 5V rail. |
"Error: Checksum mismatch on response." |
1. Post-transmit delay too short (last byte truncated). 2. Heavy EMI corrupting bits mid-flight. 3. Ground loop inducing current. |
Increase delayMicroseconds() after flush(). Switch to shielded twisted pair (STP). |
Extending the Network: Multi-Drop and ESP32 Upgrades
Once your basic two-node Master/Slave link is stable, you will likely want to scale the system. Here is how to extend or simplify the build based on your end goal.
Scaling to Multi-Drop (Up to 32 Nodes)
The standard MAX485 IC supports up to 32 unit loads on a single bus. To add more nodes:
- Wire all 'A' pins together and all 'B' pins together in a daisy-chain topology. Never use star wiring; stubs longer than 1 meter cause signal reflections that destroy data integrity at higher baud rates.
- Place 120Ω termination resistors only on the Master (first node) and the final Node in the chain.
- Implement a strict addressing protocol in software. The Master must prepend a Node ID byte to every packet, and Nodes must ignore packets that do not match their hardcoded ID.
Migrating to ESP32 for Higher Speed and Hardware UARTs
If you need to integrate WiFi/MQTT or push baud rates above 38400, the Arduino Uno's SoftwareSerial will bottleneck. Migrating to an ESP32 DevKit v1 is the logical next step, but it requires two hardware changes:
- Logic Level Shift: The ESP32 operates at 3.3V logic. Feeding 5V from a standard MAX485 into the ESP32's RX pin will eventually degrade the GPIO. Swap the MAX485 module for a MAX3485 module, which is natively designed for 3.3V operation.
- Hardware UART Assignment: The ESP32 has three hardware UARTs. Use
Serial1orSerial2for the RS485 bus to eliminate software timing jitter. You can map the UART pins in code usingSerial1.begin(115200, SERIAL_8N1, RX_PIN, TX_PIN).
For authoritative design parameters on cable capacitance and termination, refer to the Texas Instruments RS-485 Design Guide (SLYA049). For transceiver-specific electrical characteristics and truth tables, consult the Analog Devices MAX485 Datasheet.






