With reference to the Arduino Uno, Mega2560, Leonardo and similar boards:

  • How does serial communications work?
  • How fast is serial?
  • How do I connect between a sender and receiver?

Please note: This is intended as a reference question.

  • You might find this interesting about buffers on both sides of a Nano connected to a Raspian system running a Python data logger, using just a regular USB programming cable between the two: arduino.stackexchange.com/questions/11710/…
    – SDsolar
    Aug 24, 2017 at 23:28

1 Answer 1


Asynchronous serial (usually referred to as serial) communications is used to send bytes from one device to another. A device could be one or more of the following:

  • Arduino
  • PC
  • GPS
  • RFID card reader
  • LCD display
  • Modem
  • Other

Clock rate and sampling of data

Unlike SPI / USB / I2C serial communications does not have a clock signal. The sampling clock is an agreed-upon sample rate (known as the baud rate). Both sender and receiver must be configured to be using the same rate or the receiver will receive meaningless data (due to the bits not being sampled at the same rate that they were sent).

The transmission is asynchronous which basically means that bytes can be sent at any time, with varying gaps between them. This graphic illustrates a single byte being sent:

Serial comms - sending one byte

The graphic above shows the letter 'F' being transmitted. In ASCII this is 0x46 (in hex) or 0b01000110 (in binary). The least significant (low-order) bit is transmitted first, thus in the above graphic you see the bits arriving in the order: 01100010.

The "idle" time between bytes is transmitted as continuous "1" bits (effectively, the transmit line is held high continuously).

To indicate the start of a byte, the Start Bit is always indicated by pulling the line low as shown on the graphic. Once the receiver sees the start bit, it waits for 1.5 times the sample time, and then samples the data bits. It waits 1.5 times so that it:

  • Skips the start bit
  • Samples half-way through the next bit

If the baud rate is 9600 baud, for example, then the sample rate will be 1/9600 = 0.00010416 seconds (104.16 µs).

Thus, at 9600 baud, after receiving a start bit the receiver waits for 156.25 µs, and then samples every 104.16 µs.

Start bit timing

The purpose of the Stop Bit is to ensure that there definitely is a 1-bit between each byte. Without the stop bit, if a byte ended in a zero, then it would be impossible for the hardware to tell the difference between that and the start bit of the next byte.

To produce the above output on an Uno you could write this code:

void setup()

void loop ()

Number of data bits

In order to save transmission time (in the olden days, heh) you were allowed to specify different numbers of data bits. The AtMega hardware supports data bits numbering from 5 to 9. Clearly the less data bits the less information you can send, but the faster it will be.

Parity bits

You can optionally have a parity bit. This is calculated, if required, by counting the number of 1's in the character, and then making sure that this number is odd or even by setting the parity bit to 0 or 1 as required.

For example, for the letter "F" (or 0x46 or 0b01000110) you can see that there are 3 ones there (in 01000110). Thus we already have odd parity. So, the parity bit would be as follows:

  • No parity: omitted
  • Even parity: a 1 (3 + 1 is even)
  • Odd parity: a 0 (3 + 0 is odd)

The parity bit, if present, appears after the last data bit but before the stop bit.

If the receiver does not get the correct parity bit, that is called a "parity error". It indicates that there is some problem. Possibly the sender and receiver are configured to use different baud (bit) rates, or there was noise on the line which turned a zero to a one or vice-versa.

Some early systems also used "mark" parity (where the parity bit was always 1 regardless of the data), or "space" parity (where the parity bit was always 0 regardless of the data).

9-bit transmission

Some communication equipment uses 9-bit data, so in these cases the parity bit is turned into the 9th bit. There are special techniques for sending this 9th bit (the registers are 8-bit registers so the 9th bit has to be put somewhere else).

Number of stop bits

Early equipment tended to be somewhat slower electronically, so to give the receiver time to process the incoming byte, it was sometimes specified that the sender would send two stop bits. This basically adds more time where the data line is held high (one more bit time) before the next start bit can appear. This extra bit time gives the receiver time to process the last incoming byte.

If the receiver does not get a logical 1 when the stop bit is supposed to be, that is called a "framing error". It indicates that there is some problem. Quite possibly the sender and receiver are configured to use different baud (bit) rates.


Commonly, serial communication is indicated by telling you the speed, number of data bits, type of parity, and number of stop bits, like this:


This is telling us:

  • 9600 bits per second
  • 8 data bits
  • No parity (you might see instead: E=even, O=odd)
  • 1 stop bit

It is important that the sender and receiver agree on the above, otherwise communication is unlikely to be successful.


The Arduino Uno has digital pins 0 and 1 available for hardware serial:

Arduino Uno serial pins

To connect two Arduinos you swap Tx and Rx like this:

Connecting two Arduinos together


A wide range of speeds is supported (see graphic below). "Standard" speeds are usually a multiple of 300 baud (eg. 300/600/1200/2400 etc.).

Other "non-standard" speeds can be handled by setting the appropriate registers. The HardwareSerial class does this for you. eg.

Serial.begin (115200);  // set speed to 115200 baud

As a rule-of-thumb, assuming you are using 8-bit data, then you can estimate the number of bytes you can transmit per second by dividing the baud rate by 10 (because of the start bit and stop bit).

Thus, at 9600 baud you can transmit 960 bytes (9600 / 10 = 960) per second.

Baud rate errors

The baud rate on the Atmega is generated by dividing down the system clock, and then counting up to a pre-set number. This table from the datasheet shows the register values, and error percentages, for a 16 MHz clock (such as the one on the Arduino Uno).

