Serial UART And How It Works

If you have read through the Arduino Serial guides you should now have a good grasp on using serial communication but did you ever stop to ask yourself what actually is serial UART? If you did you are in the right place.

UART stands for Universal Asynchronous Receiver-Transmitter

  • Universal – ever one in the universe can use it. No, not really. It simple means there are many formats or options within the protocol. The data being transmitted can be configured in different ways and many different speeds (baud rates) can be used.
  • Asynchronous – it operates on its own independent of other things and does not require the two ends to talk to each other. One end sends, if there is something on the other end listening then great, if not, the sender don’t care and doesn’t expect a reply.
  • Receiver – you can receive data with it!
  • Transmitter – you can send data with it!

which probably doesn’t help explain what it is.

So what is UART?

UART is a serial communications protocol. The protocol defines how the data is prepared and then how it is transmitted. Serial simply means the data is transmitted serially, one piece at a time.

Serial UART is point to point, does not require any real set up and does not have an addressing (it’s point to point – no need to route traffic).

There are ways to use UART to connect multiple devices but UART is not designed to connect more than two devices doing so is, at best a botch, at worst a hack. For multiple device communication there are much better solutions.

The UART protocol has many different options and speeds and has survived and thrived, in part, because of how flexible and simple it is. It is extremely popular in the embeded and Arduino worlds.

Communication is done over two wires, one for transmit -> receive and a second for receive <- transmit. That’s it. No extra wires for clock signals or handshaking*. You usually need to join the grounds together but we won’t count that.

Arduino Nano connected to Another Arduino Nano by hardware serial
Arduino Nano connected by hardware serial to a usb-serial UART adapter

One man’s RECEIVE (RX) is another man’s TRANSMIT (TX).
Remember, RX on one side goes to TX on the other side.

*handshaking
UART can support a form of hardware handshaking called Flow Control. Flow Control utilises RTS and CTS, Ready To Send and Clear To Receive signals. Each signal requires its own connection/pin and they can be considered as optional extras that are not implemented that often, certainly not in Arduino land..
The Arduino uses the RTS signal as a way to reset the module so it is not normally available to use.

What UART Isn’t

UART is not a standard and there isn’t an ISO specification, or indeed any kind of spec for it. It just is. UART is not RS-232 (nor is it RS-484). RS-232 (and also RS-485) define the hardware and what represents a 0 or a 1. UART does none of this.

  • UART. Logical 0, the pin is pulled to GND. Logical 1 is HIGH, normally the same voltage the MCU uses, typically 3.3v or 5v
  • RS-232. A 0 is defined as +3v to + 15v. A 1 a voltage between -3V and -15V.
  • RS-485 uses two lines, A and B. 0 is defined as A high and B low. A 1 is when A is low and is B high.

UART transmission Modes

UART transmits data serially, in one of three modes:

  • Full duplex. Simultaneous communication to and from each device
  • Half duplex. Transmission is in one direction at a time
  • Simplex. One-way communication only

There isn’t really a default mode and the actual method used is down to the device being used. For example, Hardware serial on the Arduino is full duplex, it can send and receive at the same time. The built in software serial library is half duplex (cannot send and receive at the same time). AltSoftSerial is full duplex but has fixed pins for TX and RX.

UART Packet Format

UART packages the data in little packets. Each packet has the following format:

  • a start bit
  • data bits, the actual data or value
  • a parity bit (optional)
  • an end bit (or 2)
A serial UART data packet

Start Bit

The start of the data packet always has a single start bit. Start bits are always 0s so you could say the packet always starts with a nothing :-) Start bits inform the receiving device that data has started to arrive.

Data Bits

Data bits is/are where the data is at. UART allows for different number of bits to be used; anything from 5 bits to 9 bits. However, 8 data bits is very common and fits nicely with how data is stored in microprocessors. 8 bits is a byte and 1 byte normally means one character.

Parity

The parity bit can be used as a very basic checksum. The parity bit is optional and using a parity bit was far more popular in the past than it is now. For the most part the parity bit is not used any more. The Arduino is a good example of this. The default Arduino UART (8N1) does not include the parity bit.

