UART — Universal Asynchronous Receiver-Transmitter
UART is the oldest and simplest serial communication protocol. It is on every microcontroller ever made — it is how your Arduino talks to your PC, how a GPS module sends coordinates, and how a Bluetooth module accepts commands.
The Core Idea — Both Sides Agree on Speed
Most protocols send a clock signal so both sides stay in sync. UART does not. Instead, both sides agree on a speed before they start talking — this speed is called the baud rate. Once agreed, each device uses its own internal clock to time the bits.
This simplicity is why UART has survived 50+ years. The tradeoff: if the two clocks drift apart over time, bits get misread. At normal speeds this is never a problem.
The UART Frame — How One Byte is Sent
UART does not just blast bits onto the wire. Each byte is wrapped in a frame — a precise sequence that tells the receiver exactly where the byte starts and ends.
| Part | Value | Purpose |
|---|---|---|
| Idle | HIGH | Line sits high when nothing is being sent |
| Start bit | LOW | Tells receiver "a byte is about to arrive" |
| Data bits (D0–D7) | 0 or 1 | The actual byte, sent LSB first |
| Stop bit | HIGH | Tells receiver "that byte is done" |
The shorthand 8N1 means: 8 data bits, No parity, 1 stop bit. You will see this everywhere — it is the standard for almost all UART communication.
Here is what the TX line actually looks like on an oscilloscope when sending the letter 'A' (ASCII 65 = binary 01000001):
What Baud Rate Actually Means
Baud = symbols per second. For UART each symbol is one bit, so baud = bits per second.
At 9600 baud, one bit takes about 104 microseconds. A full 10-bit frame (start + 8 data + stop) takes about 1 millisecond. That means you can send roughly 960 bytes per second at 9600 baud.
Common baud rates and when to use them:
| Baud rate | Bytes/second | Typical use |
|---|---|---|
| 9600 | 960 | General debugging, GPS, GSM |
| 19200 | 1,920 | Slightly faster sensors |
| 38400 | 3,840 | Some GPS and radio modules |
| 115200 | 11,520 | Fast debugging, Bluetooth modules |
[!TIP] When connecting two devices and seeing garbage characters in the terminal, baud rate mismatch is almost always the cause. Both sides must be set to exactly the same number.
How a UART Transmission Works — Step by Step
Physical Wires
UART only needs 3 wires. Notice the cross connection — TX of one device goes to RX of the other, never TX to TX:
TX connects to RX — not TX to TX. This is the most common wiring mistake. The transmitter of one device goes to the receiver of the other, and vice versa. Also always connect GND between the two devices — without a shared ground, voltage levels have no reference.
Voltage Levels
Different devices use different voltage levels to represent HIGH and LOW. You must match them or use a level shifter in between.
Never connect a 5V TX directly to a 3.3V RX pin. The 5V signal can damage the 3.3V device. Use a simple voltage divider (two resistors) or a level-shifter module (₹20–₹50).
How UART Configuration Works — In Plain Terms
When you set up UART on a microcontroller, you are answering four questions:
Sending and Receiving — The Logic Flow
Sending a byte:
Want to send a byte?
→ Check: is the transmit buffer empty?
YES → Write your byte in
Hardware takes over — sends start bit, 8 bits, stop bit automatically
NO → Wait and check again
Receiving a byte:
Want to read a byte?
→ Check: has a new byte arrived?
YES → Read it from the data register
NO → Wait and check again
The hardware does all the actual bit-banging — setting and clearing the TX line at precisely the right moments. You just write to a register and let the hardware do the work.
UART vs Other Protocols
| UART | SPI | I²C | |
|---|---|---|---|
| Wires | 3 (TX, RX, GND) | 4 + 1 per slave | 2 + GND |
| Devices | 1-to-1 only | 1 master, many slaves | Up to 127 on same bus |
| Clock | None (async) | Shared clock | Shared clock |
| Speed | Up to ~1 Mbps | Up to 20+ Mbps | 100 kHz – 1 MHz |
| Best for | Debug console, GPS, GSM | SD cards, displays | Sensors, RTC, EEPROM |
Common Mistakes
- Wrong baud rate — see garbage instead of readable text in terminal
- TX to TX wiring — nothing arrives because you connected transmitter to transmitter
- Missing GND connection — voltage levels have no reference, everything is unreliable
- 5V into 3.3V pin — works sometimes, damages the pin over time
- Not waiting before sending — if you write a new byte before the previous one finished sending, the old byte gets cut off