UART and Serial Links

Draft. This tutorial has not been checked against the physical product yet. Confirm wiring, pin assignments and voltage limits against the product documentation before building it.
DifficultyIntermediate
CategoryConcepts
Supported boardsArduino Uno R3 and compatible ATmega328P boards
Time needed45 minutes
PrerequisitesSPI, Faster and More Wires
Tested boardNot yet verified
Tested onNot yet verified
Arduino IDE versionNot yet verified
LibraryNot yet verified

What this covers

The third bus, and the oldest. I2C and SPI were designed for chips on one board; a UART link is two wires between two independent devices, each with its own idea of the time.

It is how the Bluetooth module, the GPS receiver and the SMS module all talk to an Arduino, and it is the same mechanism as the serial monitor you have been using since your first sketch. Those two facts collide on an Uno in a way that catches everybody once.

Before you begin

Nothing to buy. Seeing What Your Program Is Doing and SPI, Faster and More Wires are the pages either side of this one.

How it works

Two wires, crossed:

Wire Means Goes to
TX Transmit The other device’s RX
RX Receive The other device’s TX

That crossing is the thing to remember. I2C’s SDA goes to SDA; SPI’s MOSI goes to MOSI; UART’s TX goes to RX. Wiring TX to TX connects two outputs together and nothing is ever received.

There is no clock wire. That is the whole design and the source of everything else on this page.

A UART link with transmit crossing to receive in both directions and no clock wire, and the Uno's single hardware port on pins 0 and 1 already carrying the USB serial monitor
TX goes to RX. There is no clock, so both ends must already agree on the speed.

No clock means both ends must agree in advance

With no clock to follow, the receiver has to know how fast bits will arrive before any arrive. It starts its own timer when the line first drops, and samples at intervals it decides.

So both ends must be set to the same baud rate — bits per second. 9600 means a bit every 104 microseconds, and the receiver counts in those.

Get it wrong and you do not get an error. You get plausible-looking rubbish, because the receiver is faithfully sampling a signal at the wrong moments. Characters like ÿ and ? and random punctuation are the signature, and if you see them the first thing to check is the number in Serial.begin() against the number in the monitor’s corner.

Common rates, and what they are for

Rate Where it turns up
9600 The library’s default, and most modules out of the box
38400 HC-05 modules in command mode
57600 Some GPS receivers
115200 ESP32 and ESP8266 boot messages, fast logging

Faster is not better here. At 115200 on a long wire, or through a breadboard with poor contacts, errors appear that 9600 would not have produced. Use the rate the module wants, and raise it only when you need the throughput.

The Uno has exactly one UART, and the USB cable is using it

This is the paragraph the page exists for.

D0 and D1 are the ATmega328P’s hardware serial pins. They are also wired to the USB chip that carries the serial monitor. One UART, two jobs.

The consequences are immediate and confusing if you have not been told:

  • Anything plugged into D0 and D1 fights the USB connection. Both talk at once and both are corrupted.
  • Uploading a sketch fails while a module is connected to those pins, because the upload is itself a serial conversation. The error mentions avrdude and stk500 and says nothing about your wiring.
  • The serial monitor shows the module’s output mixed with your own prints, which looks like a software fault and is not.

So: do not put a module on D0 and D1 on an Uno. Use the pins for the USB cable, and give the module a software serial port instead.

A Mega has four hardware UARTs and an ESP32 has three, which is one of the real reasons to move a project to a bigger board. Uno, Nano, Mega, Pro Mini or ESP32 covers that choice.

SoftwareSerial, and what it costs

SoftwareSerial makes any two digital pins behave like a serial port, by bit-banging the timing in software.

// Siratek: a module on pins 10 and 11, with the USB serial left alone.

#include <SoftwareSerial.h>

// SoftwareSerial(RX, TX) - named from the ARDUINO's point of view.
// So the Arduino's RX pin goes to the module's TX pin.
SoftwareSerial module(10, 11);