Parity bit options are:

  • No parity bit
  • Even parity – the parity bit (either a 1 or a 0) is added to make the total number of bits in the data/value add up to an even number. If the total number of bits in the data is already even then a 0 is added to keep the number bits as even. If the number of bits is odd then the parity bit is set to a 1 to make the total number of bits even.
  • Odd parity – the parity bit (either a 1 or a 0) is added to make the total number of bits in the data.value add up to an odd number. If the total number of bits in the data is already odd then a 0 is added to keep the number bits as odd.

The parity bit calculation is based on the number of bits in the data/value. The start and stop bits are not used when calculating the parity bit.

Example: Value 65, even parity.
65 is is binary 1000001 which has 2 bits as 1s. 2 bits is already even so the parity bit will be a 0. This means there are still a total of 2 bits which is even.

Example: Value 65, odd parity.
If the parity is changed to odd, then the parity is a 1. The total number of bits is now 3 and 3 is an odd number.

Stop Bit(s)

At the end of the data packet there is 1 or 2 stop bits. Stop bits are always 1s

The start and stops bits are often referred to as the synchronisation bits

Baud Rate

Baud rate is the speed at which the data is transmitted. UART does not have a fixed baud rate, the speed is fully open and, in theory, any speed can be used. There are specific speeds that are considered standard though. Baud rates are generally specified in bps, or bits per minute.
Here are the baud rates the Arduino IDE (as well as many other devices) use as defaults; 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 250000, 500000, 1000000, 2000000.

For communication to work both the transmitting and the receiving device must agree on (use) the same baud rate. When baud rates are mismatched you may get garbage characters, or more likely, nothing at all.

As you use UART more you will notice that certain speeds are very common. 9600, 38400, and 115200 are probably the most common, 9600 and 115200 are used with the Arduino a lot. 9600 is a safe speed to use with software serial libraries. 115200 is a good speed to use for hardware serial.

How Fast Is bps

9600 is 9600 bits per second, and this means means 1 bit of data (a bit, not a byte) takes:
1 second divided by 9600 = 0.000104166667 seconds or 104.166667 microseconds (μs).

Using 8N1, which uses 10 bits (see below), 9600 is capable of transmitting 960 characters per second. This may sound fast but 9600 is considered slow. A regular 16Mhz Arduino is capable of transmitting at 2,000,000 bits per second, that’s 200,000* characters per second. Not too shabby.

*Terms and conditions apply.

What Baud Rate Is best?

All of them and none of them. The best baud rate is the one that works reliably doing what you want to do.
Because UART uses only two wires, the UART signal degrades over distance, especially at 5V and 3.3V. So when transmitting data over any kind of distance, slower baud rates are more reliable. Have your Arduino sat next to a computer then faster bauds are no problem.
Sometimes you don’t have much choice. Have a Bluetooth module connected to an Arduino and using a software serial library then you are limited to a maximum speed of 38400, probably slower if the Arduino has other things to do while talking to the Bluetooth module.

UART Short Hand

Rather than fully describing all the various properties a short hand notation is often used. If you have read the Arduino Serial Introduction you have already been introduced to 8N1. 8N1 means; 8 data bits, no parity, and 1 stop bit. Since start bits are always used we don’t need to mention them.

8N1 is very very common and is used as the default setting for the Arduino as well as many other devices.

There are many combinations that can be used, and each combination or format has its own little code, here are some of them to give you an idea.

  • 5O1* – 5 data bits, odd parity, 1 stop bit
  • 6N2* – 6 data bits, no parity, 2 stop bits
  • 7N1 – 7 data bits, no parity, 1 stop bit
  • 8N1 – 8 data bits, no parity, and 1 stop bit
  • 8E2 – 8 data bits, even parity, 2 stop bits

* 5 and 6 data bits has limited use in Arduino land. 5 bits has a maxim value of 31 which does not cover the the alphabet + numeric digits.
6 binary digits has a maxim value of 61. Not quite enough to cover all printable characters let alone the rest of the ASCII characters.

As well as specifying the UART properties, you may also see the baud rate to the beginning of the short hand code, for example;

  • 9600 8N1
  • 38400 7E1

How UART Data Is Transmitted

UART data is transmitted serially bit by bit. When sending ASCII characters, the characters are broken down to their separate bits and the bits transmitted one by one. The receiving device collects all the bits and puts them back together to recreate the data. It’s kind of like how the transporter in Star Trek works. You are not sending the item as a whole, you are sending all the bits that make up the item.