Baud rate errors

The U2Xn bit affects the clock rate divisor (0 = divide by 16, 1 = divide by 8). The UBRRn register contains the number the processor counts up to.

So from the table above, we see that we get 9600 baud from a 16 MHz clock as follows:

16000000 / 16 / 104 = 9615

We divide by 104 and not 103 because the counter is zero-relative. Thus the error here is 15 / 9600 = 0.0016 which is close to what the table above says (0.02%).

You will notice that some baud rates have a higher error amount than others.

According to the datasheet the maximum error percentage for 8 data bits is in the range of 1.5% to 2.0% (see the datasheet for more details).

Arduino Leonardo

The Arduino Leonardo and Micro have a different approach to serial communications, as they connect directly via USB to the host computer, not via the serial port.

Because of this, you must wait for Serial to become "ready" (as the software establishes an USB connection), with an extra couple of lines, like this:

void setup()
      while (!Serial)
      {}  // wait for Serial comms to become ready

void loop ()

However, if you want to actually communicate via pins D0 and D1, (rather than by the USB cable) then you need to use Serial1 rather than Serial. You do so like this:

void setup()

void loop ()

Voltage levels

Note that the Arduino uses TTL levels for serial communications. This means that it expects:

  • A "zero" bit is 0V
  • A "one" bit is +5V

Older serial equipment designed to plug into a PC's serial port probably uses RS232 voltage levels, namely:

  • A "zero" bit is +3 to +15 volts
  • A "one" bit is −3 to −15 volts

Not only is this "inverted" with respect to TTL levels (a "one" is more negative than a "zero"), the Arduino cannot handle negative voltages on its input pins (nor positive ones greater than 5V).

Thus you need an interface circuit for communicating with such devices. For input (to the Arduino) only, a simple transistor, diode, and a couple of resistors will do it:

Inverting buffer

For two-way communication you need to be able to generate negative voltages, so a more complex circuit is required. For example the MAX232 chip will do that, in conjunction with four 1 µF capacitors to act as charge-pump circuits.

Software Serial

There is a library called SoftwareSerial that lets you do serial communications (up to a point) in software rather than hardware. This has the advantage that you can use different pin configurations for serial communications. The disadvantage is that doing serial in software is more processor-intensive and more prone to error. See Software Serial for more details.


The Arduino "Mega" has 3 additional hardware serial ports. They are marked on the board as Tx1/Rx1, Tx2/Rx2, Tx3/Rx3. They should be used in preference to SoftwareSerial if possible. To open those other ports you use the names Serial1, Serial2, Serial3, like this:

Serial1.begin (115200);  // start hardware serial port Tx1/Rx1
Serial2.begin (115200);  // start hardware serial port Tx2/Rx2
Serial3.begin (115200);  // start hardware serial port Tx3/Rx3


Both sending and receiving, using the HardwareSerial library, use interrupts.


When you do a Serial.print, the data you are trying to print is placed in an internal "transmit" buffer. If you have 1024 bytes or more of RAM (such as on the Uno) you get a 64-byte buffer, otherwise you get a 16-byte buffer. If the buffer has room, then the Serial.print returns immediately, thus not delaying your code. If there is no room, then it "blocks" waiting for the buffer to be emptied enough for there to be room.

Then, as each byte is transmitted by the hardware an interrupt is called (the "USART, Data Register Empty" interrupt) and the interrupt routine sends the next byte from the buffer out of the serial port.


As incoming data is received an interrupt routine is called (the "USART Rx Complete" interrupt) and the incoming byte is placed into a "receive" buffer (the same size as the transmit buffer mentioned above).

When you call Serial.available you find out how many bytes are available in that "receive" buffer. When you call Serial.read a byte is removed from the receive buffer and returned to your code.

On Arduinos with 1000 bytes or more of RAM, there is no rush to remove data from the receive buffer, provided you don't let it fill up. If it fills up then any further incoming data is discarded.

Note that because of the size of this buffer there is no point in waiting for a very large number of bytes to arrive, for example:

while (Serial.available () < 200)
  { }  // wait for 200 bytes to arrive

This will never work because the buffer cannot hold that much.


  • Before reading, always make sure data is available. For example, this is wrong:

    if (Serial.available ())
          char a = Serial.read ();
          char b = Serial.read ();  // may not be available

    The Serial.available test only ensures you have one byte available, however the code tries to read two. It may work, if there are two bytes in the buffer, if not you will get -1 returned which will look like 'ÿ' if printed.

  • Be aware of how long it takes to send data. As mentioned above, at 9600 baud you an only transmit 960 bytes per second, so trying to send 1000 readings from an analog port, at 9600 baud, won't be very successful.


  • In the 1st graphic: with the arrows it looks like the stop bit is transmitted first. If you exchanged Rx/Tx and the direction of the arrows I'd think it's less confusing.
    – ott--
    Jan 20, 2016 at 7:04
  • It was intended to be read from left to right (as is this sentence) and thus the things on the left happen first. Put it like this: on an oscilloscope, that is how you would see the trace.
    – Nick Gammon
    Jan 20, 2016 at 8:19
  • Ok with the oscilloscope explanaion I buy that. :-)
    – ott--
    Jan 20, 2016 at 11:44
  • However I've been thinking that your point makes a lot of sense. What do others think? Would it be clearer if the arrows were reversed, and I exchanged Rx/Tx?
    – Nick Gammon
    Jan 20, 2016 at 19:40
  • 1
    @linhartr22 I amended it to read "meaningless data" which is probably closer.
    – Nick Gammon
    May 7, 2016 at 22:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.