void setup() {
  Serial.begin(9600);          // the USB cable, to your screen
  module.begin(9600);          // the module, on pins 10 and 11

  Serial.println(F("Siratek: anything the module says appears below."));
}

void loop() {
  // Module to screen.
  while (module.available()) {
    Serial.write(module.read());
  }

  // Screen to module, so you can type commands at it.
  while (Serial.available()) {
    module.write(Serial.read());
  }
}

That sketch is a serial bridge, and it is the single most useful twenty lines in this part of the library. It lets you talk to an HC-05, a SIM800L or a GPS receiver by typing at it, before you write any logic at all. Every one of those tutorials starts by running something like it.

Note the argument order once, because it is the other half of the crossing: SoftwareSerial(RX, TX) is named from the Arduino’s side, so pin 10 is the Arduino’s receive pin and must be wired to the module’s transmit pin.

The three limits

It is not reliable much above 38400. The bit timing is done by counting instructions, and at high rates there is not enough time between bits to be sure of anything. 9600 is solid, 38400 is usually fine, 115200 is not.

Only one software port can listen at a time. You may create several, but only the one you last called .listen() on receives. Two GPS receivers on two software ports will not both work.

It blocks interrupts while sending or receiving. A byte at 9600 baud takes about a millisecond, and during it millis() is not counting and your interrupts are not firing. In a sketch doing careful timing, that matters — Responding Immediately with Interrupts is where this collides with servos and tone().

If any of those bite, the answer is a board with more hardware UARTs rather than a cleverer library.

3.3 volts, again

A UART’s idle state is the line held high, at whatever that device calls high. An Uno’s high is 5 V; an ESP32’s, a GPS module’s and most SIM modules’ is 3.3 V.

The direction that matters is Arduino TX to module RX: 5 V going into a 3.3 V input. The other direction is usually fine, because 3.3 V is high enough for the Uno to read as HIGH.

So the common fix is one divider or one converter channel, on one wire. Mixing 3.3 V and 5 V Safely has the detail, and the module pages say which of them need it.

Check yourself

Your module is on D0 and D1 and the upload fails. Why? The upload is a serial conversation on those same pins.

You see ÿ?ÿ in the monitor. The baud rates do not match.

SoftwareSerial module(10, 11) — which pin goes to the module’s TX? Pin 10, the Arduino’s receive pin.

Troubleshooting

Symptom Likely cause Check or fix
Nothing received at all TX to TX The two wires cross
Rubbish characters Baud rates differ Both ends, same number
Upload fails, avrdude error A module on D0/D1 Unplug it to upload, then move it
Monitor shows two sets of output mixed Module on the USB UART Use SoftwareSerial on other pins
Works at 9600, fails at 115200 SoftwareSerial’s limit Stay at or below 38400
Two software ports, only one works Only the listening one receives .listen(), or a bigger board
Servo jitters while data arrives SoftwareSerial blocks interrupts Hardware UART, or separate the timing
Module ignores commands Missing line ending Many want carriage return and newline
Module responds once, then stops Buffer overrun, 64 bytes Read it more often than it fills
3.3 V module behaving oddly 5 V on its RX A converter on that one wire

Next steps

  • Easier first: Seeing What Your Program Is Doing, which is this bus without the wiring.
  • Related: Mixing 3.3 V and 5 V Safely, which nearly every UART module needs.
  • Use it: Bluetooth Serial with an HC-05, Reading Position with a NEO-6M and Sending SMS Alerts with a SIM800L are three modules, one bus and three sets of commands.

Sources and attribution

All text and code in this tutorial are original Siratek work.

  • The single hardware UART on the ATmega328P, its sharing with the USB interface on D0 and D1, the 64-byte receive buffer and the bit timing are properties of the chip and the Arduino core described in their documentation.
  • The SoftwareSerial limits — one listening port, interrupt blocking, and unreliability at high rates — are documented behaviour of that library.

Baud rates for particular modules are the usual defaults rather than measurements, and each module tutorial gives the figure for its own part. No third-party tutorial text, diagrams, photographs or code has been reproduced here.

Shop
Sidebar
0 Wishlist
0 Cart