Skip to content
Tutorial
15 min read
October 17, 2026

RS485 with MAX485 and Arduino: Wiring, Code and Modbus RTU

Build a robust multi-drop RS485 bus with MAX485 modules: wiring for Uno and ESP32, termination, direction control, a checksummed master/slave protocol, and a Modbus RTU master.

What You'll Build

A small RS485 network in which one Arduino (the master) talks to one or more slave nodes over a single twisted pair. The master polls each slave for a sensor reading and switches an LED on a slave on and off. Then you will switch the same hardware to Modbus RTU and read registers from an industrial-style sensor.

You will learn:

  • Why RS485 survives noise and long cables where plain UART and TTL do not
  • How the MAX485 transceiver works and what DE and RE do
  • How to wire it to an Arduino Uno and to an ESP32 (and the level trap on the ESP32 receive line)
  • How to terminate and bias a bus so it stays reliable
  • How to design a simple addressed, checksummed protocol, then use Modbus RTU
DifficultyIntermediate
Build timeAbout 45 minutes
BoardsArduino Uno or ESP32 (two or more for the bus)
PartsMAX485 modules, twisted pair, 120 ohm resistors
Two boards, each with a MAX485 module, joined by a twisted pair: the master on the left, a slave node on the right.

Why RS485?

A normal UART sends each bit as a voltage on one wire measured against ground. Over a long cable, noise and ground differences corrupt that voltage quickly, and only two devices can share the link.

RS485 fixes both problems:

  • Differential signalling. Data travels on two wires, A and B. The receiver looks at the difference between them, not the absolute level. Noise that couples equally onto both wires cancels out.
  • Multi-drop. Many devices connect to the same pair. The standard allows 32 unit loads, and modern low-load transceivers allow more.
  • Distance. Cable runs of up to about 1200 m are possible at lower baud rates.
  • Half duplex. With one pair, only one device may talk at a time. Everyone else listens.
PropertyUART (TTL)RS232RS485
SignallingSingle-endedSingle-ended, +/-12 VDifferential
Devices22Up to 32 (more with low-load parts)
Typical max distance1 to 2 mAbout 15 mAbout 1200 m at low speed
Noise immunityPoorFairExcellent
WiresTX, RX, GNDTX, RX, GNDA, B (plus a reference ground)

The figures are standard-spec rules of thumb. Real limits depend on cable quality, baud rate and termination.

The same noise on a single-ended line (corrupted bits) and on a differential A/B pair (the difference is unchanged).

The MAX485 Module

The MAX485 is a half-duplex RS485 transceiver. It has a driver that converts your UART TX into the A/B differential pair, and a receiver that turns A/B back into a logic signal.

PinNameFunction
1ROReceiver output: goes to your board's RX
2RE (active low)Receiver enable: LOW = receiver on
3DEDriver enable: HIGH = driver on
4DIDriver input: comes from your board's TX
5GNDGround
6ANon-inverting line
7BInverting line
8VCC5 V

DE and RE tied together. Because RE is active low and DE is active high, joining them gives one control pin: HIGH = transmit, LOW = receive. Most ready-made modules already bridge the two, and the examples here use one GPIO for both.

Direction control is the heart of every RS485 bug. Raise the pin just before you send, and lower it as soon as the last bit has physically left the UART. Lower it too early and the end of your message is cut off. Lower it too late and you miss the start of the reply.

MAX485 module pinout: RO, RE, DE, DI on the logic side and A, B, VCC, GND on the bus side.

Components

9 items
NameQtyLink
MAX485 TTL to RS485 module×2—
Arduino Uno R3 (master)×1—
Arduino Uno or ESP32 (slave)×1—
Twisted pair cable (CAT5 works well)×1—
120 ohm resistor (bus termination)×2—
LED and 220 ohm resistor (slave output)×1—
Potentiometer or any analog sensor (slave input)×1—
Resistors 1k and 2k for ESP32 level divider×1—
Breadboard and jumper wires×1—

Wiring

Arduino Uno to MAX485

MAX485Uno
VCC5V
GNDGND
ROD10 (SoftwareSerial RX)
DID11 (SoftwareSerial TX)
DE + RE (joined)D3

ESP32 to MAX485

MAX485ESP32
VCCVIN (5 V)
GNDGND
ROGPIO 16 (RX2) through a voltage divider
DIGPIO 17 (TX2)
DE + RE (joined)GPIO 4

Between the nodes

Node 1Node 2
AA
BB
GNDGND (see note below)

The slave in the sketch reads an analog sensor on A0 (Uno) or GPIO 34 (ESP32) and drives an LED on pin 8.

Wiring diagram: Uno and ESP32 nodes with MAX485 modules, A to A and B to B, 120 ohm resistors at both ends.

⚠️ Warning

