UART basics: TX, RX, and no clock line
UART (Universal Asynchronous Receiver/Transmitter) is the oldest and simplest of the three protocols — and still everywhere. It's the natural place to start, because once you understand UART's asynchronous nature, SPI and I²C make sense as solutions to UART's limits.
Just two data lines, crossed
A UART link uses two data wires plus a shared ground:
- TX — transmit. The device sends data out of this pin.
- RX — receive. The device reads incoming data on this pin.
The crucial wiring rule: TX connects to the other device's RX, and RX to the other's TX. They cross over.
Device A Device B
TX ───────────► RX
RX ◄─────────── TX
GND ───────────── GND (common ground, always)
Wiring TX-to-TX (straight across, the intuitive-but-wrong way) is the single most common UART mistake — two transmitters shouting at each other, two receivers hearing nothing. Cross them, and share a ground, and the link is physically complete.
No clock — each side keeps its own time
Notice what's missing: there is no clock wire. UART is asynchronous. Neither device tells the other "read now." Instead, each runs its own internal clock at a pre-agreed speed, and they rely on that shared speed to stay in step. (How they agree on the speed — the baud rate — is the next slide.)
Bytes are framed with start and stop bits
Because there's no clock, the receiver needs to know when a byte begins. UART solves this by framing each byte:
- The line idles HIGH when nothing is sent.
- A start bit (a drop to LOW) announces "a byte is coming — begin sampling."
- The 8 data bits follow, one per bit-time.
- A stop bit (back to HIGH) marks the end.
So each 8-bit byte actually travels as ~10 bits on the wire (start + 8 + stop). The start bit is the trigger that re-synchronises the receiver's timer for every single byte — clever, and the reason UART tolerates having no shared clock.
Bidirectional and simple
Because TX and RX are separate wires, UART is full-duplex — both devices can send at the same time. And it's beautifully simple: two crossed wires, a ground, and an agreed speed. That simplicity is exactly why UART endures despite being the slowest and most limited of the three.
The next slide covers the one thing both sides must agree on for any of this to work: the baud rate.
In a UART link, device A's TX pin connects to device B's:
Baud rate: the shared timing agreement
UART has no clock wire, so the one thing both devices absolutely must share is the bit speed — the baud rate. Get it right and UART just works. Get it wrong and you get gibberish. This single number causes more real-world serial bugs than anything else.
What baud rate means
Baud rate is how many bits per second travel down the line — i.e., how long each bit lasts. Common values you'll see: 9600, 19200, 57600, 115200. At 9600 baud, each bit lasts about 0.1 millisecond; at 115200, about ten times shorter.
Because there's no clock telling the receiver when to read, the receiver instead counts time using its own clock: "the start bit dropped — now wait one bit-time, sample; wait another bit-time, sample…" That counting only lands on the right moments if the receiver's idea of "one bit-time" matches the sender's. Baud rate is that shared idea of bit-time.
Why a mismatch garbles everything
Suppose the sender transmits at 115200 but the receiver is set to 9600. The receiver waits far too long between samples, reads the line at the wrong instants, and reconstructs completely wrong bytes. There's no error message — just garbage characters, or nothing intelligible.
This is the classic symptom: "I connected my serial device and I'm getting random junk." Almost always, the fix is make the baud rates match. It's the first thing to check, every time.
Both ends, set deliberately
Because the speed is a mutual agreement, you configure it on both devices:
- On the microcontroller, in code (e.g.,
Serial.begin(115200)on an Arduino-style board). - On the other device (a GPS module, a serial sensor, a PC terminal), to the same number.
There's no negotiation and no auto-detection in plain UART — whatever you set is what you get. The two must be identical.
The other settings (briefly)
Baud rate is the big one, but a UART link technically also agrees on a few smaller parameters — data bits (almost always 8), parity (usually none), and stop bits (usually 1). You'll often see this written as "8N1" (8 data bits, No parity, 1 stop bit), which is the near-universal default. In practice, set 8N1 and match the baud rate, and you're done — but knowing what 8N1 means saves confusion when a datasheet specifies something different.
The takeaway
UART's freedom from a clock wire is paid for by this one discipline: both sides must agree on baud (and the 8N1 settings) in advance. That's the whole asynchronous bargain. The next slide looks at where UART genuinely shines — and where its limits push you toward SPI or I²C.
If two UART devices are set to different baud rates, the result is:
Where UART shows up (and its limits)
UART is simple and everywhere — but simplicity comes with hard limits. Knowing where UART fits, and where it runs out of room, is what makes the case for SPI and I²C in the next two lessons.
Where UART shines
UART is the right tool for a whole class of jobs:
- Module-to-module links. Many ready-made modules speak UART: GPS receivers, some GSM/cellular modems, Bluetooth-to-serial bridges, certain barcode scanners. You wire TX/RX, set the baud, and read lines of data.
- Debugging and logging. The classic "serial monitor" — your microcontroller printing status messages to a PC — is UART (often over a USB-to-serial chip). It's the developer's window into a running board.
- Simple two-device communication where you control both ends and only need a modest data rate.
For these, UART's two-wire simplicity is a virtue, not a weakness.
Where UART runs out of room
UART's limits are real and they're the reason other protocols exist:
1. It's point-to-point — only two devices. UART has no addressing and no select line. One TX talks to one RX. If you have five sensors to read, plain UART can't bus them onto one link — you'd need five separate UART ports, and most microcontrollers have only one or two. This is UART's biggest constraint.
2. The baud-rate fragility. Both ends must be set identically, with no negotiation. Mismatches garble silently (last slide). It's manageable but unforgiving.
3. Moderate speed. UART is fine for sensor readings and text, but it's the slowest of the three. For streaming lots of data fast (a graphical display, bulk memory), it's outclassed by SPI.
The limit that drives the rest of L5
The decisive limitation is "only two devices." A real build — say an ESP32 monitoring a solar system — might need a temperature sensor, a current sensor, a display, and a real-time clock all at once. UART simply can't bus them. That single problem is what SPI and I²C were designed to solve, each in its own way:
- SPI (next lesson) keeps things fast and adds a select line per device so the controller can pick among many.
- I²C (Lesson 4) gives each device an address so many share just two wires.
So UART isn't obsolete — it's the simple baseline. When a job outgrows "two devices, modest speed," you reach for SPI or I²C. Understanding why you'd reach is the real lesson.
Next: SPI, the fast synchronous protocol that trades extra pins for speed and multi-device support.