Protocols
UART — Universal Asynchronous Receiver/Transmitter
Point-to-point, full-duplex, and clockless — both ends must independently agree on the bit rate ahead of time, because there's no shared clock line to synchronize with.
- What it is
- A point-to-point serial link with no shared clock — both ends pre-agree on a baud rate and frame each byte with start/stop bits.
- Mental model
- Two people who've agreed in advance how fast to talk, so neither needs a metronome to stay in sync.
- Key numbers
- 2 signal wires (TX, RX) + GND, common bauds 9600–115200, typically 8N1 framing.
- Reach for it when
- You need a simple, universally-supported console/debug link or a basic point-to-point connection between two devices.
Wires
- TX
- Transmit — connects to the other device's RX.
- RX
- Receive — connects to the other device's TX.
- GND
- Common ground reference — required, easy to forget when only two signal wires are wired up.
Optional handshaking lines (RTS/CTS) exist for hardware flow control; most embedded links skip them.
Frame format
Each byte is sent as its own self-contained frame:
- Start bit — line drops from idle-high to low, marking the beginning of a frame.
- Data bits — usually 8, LSB first.
- Parity bit — optional (none/even/odd), for basic error detection.
- Stop bit(s) — 1 or 2, line returns to idle-high.
Commonly written as a shorthand like 8N1 (8 data bits, no
parity, 1 stop bit) — the configuration both ends must agree on, along
with the baud rate.
Baud rate
The receiver has no clock signal to lock onto — it estimates bit timing from the start-bit edge and its own local baud-rate generator. Common rates: 9600, 19200, 38400, 57600, 115200. A receiver whose clock is off by more than roughly ±2–3% from the sender's will start misreading bits, worse the longer the frame runs (which is part of why frames are kept short — one byte at a time).
Flow control
| Type | Mechanism |
|---|---|
| None | Receiver must always be ready; risk of overrun on bursty data. |
| Software (XON/XOFF) | In-band control bytes pause/resume transmission — unsafe for binary data. |
| Hardware (RTS/CTS) | Extra wires signal buffer readiness — reliable, costs 2 more pins. |
Voltage levels: UART vs. RS-232 vs. RS-485
"UART" describes the framing, not the voltage. A microcontroller UART peripheral typically idles at logic-high (3.3 V or 5 V, non-inverted). RS-232 uses the same framing but inverted, higher voltage swings (traditionally ±12 V) — a level-shifter (e.g. MAX3232) is required between the two. RS-485 is differential and supports multi-drop buses over long distances, again the same framing underneath but a different electrical layer.
FIFO buffering and overrun
A UART peripheral without any buffering needs the CPU to read every received byte before the next one finishes arriving — at any meaningful baud rate, that means an interrupt per byte, which adds up fast. Most real UART peripherals include a small hardware FIFO (typically 16 bytes or so) that lets several bytes accumulate before firing an interrupt, cutting interrupt overhead roughly in proportion to the FIFO depth. If the software genuinely can't keep up and the FIFO fills completely, the next incoming byte causes an overrun — it's simply lost, silently, with only an overrun-error flag (if the application checks for it) as evidence anything went wrong.
Break condition and 9-bit multidrop mode
A break is a deliberate, extended low period held longer than a normal frame would ever be — long enough that it can't be confused with any valid start bit plus data plus stop bit sequence. It's used as an out-of-band signal: some bootloaders watch for a break to force entry into a recovery mode, and some multidrop protocols use it to mark "this is a new addressed frame, resynchronize here."
Separately, some UART peripherals support a 9-bit mode (8 data bits plus one extra address/data marker bit) specifically to support simple multidrop buses: a byte with the marker bit set is interpreted as a device address, letting every device on a shared line wake up, check if the address is theirs, and go back to ignoring traffic if it isn't — a lightweight alternative to CAN-style multi-master arbitration for buses that don't need CAN's full feature set. This is the mechanism under protocols like Modbus RTU's addressed multidrop mode.
Real-world applications
- Serial console / debug port — nearly every dev board exposes a UART console for boot logs and a login shell — the very first thing you connect to on new hardware.
- GNSS modules — almost all GPS/GNSS receivers stream NMEA sentences over a plain UART — see GNSS.
- Bluetooth/Wi-Fi modules — many "serial-to-wireless" modules (HC-05, ESP-01 in AT-command mode) are controlled entirely through a UART, hiding the actual radio protocol behind simple text commands.
- Industrial RS-485 links — Modbus RTU and similar factory-floor protocols run UART framing over a differential RS-485 physical layer for long, noisy cable runs.
- Bootloader/firmware update ports — many MCU vendors' in-system programming/recovery modes talk over UART because it needs no special hardware beyond a $2 USB-serial adapter.
Gotchas
- TX↔RX crossed wiring is the most common "nothing works" bug — connect TX to RX, not TX to TX.
- Baud rate mismatch often shows up as consistent garbage, not intermittent failure — that's a strong hint to check baud/parity/stop-bit settings before touching the wiring.
- On Linux, a UART shows up as a
ttydevice (e.g./dev/ttyUSB0,/dev/ttyS0) — configured withtermios, covered in Linux → Drivers.