The MAX485 is a **5 V part**, so its RO output swings to 5 V. That is too much for an ESP32 input (3.3 V max). Put a divider between RO and GPIO 16: RO to 1 k to the GPIO, and from the GPIO to GND with 2 k, which gives about 3.3 V. Or avoid the problem by using a 3.3 V transceiver such as the **MAX3485** or **SP3485**. The ESP32 TX line into DI is fine: a 3.3 V high is still above the MAX485 input threshold.

Termination, Bias and Topology

Three things separate a bus that works on the bench from one that works in the field.

Topology: a line, not a star. Run one continuous cable from device to device (a daisy chain), keeping any branch stubs very short. Star wiring causes reflections that scramble data at higher speeds.

Termination. A signal reaching the end of an unterminated cable reflects back and interferes with itself. Place a 120 ohm resistor across A and B at each of the two physical ends of the bus, and nowhere else. Over a few metres at 9600 baud you can often get away without it, but add it as soon as the cable gets long or the baud rate rises. Many modules have an on-board termination jumper.

Bias (failsafe) resistors. When nobody is driving the bus, A and B float and the receiver can see random noise as data. A pull-up on A and pull-down on B, usually somewhere in the 560 to 1k ohm range and fitted in one place only, holds the idle line in a clean state. Cheap modules often lack them. If you see stray garbage characters while the bus is idle, add bias.

Ground. RS485 is differential, but receivers have a limited common-mode range. Tie the grounds of all nodes together (many designs use a third wire or the cable shield through a small resistor) so the nodes stay within that range.

A and B labelling. Vendors disagree on which terminal is A and which is B. If nothing works and everything else is right, swap the two wires.

Bus topology: a daisy chain with 120 ohm terminators at the two ends, bias resistors at one point, and short stubs only.

Speed Versus Distance

Higher baud rates need shorter cables. These are the commonly quoted RS485 limits for good twisted-pair cable with proper termination:

Baud rateTypical maximum cable length
9,600About 1200 m
115,200A few hundred metres
1 MbpsAbout 100 m
10 MbpsAbout 12 m

Treat the table as an upper bound. A cheap module on thin wire will fall short, which is another reason to start at 9600 baud and only raise it once the bus is stable.

Designing the Protocol

RS485 only moves bytes. It has no concept of "who is this for" or "did it arrive intact". You supply that. The example uses a readable ASCII frame:

$<addr>,<cmd>,<value>*<checksum>\n

  • $ marks the start of a frame, so a receiver can resynchronise after noise.
  • addr says which slave the frame is for (and which slave a reply is from).
  • cmd is GET, SET, or a reply: VAL, ACK, ERR.
  • checksum is the XOR of every character between $ and *, written as two hex digits.
  • \n ends the frame.

The master sends $01,GET,0*xx and slave 1 answers $01,VAL,512*xx. A slave that sees a bad checksum stays silent, and the master treats a missing reply as a timeout. Only the addressed slave ever drives the bus, which is how half duplex stays collision free.

Steps

  1. 1Wire each board to its MAX485 as shown, with the board unpowered.
  2. 2Connect A to A, B to B and GND to GND between the two nodes; add 120 ohm resistors across A and B at both ends.
  3. 3Upload the slave sketch to node 2 (set MY_ADDR = 1) and open its Serial Monitor at 115200.
  4. 4Upload the master sketch to node 1 and open its Serial Monitor at 115200.
  5. 5Turn the potentiometer on the slave and watch the master print the changing value; the slave LED should toggle once per second.

Slave Code

Upload this to every slave and give each a different MY_ADDR. It works on both the Uno and the ESP32. A slave only answers frames addressed to it.

C++

Master Code

The master asks each slave for a value, prints it, then toggles the LED on slave 1. Each request() drains stale bytes, sends a frame, and waits up to 200 ms for the matching reply. A corrupted or missing reply is reported as "no reply" instead of hanging the sketch.

C++
Both Serial Monitors side by side: the master printing slave values and "no reply" for an absent slave 2, and the slave logging activity.

If you only built one slave, the master will print Slave 2: no reply every cycle. That is the timeout path working as designed. Add a second slave with MY_ADDR = 2 and it disappears.

How the Direction Control Works

The three lines around bus.print() in sendFrame() are the most important in the whole project:

  1. digitalWrite(DE_RE_PIN, HIGH) turns the driver on and the receiver off. A 50 microsecond pause lets the driver settle.
  2. bus.flush() blocks until the UART has shifted out the last bit. Without it, the code would flip back to receive mode while bytes were still being sent, truncating the frame.
  3. A 2-bit-time delay, then LOW, adds a little margin and returns the transceiver to listening, ready for the slave's reply.

With SoftwareSerial on the Uno, bytes are sent in software, so flush() behaves differently from hardware serial. The extra delay covers that. On the ESP32 hardware UART it is cheap insurance.

Going Industrial: Modbus RTU