When you use Serial.Write(“ABCD”) in an Arduino sketch, the Arduino Serial library takes each character in turn, A, B, C, D, breaks the character down in to bits and adds extra bits to create the UART packet (see above). The packet is then transmitted bit by bit by making the TX pin HIGH/LOW/HIGH/LOW as required.

It should be noted that UART uses a normally HIGH signal line.

The format of the packet is governed by the settings specified (such as 7N1, 8N1) when the serial connection is initialised. If a setting is not specified then the Arduino uses 8N1 by default.

Serial.begin(9600);  // use the default 8N1 packet format

Serial.begin(9600,SERIAL_7E1);  // 7E1 packet format

Serial.begin(9600,SERIAL_8N2); //   2 stop bits

It is the UART protocol that specifies how the packet of data is put together and when transmitting, the baud rate specifies how quickly, or more precisely, when, the TX signal goes HIGH and when it goes LOW.

Bit Transmission Time

Bit transmission time is the amount of time used for 1 bit of data. The same duration is used for all bits within the packet and is governed by the baud rate. Since the baud rate is in bps (bits per second) we can calculate the bit transmission time by simple dividing 1 by the baud rate.

For 9600 this is: 1 / 9600 = 104.166667 microseconds
For 115200 it is: 1 / 115200 = 8.68055556 microseconds

Due to how microprocessors work (they do things at specific points in time based on a clock tick), they may not match the baud rate exactly. They normally get close enough that it usually doesn’t matter though.

If I use PulseView to measure the bit time for baud rate 9600 I can see it is around 104.125 microseconds which works out to an actual baud rate of 9603.84. Luckily UART has some margin of error built in and as long as the actual baud is within around 2% of the desired baud rate all is good.

The difference between the desired baud rate and the baud rate the microprocessor produces is called the transmission error and is more prominent at certain, usually slower, baud rates. At baud rate 1,000,000 for example, the Arduino can match the baud rate exactly.

Closer look At UART

I think that’s enough theory so let’s start to play. I have an Arduino Nano connected to a logic analyser (LA), it’s a cheap aliexpress special, although I got it from taobao even cheaper ;-)

Hardware TX to LA channel 0
Hardware RX to LA channel 1 (not used)
Pin 13 (built in LED) to LA channel 3. I am using pin13 to trigger the capture.

Arduino Sketch

The Arduino has a very simple sketch. All it does is

  • turn on the built in LED
  • start serial at 9600
  • turn off the LED
  • send U by serial (capital u)

I use LED to tell me when to start the logic analyser – I sees the LED, I have 1 second to click the RUN button. The logic analyser starts the actual capture when the LED goes off (pin 13 goes LOW and triggers the data capture).

const int LED_PIN = 13;
void setup() 
{
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, HIGH);

    // 8N1 is the default setting for the Arduino serial monitor
    Serial.begin(9600,SERIAL_8N1 );

    // when the LED turns on it is my mark to start the logic analyser.
    // the logic analyser is monitoring only until the pin goes low
    delay(1000);

    // when pin13 goes LOW the actual capture starts
    digitalWrite(LED_PIN, LOW); 

    Serial.print("U");
}

void loop() { ; }

Data Packet

Here is the character U at 9600 baud rate using 8N1. I am assuming you remember what 8N1 means.

Nice even ups and downs (its actually down and ups but still looks nice)

Capital U is a good character to use as an example because its ASCII value has a nice bit pattern. The ASCII code for U is decimal 85 and decimal 85 in binary 1010101, no two adjacent digits are the same. This makes each bit easy to see in the diagram above.

The first thing to notice is that the base UART line is HIGH. It starts HIGH and ends HIGH, and this is why the start bit is a LOW. A HIGH start bit on a HIGH line is going to be hard to see :-) The line goes LOW when transmitting data. 0s are transmitted as LOW, 1s are transmitted as HIGH.

The receiving device knows the baud rate (or should know) so it knows how long each bit is transmitted for.

When using the UART decoder in PulseView we get handy labels showing what the bits represent and we can see that the first bit is indeed the start bit.

We then get the 8 data bits that represent the actual data or value. In this case a capital U. again, PulseView has kindly labelled the data for me.

I have 2 UART decoders displayed at the same time, one shows decimal, the second shows ASCII.

8 data bits is perfect for ASCII and the original ASCII value is used as is, no changes or conversions required. In the diagram below, you should be able to see the binary value 10101010. Each HIGH is a 1 and each LOW is a 0.

