# How to Read Data From a Serial Port

> What a serial port actually is, how baud rate and 8N1 framing work, where the port shows up on Windows, macOS and Linux, and how to read the data.
>
> Fundamentals · May 21, 2026 · by Alex Spataru · https://serial-studio.com/blog/how-to-read-a-serial-port

If you have wired up an Arduino, an ESP32, a GPS module, or almost any microcontroller, you have used a serial port, probably without thinking much about what it is. It is worth understanding, because a few minutes on the basics will save you hours of chasing "garbage on the screen" later.

## What a serial port really is

"Serial port" usually means a UART: a Universal Asynchronous Receiver-Transmitter. It is the small piece of hardware that turns a byte into a sequence of bits on a single wire, and turns bits back into bytes at the other end. A UART is a peripheral, not a protocol. The protocol it speaks is plain asynchronous serial, which is what a datasheet means when it says a chip "speaks serial at 115200 8N1".

The word *asynchronous* is the important one. There is no shared clock line between the two ends. Instead, both sides agree in advance on how fast the bits arrive, and the receiver re-synchronizes at the start of every byte.

## The frame, and 8N1

Every byte travels inside a small fixed-shape frame:

- The line sits **idle** (logic high) when nothing is being sent.
- A single **start bit** pulls it low. That falling edge is the receiver's cue to start sampling.
- The **data bits** follow, least-significant bit first. Eight bits is by far the most common width.
- An optional **parity bit** can catch single-bit errors.
- One or more **stop bits** return the line high before the next byte.

The usual configuration is written `8N1`: 8 data bits, No parity, 1 stop bit. With the start and stop bits, that is ten line-bits per byte, so the raw efficiency is 80 percent. Most modern devices leave parity off, because USB and short cables rarely flip bits and any error checking that matters lives in the application layer.

## Baud rate: the one setting people get wrong

Baud rate is how many bits per second travel on the line. At 9600 baud each bit lasts about 104 microseconds; at 115200 it lasts about 8.7. Common rates are 9600, 19200, 38400, 57600, 115200, 230400 and up.

Both ends must use the same rate. UARTs tolerate a small clock mismatch (the error accumulated across one byte has to stay under half a bit, which works out to a few percent), but if the configured rates actually differ, you get nonsense or nothing at all. A useful tell: a wrong rate produces *consistent* garbage, the same wrong bytes every time you send the same data, rather than a mix of correct and random characters. If instead most of the text is right with the odd mangled character, suspect noise or wiring before you touch the baud rate.

## Where the port appears

The same physical adapter shows up under a different name on each operating system:

- **Windows:** a `COM` port, such as `COM3`.
- **Linux:** a device file, usually `/dev/ttyUSB0` (for a USB-to-serial chip) or `/dev/ttyACM0` (for a board with native USB).
- **macOS:** `/dev/cu.usbserial-XXXX` for adapters based on FTDI or CP210x chips, or `/dev/cu.usbmodemXXXX` for boards with native USB.

Whatever the name, opening it gives you a stream of bytes. Nothing more. A serial port has no idea whether those bytes are text, numbers, or a binary packet. That meaning is up to you.

## What the bytes usually are

For debugging, most firmware prints human-readable lines of numbers. A sketch that streams a filtered sensor reading might do nothing more than this:

```cpp
void loop() {
  int value = analogRead(A0);
  Serial.println(value);   // one number per line, at 115200 baud
  delay(10);
}
```

That is exactly what the Serial Studio [pulse-sensor example](https://serial-studio.com/examples#PulseSensor) does with a heart-rate sensor on pin A0. If you send several values, separate them with commas on one line:

```cpp
Serial.print(temperature);
Serial.print(",");
Serial.println(humidity);
```

## Actually seeing it

To read the port you need a program that opens it at the right baud rate and shows you what arrives. The Arduino IDE has a Serial Monitor for text and a Serial Plotter for a basic graph. They work, but they are minimal.

Serial Studio reads the same stream and does two useful things with it. Its console shows the raw text (or hex, if the data is binary), and its **Quick Plot** mode splits each incoming line on commas and draws every value as a live trace, with no configuration. You pick the port, set the baud rate to match your firmware, and choose *Quick Plot (Comma Separated Values)* under Frame Parsing. It also records the session to a CSV file you can open later.

## Two things that trip people up

- **The board resets when you connect.** On an Uno or Nano, opening the port toggles the DTR line, which the bootloader reads as "reset". That is normal. If you need to prevent it, disable the DTR signal in the port settings.
- **The port opens but nothing arrives.** Usually the transmit and receive lines are swapped, or the baud rate is wrong. Check the rate first, since it is the quicker fix.

Once you can see a clean column of numbers, you understand the serial port. Turning those numbers into gauges and plots is what comes next.

## Frequently asked questions

### What baud rate should I use?

Whatever your firmware sets; the two just have to match. For new code, 115200 is a sensible default: fast enough for most debugging, slow enough for any adapter. One useful exception: boards with *native* USB (a Leonardo, a Teensy, most modern dev boards) only emulate a serial port, so the configured baud rate is ignored and data moves at USB speed regardless of the number you pick.

### Why does my serial port say "busy" or "access denied"?

Something else already has it open. Serial ports are exclusive, so a forgotten serial monitor, a stray `screen` session, or the Arduino IDE's own console will lock everyone else out. Close the other program. On Linux there is a second cause: your user needs permission for the device, which on most distributions means adding yourself to the `dialout` group and logging in again.

### Can two programs read the same port at once?

Not directly; the first one to open the port owns it. If you genuinely need two readers, one program has to own the hardware and re-publish the data, for example over a local TCP or UDP socket that the second program connects to.

### I opened the port and see garbage. Which setting is wrong?

Check the baud rate first, then the data format (nearly everything is 8N1, but not everything). The pattern of the garbage is diagnostic: the same wrong characters every time points to a rate mismatch, while mostly-correct text with occasional corruption points to wiring, noise, or a voltage-level mismatch between a 5 V and a 3.3 V device.