Most commercial RS485 sensors, meters and PLCs speak Modbus RTU. It is a standard on top of the same hardware, so your wiring does not change. Instead of ASCII, frames are binary and protected by a 16-bit CRC:

FieldSizeExample (read 2 registers)
Slave address1 byte01
Function code1 byte03 (read holding registers)
Start register2 bytes00 00
Register count2 bytes00 02
CRC162 bytes (low byte first)C4 0B

So the full request is 01 03 00 00 00 02 C4 0B. A temperature and humidity sensor might answer 01 03 04 00 FA 01 F4 DA 15: four data bytes holding 250 and 500, which the sensor's manual says means 25.0 degrees and 50.0 percent.

You do not need to calculate the CRC by hand. The ModbusMaster library by Doc Walker (install from Library Manager) builds the frame and checks the reply. Its two callbacks switch the DE/RE pin before and after each transmission.

C++

Always take the address, baud rate, parity, register map and scaling from your device's datasheet. They vary widely. A very common mismatch is parity: many devices use 8E1 or 8N2 instead of 8N1, and SoftwareSerial cannot do parity. For those devices use a hardware serial port, for example Serial2.begin(9600, SERIAL_8E1, 16, 17) on the ESP32.

ModbusMaster returns a status code. The ones you will meet most:

CodeMeaningUsual cause
0x00Success
0xE0Invalid slave IDReply came from a different address
0xE1Invalid functionDevice does not support that function code
0xE2Response timeoutWrong wiring, A/B swapped, wrong baud, wrong address, no power
0xE3Invalid CRCNoise, missing termination, parity mismatch

Inspecting the Bus

When something is wrong, look at the signal. A logic analyzer or oscilloscope on A and B shows frames directly. Even a cheap USB-to-RS485 adapter on a PC with a serial terminal lets you see exactly what bytes are on the wire, which separates a wiring problem from a code problem in seconds.

A scope or logic analyzer capture of one frame: the A and B lines mirror each other, and the driver-enable line brackets the transmission.

Troubleshooting

SymptomLikely causeFix
Master always prints "no reply"A and B swapped, no common ground, wrong addressSwap A and B; connect GND; check MY_ADDR.
Garbage charactersBaud mismatch, parity mismatch, no terminationMatch settings on both ends; add 120 ohm terminators.
First bytes of the reply are lostDE/RE released late or master raised it lateKeep the direction switching tight; the master should be listening before the slave replies.
End of the message is cut offDE/RE dropped too earlyCall flush() and keep the short delay before going low.
Works on the bench, fails on the long cableMissing termination or bias, star wiringTerminate both ends, daisy-chain, add bias, lower the baud.
Random errors when a motor runsNoise or ground shiftUse twisted pair, keep it away from motor wiring, and use shielded cable with a single ground point.
ESP32 receives nothingRO into GPIO 16 without divider, wrong pinsFit the divider or a 3.3 V transceiver; confirm RX2/TX2 pins.
ESP32 resets or behaves oddly5 V on a 3.3 V pinCheck every line crossing the 5 V / 3.3 V boundary.
Modbus gives 0xE2Wrong slave ID, baud, parity or wiringVerify against the device manual; try swapping A and B.
Two slaves answer at onceSame addressGive every slave a unique address.

Ideas to Extend

  • More slaves. Add nodes 3, 4 and beyond, each with its own MY_ADDR. Keep the polling timeout in mind: each missing slave costs one timeout per cycle.
  • Isolation. For noisy industrial settings use an isolated RS485 transceiver so ground differences cannot damage your board.
  • Bridge to the cloud. Let an ESP32 master poll the bus and forward readings with the ESP32 MQTT tutorial.
  • Longer reach without wires. If the nodes are too far apart to run cable, look at the LoRa guide instead.
  • Another wired option. For short on-board links compare with I2C vs SPI.

FAQ

Can I use RS485 with just two wires? Yes: A and B are the signal pair. Tie the grounds as well for reliability.

Does RS485 need a master? The electrical standard does not, but practical protocols like Modbus RTU use one master and many slaves to avoid collisions on the shared pair.

What is the difference between RS485 and RS422? RS422 is full duplex with separate transmit and receive pairs; RS485 is usually half duplex on a single pair.

Can I use SoftwareSerial for this? For simple 9600 baud links on the Uno, yes. For higher speeds, parity, or when the board is busy, use a hardware serial port.

Why do I need two 120 ohm resistors, not one? Each end of the line needs a terminator to absorb the signal; with only one end terminated, reflections still occur from the other.

Related on SolderHub

Published on SolderHub

Signal In

Built from what makers search for

The lookups piling up in SolderHub's search bar every day shape what we publish next — new component pages, board guides, and firmware notes, sent out as they go live.

By subscribing you agree to our Privacy Policy. Unsubscribe anytime.