8N1 doesn’t have a parity bit so there isn’t one to see. We do have the stop bit at the end though. The stop bit is a 1 so the signal is HIGH. After the stop bit the signal goes back to waiting which is a HIGH line.
You can’t see the end of the stop bit in the chart but because the receiving device knows the baud rate it can calculate it when the stop bit ends.

Here is the same character with a even parity bit and 1 stop bit – AKA 8E1

Since 10101010 has an even number of 1s, the parity bit is a 0 to keep the total even.

Let’s change the UART to 8O1. 8 data bits, odd parity, 1 stop bit. To make the total number of bits odd, the parity becomes a 1.

Let’s go back to 8N1 and try some different characters. Here are ABCD, 1234.

    Serial.print("ABCD");
    Serial.print("1234");

Not as easy to read as the U, just remember, a LOW is a 0 and a HIGH is a 1, and follow the binary value.

Here is a close up of A. The binary ASCII value for A is 10000010

That’s all there is to it. Data is transmitted one bit at a time by using LOW/HIGH signals. LOW is the pin pulled to GND and HIGH is the pin pulled HIGH to whatever voltage the MCU is using (normally 3.3v or 5v). In my case I am using a 5v Arduino Nano so the HIGH signal is 5v.

The duration of the bit transmission time is set through the baud rate. The slower the baud rate, the longer the bit transmission time, the faster the baud rate the shorter the bit transmission.

ASCII Table

ASCII stands for American Standard Code for Information Interchange. It was originally developed for use with teletypes.

Dec  Char 
----  ----  
  0  NUL (null)
  1  SOH (start of heading) 
  2  STX (start of text)
  3  ETX (end of text) 
  4  EOT (end of transmission) 
  5  ENQ (enquiry) 
  6  ACK (acknowledge) 
  7  BEL (bell) 
  8  BS  (backspace) 
  9  TAB (horizontal tab)
 10  LF  (NL line feed, new line) 
 11  VT  (vertical tab) 
 12  FF  (NP form feed, new page) 
 13  CR  (carriage return)  
 14  SO  (shift out) 
 15  SI  (shift in)  
 16  DLE (data link escape) 
 17  DC1 (device control 1) 
 18  DC2 (device control 2)
 19  DC3 (device control 3) 
 20  DC4 (device control 4) 
 21  NAK (negative acknowledge) 
 22  SYN (synchronous idle) 
 23  ETB (end of trans. block) 
 24  CAN (cancel) 
 25  EM  (end of medium) 
 26  SUB (substitute) 
 27  ESC (escape) 
 28  FS  (file separator) 
 29  GS  (group separator) 
 30  RS  (record separator) 
 31  US  (unit separator) 
Dec  Char 
----  ----- 
 32  SPACE
 33  !    
 34  "    
 35  #    
 36  $    
 37  %    
 38  &    
 39  '    
 40  (    
 41  )    
 42  *    
 43  +    
 44  ,    
 45  -    
 46  .    
 47  /    
 48  0    
 49  1    
 50  2    
 51  3    
 52  4    
 53  5    
 54  6    
 55  7    
 56  8    
 57  9    
 58  :    
 59  ;    
 60  <    
 61  =    
 62  >    
 63  ?    
Dec  Char
----  -----
 64  @   
 65  A   
 66  B   
 67  C   
 68  D   
 69  E   
 70  F   
 71  G   
 72  H   
 73  I   
 74  J   
 75  K   
 76  L   
 77  M   
 78  N   
 79  O   
 80  P   
 81  Q   
 82  R   
 83  S   
 84  T   
 85  U   
 86  V   
 87  W   
 88  X   
 89  Y   
 90  Z   
 91  [   
 92  \   
 93  ]   
 94  ^   
 95  _   
 Dec  Char
 ----  ------
  96  `
  97  a
  98  b
  99  c
 100  d
 101  e
 102  f
 103  g
 104  h
 105  i
 106  j
 107  k
 108  l
 109  m
 110  n
 111  o
 112  p
 113  q
 114  r
 115  s
 116  t
 117  u
 118  v
 119  w
 120  x
 121  y
 122  z
 123  {
 124  |
 125  }
 126  ~
 127  DEL

2 thoughts on “Serial UART And How It Works”

Leave a Comment