UART | Serial Communication With PIC Microcontrollers Tutorial

Previous Tutorial Previous Tutorial Tutorial 18 Next Tutorial Next Tutorial
UART Serial Communication Protocol
Intermediate Level ★★☆☆☆

 

In this tutorial, we’ll be discussing our first serial communication protocol (UART). You’ll get to know what is the UART serial communication protocol? How does it work? What are the typical applications for UART? We’ll also discuss in detail the process of creating the required firmware to drive the UART module in our PIC Microcontrollers. And finally, create a simple communication application MCU-To-MCU and test it out. It’s going to be a very long read with a massive amount of information, So let’s get started!

 

SPI Tutorial - PIC MicrocontrollersYou may also need to check out the SPI (serial peripheral interface) tutorial. It’s another 10k words long-read kind of gigantic tutorial. Check it out and maybe keep it bookmarked as a guide for future work!

 

I2C Tutorial With PIC Microcontrollers ThumbnailYou may also need to check out the I2C Bus tutorial. It’s another 12k words long-read kind of gigantic tutorial. Check it out and maybe keep it bookmarked as a guide for future work!

 

 

[toc]


   Required Components   

Qty. Component Name Buy On Amazon.com
2 PIC16F877A Add
2 BreadBoard Add
8 LED Add    Add
1 Resistors Kit Add    Add
1 Capacitors Kit Add    Add
1 Jumper Wires Pack Add    Add
1 USB-TTL Converter or FTDI Chip Add    Add
1 LM7805 Voltage Regulator (5v) Add
1 Crystal Oscillator Add
1 PICkit2 or 3 Programmer Add
2 9v Battery or DC Power Supply Add    Add    Add

The Prototyping Board Setup

Prototyping Board - Embedded Systems Tutorials With PIC MCUs


   Introduction To Serial Communication   

 

In Embedded Systems, Telecommunication, and Data Transmission applications, Serial Communication is known to be the process of sending data one bit at a time (bit-by-bit) sequentially, over the serial bus. It takes a complete clock cycle in order to transfer each bit from an end to the other. Conversely, parallel communication is known to be the process of sending several bits, even bytes, as a whole only in a single clock cycle. However, even if you transfer fewer data per cycle with a serial transmission, you can do it at much higher frequencies which results in higher net transfer rates than of the parallel communication.

 The Fundamental Concepts 

There do exist many serial communication protocols, each of which is working in a different way. However, it turns out to be some similarity that they do share in common. Frankly speaking, serial communication protocols have Shift Registers somehow/somewhere in their hardware implementation as the working-horse (core). Shift registers are used to shift out the data to be transmitted bit-by-bit each clock cycle. So, let’s dig deeper into a shift register in order to build-up a complete understanding for what is actually happening at the Register(low)-Level.

Shift registers are basically some D-Flip-Flops serially connected while sharing the same clock line. Here is a graphical animation that demonstrates how does a shift register work internally.

Shift Register Flip-Flop Animation | UART Tutorial

 

As you might have noticed, the data input (0’s and 1’s) is being shifted from the input pin to the output end at bit-0. It takes only 1-clock to transfer a single bit, which means it takes 8-clocks for a single byte transfer. For the same of simplicity, we’ll represent the shift register as a single block instead of a series of D-Flip-Flops as shown above.

 

Here is an animation for an 8-Bit shift register with a serial input & serial output data lines.

Shift Register | UART Tutorial With PIC Microcontroller

 

Well, now you should know how shift registers are actually working. Frankly speaking, serial communication is as simple as connecting a couple of shift registers together! Connecting the data output of a shift register to be the data input of the other shift register enables us of sending digital data serially from an end to another!

 

In the following animation, I’m connecting a couple of 4-Bit shift registers. One at the transmitter device and the other at the receiver device. The serial bus consists of a couple of wires (data, and clock). Each clock, a bit is sent from the transmitter TX pin and received by the receiver’s RX pin.

Serial Communication | UART Tutorial With PIC Microcontroller

As you might have noticed, it takes 4-clocks to send the 4-Bit data from the transmitter to the receiver. This is simply the short answer to the “How Serial Communication Works?”. However, it’s not everything you should know about serial communication or at least to the level of being able to implement a simple serial data transfer process.

In fact, there are some other options and configurations for each serial communication protocols. Which includes, various data transmission rates, error detection, and correction mechanisms, and much more that adds to the overall complexity associated with each protocol. We’ll be working with the UART protocol in this tutorial, which has a decent steep learning curve.

 Serial VS Parallel Communication 

As we’ve stated earlier, serial communication is the process of sending data each bit at a time (bit-by-bit). And conversely, the parallel communication is the process of sending multiple bits, even bytes, as a whole in a single clock cycle.

A very basic implementation, that you can create on your own, for the parallel data transfer is shown down below. As I’m connecting a couple of 4-Bit registers, via the 5-wire parallel bus (4-data pins + 1-clock). Here is an animation that shows you how parallel data transfer is done.

Parallel Communication | UART Tutorial

As you might have noticed, it takes only 1-clock to transfer the data from a transmitter device to the receiver! Frankly speaking, we can theoretically transfer any number of bits (or bytes) using parallel communication protocols in a single clock cycle at a time. 

Here is a brief comparison between serial communication and parallel communication protocols.

Feature Serial Communication Parallel Communication
Relative Speed Faster Slower
Distance Range Much Farther Shorter
Transfer Method One bit is transmitted at a time Bytes are transmitted in parallel, One byte or more at a time
Applications Computer small peripherals, modules interfacing, and sensors measuring & sending simple data frames Short distance High-Speed communication such as Computer printers, etc 
Wires Inside Few wires, all data bits pass only through the same data line Multiple, more wires, each bit has a dedicated wire. So as to be transmitted all at once
Cables Pictures Ethernet Serial Cable | UART TutorialUSB Serial Cable | UART Tutorial Serial Cable | UART Tutorial Parallel Port | UART Tutorial Parallel Cable | UART Tutorial Parallel Connectors | UART Tutorial

 Applications Of Serial Communication Protocols 

There are countless situations in which we do use one or more of the serial communication protocols. Here, I’ll try to categorize the main purposes for which we use serial communication instead of listing down all possible applications that may be serving the same purposes. Hence, any application will, hopefully, possibly fall under the umbrella of the following purposes.

  • External devices/modules communications
  • Downloading / Updating The Firmware
  • Console io
  • Data Transmission
  • Debugging interface

Serial communication protocols are of fundamental importance for each embedded systems application. And as embedded systems engineers, we must have a very solid experience with almost all of the commonly used serial communication protocols. And in the next sub-section, we’ll see a brief collection of the commonly available serial communication protocols in the embedded market.

 Examples Of Serial Communication Protocols 

There are many serial communication protocols that are existent and being used in various domains and sub-domains of embedded systems. Some of which are more likely to be used in the automotive industry such as LIN & CAN, some of which is more likely to be used for external memory interfacing as I2C, high-speed computer interfacing as USB, and for audio applications such as I2S. Here is a list of the most common serial communication protocols in the industry.

USB CAN I2C
I2S LIN SPI
Ethernet 1-Wire UART/USART
And many more…

We’ll be focusing only on the UART serial protocol in the rest of this tutorial. Just to understand the fundamentals & mechanics of UART communication. Only then, we’ll be able to develop the necessary firmware in order to transmit data from an embedded MCU to another as we’ll be doing the lab at the end of this tutorial. So, let’s get started with UART!

 


   Introduction To UART   

 

Universal Asynchronous Receiver/Transmitter or UART for short represents the hardware circuitry (module) being used for the serial communication. UART is sold/shipped as a standalone integrated circuit (IC) or as an internal module within microcontrollers. In this tutorial, we’re actually concerned with the internal UART module within PIC Microcontrollers.

There is a couple of io pins dedicated to the UART serial communication module highlighted in the following figure. Namely, RX (data input – receiving end) & TX (data output – transmitting end).

PIC UART RX-TX Pins

 Forms Of UART Communication 

There are actually two forms of UART as follows:

  • UART – Universal Asynchronous Receiver/Transmitter
  • USART – Universal Synchronous/Asynchronous Receiver/Transmitter

The Synchronous type of transmitters generates the data clock and sends it to the receiver which works accordingly in a synchronized manner. On the other hand, the Asynchronous type of transmitter generates the data clock internally. There is no incoming serial clock signal, so in order to achieve proper communication between the two ends, both of them must be using the same baud rate. The baud rate is the rate at which bits are being sent bps (bits per second).

UART USART
Standalone Communication Protocol It can support multiple protocols like LIN, RS-485, IrDA, etc
Commonly used for low-speed applications More suitable for high-speed applications
The data rate is relatively low The data rate is much higher
The clock is generated locally and both devices are configured to run at the same baud rate The clock signal is generated by the transmitter and sent to the receiver during data transmission
The baud rate of the receiver module must be known prior to any communication The baud rate is useless as the receiver module will be using the clock coming from the transmitter device
Offer reduced low energy footprint even in sleep mode Operates at high energy consumption modes

So, is UART and USART are the same? Technically, NO! A USART generally has much more capabilities than a generic UART. Being able to generate clocked data allows the USART to operate at much higher baud rates way more than what a typical UART can handle.

 Modes Of UART Communication 

The communication over the UART bus can be configured (set) to be on one of the following modes:

  • Simplex – One direction only, a transmitter to a receiver
  • Half Duplex – Devices take turns transmitting and receiving
  • Full Duplex – Devices can send and receive simultaneously (at the same time)

 Modes Of Operation For UART Devices 

The UART serial communication bus can only have 2 devices communicating with each other in one of the 3 modes shown in the previous sub-section. Which necessarily means, each device can either be a transmitter or a receiver during the data transmission process.

  • Transmitter
  • Receiver

You should know that the transmitter in synchronous mode must generate the serial data clock for the receiver. On the other hand, in asynchronous mode, there is no need to do so.

And there can’t be more than 2 devices on the UART serial bus. Otherwise, there will be some issues introduced to the system which you’ll have to work around.

The proper connection for any 2 devices for UART serial communication goes as follows: the transmitter’s TX goes to the receiver’s RX and the receiver’s TX goes to the transmitter’s RX. Frankly speaking, the 2-wires are basically crossed!

UART RX-TX Connection

 UART Data Packet 

The data being transmitted/received in UART serial communication is organized into specific blocks called Packets. In the idle state, UART lines are pulled high. This allows the receiver side to recognize that there is a transmitter device on the other end which is connected to the serial bus. UART Packets usually start with “Start Bit” which is a logic low and is used to signal the receiver that there is a new coming packet. The structure of a typical UART Data Packet is shown in the figure down below.

UART Data Packets

Start Bit

The UART data transmission line (TX) is normally held High (1) logic-level when there is no data transmission on the line. To start data transfer, the transmitting UART pulls-down the transmission line from high to low for one clock cycle. When the receiving UART module detects the high to low voltage transition, it begins reading the incoming bits of the entire data frame at the same frequency of the specified baud rate.

Data Frame

These are the actual data bits being transmitted from transmitter to receiver. The length of the data frame can be anywhere between 5 and 9 (9-Bits if parity is not used and 8-Bits if parity is used). In general settings, the LSB is the first bit to be shifted-out, transmitted, (unless otherwise specified).

Parity Bit

Parity bit allows the receiver to check the correctness of the received data. Parity is a low–level error checking mechanism and has two different options to choose from: Even Parity and Odd Parity. After the receiver UART reads the data frame, it counts the number of bits with a value of 1 and checks if the total value is an even or odd number. If the parity bit is a 0 (even parity), the number of bits with a value of 1 in the data frame should sum-up to an even number. If the parity bit is a 1 (odd parity), the number of bits with a value of 0 in the data frame should sum-up to an odd number. When the parity bit matches the data, the receiver UART knows that the transmission was a success. Frankly speaking, the parity bit is optional and it’s actually not widely used.

Stop Bit

As the name suggests, this bit is used to signal the end of the data packet being sent. The sending UART drives the data transmission line from low to high for at least two-bit durations but most often only one bit is used. The data line is held high back to the idle state and ready for any future transmission.

 Baud Rate 

The Baud Rate specifies how fast the data is sent over the bus and it is specified in bits-per-second or bps. You can actually choose any speed for the baud rate. However, there are some specific values that are known to be the industry standards. The most common and widely-used standardized value is 9600. Other standard baud rates include: 1200, 2400, 4800, 19200, 38400, 57600 and 115200. Obviously, baud rates are always multiples of 300. Baud rates higher than 115200(bps) can be used with an additional probability of having, at best, missing data packets. The rule of thumb in UART communication is, both the transmitter and the Receiver UART must agree on the exact same Baud Rate for a successful data transmission.

 Digital Block Diagram (UART Transmitter) 

Here is the block diagram for a generic UART transmitter module as found in PIC16F87XA devices’ datasheet (fig-10.1, page-115).

UART Transmitter Block Diagram

A Brief Description For UART Transmission Process

In UART transmitter mode, a byte of data is written to the 8-Bit TXREG register. Then it’s latched to the TSR transmitter shift register combined with the 9th bit (if used). The data is shifted out through the TX/RC6 physical pin at a rate specified by the BRG baud rate generator. The baud rate is pre-determined and pre-configured by us (the programmers) in order to match the design specifications. Setting the baud rate to be generated is as easy as writing a byte-value to the SPBRG register. The value is precisely calculated using a specific formula as we’ll discuss hereafter. All in all, the transmission process is as simple as you might be thinking right now.

 Digital Block Diagram (UART Receiver) 

Here is the block diagram for a generic UART transmitter module as found in PIC16F87XA devices’ datasheet (fig-10.4, page-117).

UART Receiver Diagram

A Brief Description For UART Receiving Process

The data is received on the RX/C7 physical pin and drives the data recovery block. The data recovery block is actually a high-speed shifter, operating at x16 times the baud rate. Whereas the main receiver serial shifter operates at the bit rate or at FOSC.

Once the Asynchronous mode is selected, reception is enabled by setting bit CREN. The heart of the receiver is the Receive Serial Shift Register RSR. After sampling the Stop bit, the received data frame in the RSR is transferred to the RCREG register (if it is empty). If the transfer is complete, the flag bit, RCIF, is set. The actual interrupt can be enabled/disabled by setting/clearing the enable bit, RCIE. Flag bit RCIF is a read-only bit which is cleared by the hardware. It is cleared when the RCREG register has been read and is empty. The RCREG is a double-buffered register which means it’s a two-level deep FIFO.

 Physical Layer Standards 

There are actually many different standards that utilize the same UART protocol previously described. Such as: TTL level UART, RS-232, RS-422, RS-485, etc. We’ll only discuss both the TTL-level UART and RS-232 in this sub-section of our tutorial. However, we are more interested in the TTL-Level supported by the microcontrollers which we’re aiming to (program) drive hereafter in this tutorial.

TTL-Level UART

The majority of microcontroller chips with UART serial communication modules do use TTL (Transistor-transistor Logic) level UART. Actually, it’s the simplest form of UART. Both logic-1 and logic-0 are represented by 5V and 0V respectively.

Logic Level Logic-1 (High) Logic-0 (Low)
Voltage 5v 0v

The TTL-level UART is more likely to be used in the communications between MCUs, modules, sensors, and ICs. It requires only 2-wires for the full-duplex communication and it’s connected as shown in the following diagram.

UART RX-TX Connection

RS-232 UART

RS-232 (Recommended Standard 232) is a standard for serial binary data signals connecting between a Data Terminal Equipment (DTE) and a Data Communication Equipment (DCE). It is commonly used in computers’ old-school serial ports. The major differences between TTL level UART and RS-232 include the voltage-level. The digital signals in RS-232 are ±3 to – ±15V, and signals near 0V aren’t detected anyway.

Logic Level Logic-1 (High) Logic-0 (Low)
Voltage +3 to +15v -3 to -15v

RS232 UART Data Frames

The RS-232 also has a few more pins than the TTL-level UARTs, specifically designed for the communication between PCs and Modems in the past. The pinout of the DB-9 and their functions are shown down below.

RS-232 UART DE9 Connectors Pinout

RS-232 DE9 Pinout Functions Table

We’re more interested in the standard TTL-Level UART modules available in our microcontroller, but you should also know the basics of RS-232 standards. Maybe in the future, I’ll consider creating a dedicated tutorial for this. For now, let’s continue our introduction to UARTs.

 Advantages Of UART Serial Communication 

  • Only two wires are required for a full-duplex data transmission (excluding the power lines).
  • The structure of the data packet can be changed with coordination between both ends.
  • No need for a serial clock signal (in asynchronous mode).
  • Parity bit provides a hardware-level error detection.
  • Well-documented and widely-used protocol.
  • Relatively easy to set-up and run.

 Disadvantages Of UART Serial Communication 

  • Speed for data transfer is less compared to parallel communication or even USARTs.
  • The baud rates of each UART must be the same within a limited small error margin.
  • The size of the data frame is limited to a maximum value of 9-Bits.
  • Doesn’t support multiple slaves or multiple masters capability.

 


   USART Module In PIC MCUs   

 

 Description 

The Universal Synchronous Asynchronous Receiver Transmitter (USART) module is one of the two serial I/O modules. (USART is also known as a Serial Communications Interface or SCI.) The USART can be configured as a full-duplex asynchronous system that can communicate with peripheral devices, such as CRT terminals and personal computers, or it can be configured as a half-duplex synchronous system that can communicate with sensors, modules, etc.

The USART module can be configured to operate in one of the following modes:
• Asynchronous (full-duplex)
• Synchronous – Master (half-duplex)
• Synchronous – Slave (half-duplex)

 Baud Rate Generator (BRG) 

The BRG supports both the Asynchronous and Synchronous modes of the USART. It is a dedicated 8-bit baud rate generator. The SPBRG register controls the period of a free running 8-bit timer. In Asynchronous mode, bit BRGH also controls the baud rate. In Synchronous mode, bit BRGH is ignored. Down below is the formula for computation of the baud rate for different USART modes which only apply in Master mode (internal clock).

Baud Rate Generator Equation

Given the desired baud rate and FOSC, the nearest integer value for the SPBRG register can be calculated using the formula previously shown. From this, the error in baud rate can be determined. It may be advantageous to use the high baud rate (BRGH = 1) even for slower baud clocks. This is because the FOSC/(16 (X + 1)) equation can reduce the baud rate error in some cases.

You can refer to table 10-4 in the datasheet for some example values for Baud Rate VS multiple values for Fosc (in Asynchronous mode, BRGH=1). Here is a snapshot for this table.

UART Baud Rate Table

Note That: Writing a new value to the SPBRG register causes the BRG timer to be reset (or cleared). This ensures the BRG does not wait for a timer overflow before outputting the new baud rate.

 UART SFR Registers 

Here is a list of the SFRs (special function registers) involved in the UART data transmission/reception.

  • TXSTA – Transmitter status and control register
  • RCSTA – Receiver status and control register
  • SPBRG – Baud rate generator register
  • TXREG – Transmitter Buffer Register
  • RCREG – Receiver Buffer Register

 


   How To Configure The UART Transmitter?   

 

In this section, we’ll be focusing on the process of configuring a PIC microcontroller to work as a UART Asynchronous Transmitter. Enough of general information about UART! let’s get our microcontroller to work as a serial UART transmitter!

 The Mechanics Of UART Transmission 

The UART transmits and receives the LSB first. The transmitter and receiver are functionally independent but use the same data format and baud rate. The baud rate generator produces a clock, either x16 or x64 of the bit shift rate, depending on bit BRGH. Parity is not supported by the hardware but can be implemented in software (and stored as the ninth data bit). Asynchronous mode is stopped during Sleep. Asynchronous mode is selected by clearing bit SYNC. The UART Asynchronous module consists of the following important elements:
• Baud Rate Generator
• Sampling Circuit
• Asynchronous Transmitter
• Asynchronous Receiver

UART Transmitter Block Diagram

The heart of the transmitter is the Transmit (Serial) Shift Register TSR. The shift register obtains its data from the Read/Write Transmit Buffer, TXREG. The TXREG register is loaded with data in software. The TSR register is not loaded until the Stop bit has been transmitted from the previous loading process. As soon as the Stop bit is transmitted, the TSR is loaded with new data frame from the TXREG register (if available). Once the TXREG register transfers the data to the TSR register (occurs in one TCY), the TXREG register is empty and flag bit, TXIF, is set. This interrupt can be enabled/disabled by setting/clearing enable bit, TXIE.

Flag bit TXIF will be set regardless of the state of enable bit TXIE and cannot be cleared in software. It will reset only when new data is loaded into the TXREG register. While flag bit TXIF indicates the status of the TXREG register, another bit, TRMT, shows the status of the TSR register. Status bit TRMT is a read-only bit which is set when the TSR register is empty. No interrupt logic is tied to this bit so the programmer has to poll this bit in software to determine if the TSR register is empty or not.

Transmission is enabled by setting enable bit, TXEN. The actual transmission will not occur until the TXREG register has been loaded with data and the Baud Rate Generator (BRG) has produced a shift clock as in the following diagram.

UART Asynchronous Master Transmission

The transmission can also be started by first loading the TXREG register and then setting enable bit TXEN. Normally, when a transmission is first started, the TSR register is empty. At that point, transfer to the TXREG register will result in an immediate transfer to TSR, resulting in an empty TXREG. A back-to-back transfer is thus possible, which means we can send consecutive data frames continuously as shown in the following diagram.

UART Tutorial | Asynchronous Master Transmission Back-To-Back

Clearing the enable bit TXEN during a transmission will cause the transmission to be aborted and will reset the transmitter. As a result, the TX/RC6 pin will revert to High-impedance.

If it feels overwhelming, stay cool. It really does! Each of us has been at the same point and yes! it felt overwhelming. Take the time to understand each step of the mechanics.

Down below are the exact brief steps that you should follow to configure your UART Asynchronous Transmitter, even without looking up any diagram in the datasheet. However, you should consider doing so sooner or later at some point.

 Steps For Configuring The UART Transmitter 

  1. Initialize the SPBRG register for the appropriate baud rate. If a high-speed baud rate is desired, set the bit BRGH.
  2. Enable the asynchronous serial port by clearing bit SYNC and setting bit SPEN.
  3. Bits TRISC<7:6> have to be set in order to configure pins RC6/TX/CK and RC7/RX/DT as the Universal Synchronous Asynchronous Receiver Transmitter.
  4. If interrupts are desired, then set the enable bit TXIE.
  5. If the 9-bit transmission is desired, then set transmit bit TX9.
  6. Enable the transmission by setting bit TXEN, which will also set bit TXIF.
  7. If the 9-bit transmission is selected, the 9th bit should be loaded in bit TX9D.
  8. Load data to the TXREG register (this step automatically starts the transmission).
  9. If using interrupts, ensure that GIE and PEIE (bits 7 and 6) of the INTCON register are set.

 Implementing UART Transmitter Driver Firmware 

 

 Step1  write to the SPBRG register in order to set the desired baud rate

Using the High-Speed baud rate even for low speeds is advantageous due to the fact that the error percentage will be significantly smaller. Doing so requires setting the BRGH bit.

Let’s say our system is running @ 4MHz Fosc and it’s desired to generate 9600bps baud rate. Using the baud rate formula shown earlier.

UART Baud Rate Ex Equation

Solving for x (the value to be written to the SPBRG register), it turns out to be

x = 25 (approximately)

Therefore, the c-code for this step is as follows

 

 Step2  Enable The Asynchronous Serial Port

We won’t be using interrupts for UART transmitter in this tutorial, so I won’t be going through any interrupt activation steps.

 

 Step3   Set The RX-TX Pins Data Direction

 

 Step4   Enable The UART Transmission Process

This is done by setting the TXEN bit.

 

 Step5   Load The Data To TXREG

Load the data to be transmitted to the TXREG register.

Mission Complete! Transmission is done!

 UART Transmitter Full Code Listing 

You can easily use those 3-functions within your code. Calling the UART_TX_Init() procedure will configure the UART transmitter for you. Then, calling the UART_Write(data) will shift-out the data frame from your transmitter to the receiving end.

 


   How To Configure The UART Receiver?   

 

In this section, we’ll be discussing the process of configuring a PIC microcontroller to work as a UART receiver. Let’s get our microcontroller to work as a serial UART receiver.

 The Mechanics Of UART Reception 

The data is received on the RX/C7 physical pin and drives the data recovery block. The data recovery block is actually a high-speed shifter, operating at x16 times the baud rate. Whereas the main receiver serial shifter operates at the bit rate or at FOSC.

UART Receiver Diagram

Once the Asynchronous mode is selected, reception is enabled by setting bit CREN. The heart of the receiver is the Receive Serial Shift Register RSR. After sampling the Stop bit, the received data frame in the RSR is transferred to the RCREG register (if it is empty). If the transfer is complete, the flag bit, RCIF, is set. The actual interrupt can be enabled/disabled by setting/clearing the enable bit, RCIE. Flag bit RCIF is a read-only bit which is cleared by the hardware. It is cleared when the RCREG register has been read and is empty. The RCREG is a double-buffered register which means it’s a two-level deep FIFO.

Down below are the exact brief steps that you should follow to configure your UART Asynchronous Receiver, even without looking up any diagram in the datasheet. However, you should consider doing so sooner or later at some point.

 Steps For Configuring The UART Receiver 

  1. Initialize the SPBRG register for the appropriate baud rate. If a high-speed baud rate is desired, set bit BRGH.
  2. Enable the asynchronous serial port by clearing bit SYNC and setting bit SPEN.
  3. Bits TRISC<7:6> have to be set in order to configure pins RC6/TX/CK and RC7/RX/DT as the Universal Synchronous Asynchronous Receiver Transmitter.
  4. If interrupts are desired, then set enable bit RCIE.
  5. If a 9-Bit reception is desired, then set bit RX9.
  6. Enable the reception by setting bit CREN.
  7. Flag bit RCIF will be set when reception is complete and an interrupt will be generated if enable bit RCIE is set.
  8. Read the RCSTA register to get the ninth bit (if enabled) and determine if any error occurred during reception.
  9. Read the 8-bit received data by reading the RCREG register.
  10. If any error occurred, clear the error by clearing enable bit CREN.
  11. If using interrupts, ensure that GIE and PEIE (bits 7 and 6) of the INTCON register are set.

 Implementing UART Receiver Driver Firmware 

 

 Step1  write to the SPBRG register in order to set the desired baud rate

The same as the UART transmitter which runs @ 4MHz and the desired baud rate must be 9600 as well. Hence, the c-code for this step is as follows

 

 Step2  Enable the asynchronous serial port

We won’t be using interrupts for UART transmitter in this tutorial, so I won’t be going through any interrupt activation steps.

 

 Step3   Set The RX-TX Pins Data Direction

We’ll be using UART Data Reception interrupt to signal our microcontroller each time a data frame arrives at the UART receiving buffer. The ISR routine should read out the data from the buffer and store it in the respective (safe) place. This action will automatically set the receiver to be ready for a consecutive data reception. However, we (the programmers) should not forget clearing the interrupt flag bit in software!

 

 Step4   Setup UART Receiving Interrupt

 

 Step5   Enable UART Data Reception

This is done by setting the CREN bit.

 

 Step6   Read The Received Data Upon Reception

This is actually done within the ISR function by reading the RCREG (the receiver buffer register).

However, you can still poll the RXREG buffer register within your main code. Almost in every situation, you’ll be missing most of the received data using this way! But, for limited applications where data received via UART is coming at a very low rate (maybe 10-Bytes/second or whatever), then you might be using the following simple UART_Read() function and calling it from your main routine.

Mission Complete! Reception Accomplished!

 UART Receiver Full Code Listing 

You can easily use those functions within your code. Calling the UART_RX_Init() procedure will configure the UART receiver for you. Then, calling the UART_Read() will return the data frame from your receiver buffer register.

 


   µC-To-µC UART Communication – LAB   

 

Lab Name UART Basic Communication
Lab Number 16
Lab Level Intermediate
Lab Objectives Learn how to create a serial communication interface between 2 microcontrollers using UART Protocol. We’ll send specific data frames from a transmitter MCU and receive it back with another one then double-check the data correctness and validate the communication process.

 

       1. Coding       

 

Open the MPLAB IDE and create a couple of new projects name them “UART_TX” and “UART_RX” for master and slave MCUs respectively. If you have some issues doing so, you can always refer to the previous tutorial using the link below.

Create New Project With MPLAB IDE

Set the configuration bits to match the generic setting which we’ve stated earlier. And if you also find troubles creating this file, you can always refer to the previous tutorial using the link below.

Now, open the main.c file of each project and let’s start developing the firmware for our project.

1. UART Transmitter (Master)

[ Transmitter Firmware ]

Our task is to take 3 inputs from the user using 3 push buttons to do the following tasks:

Button1: increment the data value

Button2: decrement the data value

Button3: send the current data frame via UART @ 9600bps

We’ll use PORTD to display the current data value for the user. And 3 input pins of PORTB. Obviously, we’ll also configure our microcontroller to operate as a transmitter as we’ve seen earlier in this tutorial. Here is the full code listing for the transmitter MCU chip.

2. UART Receiver (Slave)

[ Receiver Firmware ]

Our task is to set up the UART module to operate in slave mode @ 9600bps and enable the UART data reception interrupt. Within the ISR handler, we should read the received byte of data and latch it out to PORTB with some LEDs for data inspection. And here is the full code listing for the receiver MCU chip.

And We’re Done With The Firmware! Cross Your Fingers! And Hit The Compile Button!

 

       2. Simulation       

 

Create the simulation project on your simulator and connect your circuitry as shown in the schematic diagram down below. Add the hex code to the respective microcontroller chip. The receiver code to the receiver chip and so. Click the run button and test out everything!

 

UART Serial Communication With PIC Microcontroller Tutorial - LAB Schematic

The Running Simulation Test !

UART LAB Simulation

 

       3. Prototyping       

 

If you’ve correctly followed the schematics shown above in the simulation section, you should get your code up and running on a real breadboard flawlessly! However, you should be careful with grounding and RX-TX connections and make sure that you’ve (flashed) uploaded the right code to each chip (Master & Slave).

And here is the final running prototype for this project in case you’re curious.

Play Video On YouTube

 

       4. Firmware Template       

 

The previous code listings for this lab despite being fully-functional. It may need a little bit of work to get it working at a different baud rate or at a different clock frequency. That’s why I’ll give you a template for more portable and easier to use firmware for both your transmitter & receiver devices.

Transmitter ( Master Code )

Receiver ( Slave Code )

 


   Pro Tips + Concluding Remarks   

 

  1  

PC Interfacing With Microcontroller

Practically, there do exist many ways to build a PC-MCU interface. However, it’s much easier to use the last one of the following list. We’ll be implementing a PC-controlled embedded system to control some actuators in a dedicated LAB following this tutorial. For now, let’s check the interfacing capabilities (options) to get a microcontroller chip (MCU) to talk to a personal computer (PC) and vice versa.

TTL-UART To RS-232 Serial (Old Generic Interfacing)
UART To RS-232 Generic Interfacing To PC
TTL-UART To RS-232 Serial To USB
UART PC Interfacing With USB-RS232 Converter
USB-TTL Converter Module
UART PC Interfacing With USB-TTL Converter

  2  

RX-To-TX & TX-To-RX

it’s a very common mistake to have your RX & TX lines wrongly wired. So, please be careful and make sure you’ve connected them correctly. It may take you some time to find out & debug, so be careful in the first place instead.

UART RX-TX Connection

  3  

Baud Rate Mismatching

if data is being transmitted at 9600bps Baud rate and being received at a 38400bps. The received data will be a total mess (garbage)! Baud rate must be matched at both ends (Transmitter & Receiver). It’s a rule of thumb in UART serial communication. The maximum allowable shift in baud rates tends to be between (1-2%). So try to generate the exact same baud rate at both ends to avoid mismatching error. 

  4  

Debugging With Virtual Terminal

Communication channels can go crazy in almost any system. Whether it’s a wired or wireless communication. Let’s focus our investigation on the serial UART communication. Imagine a situation in which you’ve got a device A (master) communicating with device B (slave).

Device A: is programmed to send a data frame of (0x05)

Device B: is programmed to latch the received data within the ISR and write it out to PORTB

UART Serial Debugging

Yet, device B is printing out some random garbage!

The question is, who is the criminal to suspect? is it A? or B? or even the hardware bus on-board?

That’s why it’s kind of a tricky business to debug serial bus communications!

You just can’t decide which firmware has to be fixed. Arbitrarily suspicion & random modifications to either of firmware at A or B can make it more difficult and time-consuming. What I prefer, is to use one of the following methods

  • An oscilloscope or Logic Analyzer (inspection)
  • Standard virtual serial protocols debugger

I assume that everybody should be familiar with capturing signals on a generic CRO or a Logic analyzer. What I’d really like to point out to are the Virtual Serial Debugger Tools. Just a standard UART receiver/transmitter which you can graphically configure using a GUI. Using it will make your life much more easier, but why?

Well, if you’ve got a standard receiver that is guaranteed to correctly receive each and every data frame, Then you can tell if your UART transmitter (device A) is malfunctioning or not!

Conversely, if you’ve got a standard transmitter that’s is guaranteed to generate and sens specific data frames at a specific baud rate flawlessly, Then you can tell if your UART receiver (Device B) is malfunctioning or not!

UART Serial Communication Virtual Debugging Tool

It’s available in proteus ISIS simulator and can be easily configured/connected as you’ve seen in the figure above. Use your own tools and what you personally prefer for debugging. Always be sure that you’re consistently stepping forward toward solving the problem or finding out who is the hiding criminal. And determine where and which changes have to be made!

  5  

UART Bus Length VS Baud Rate

UART serial buses can go for quite long distances if your application needs so. However, the maximum allowed baud rate gets limited as you go further respectively. It also depends on the hardware implementation (Physical Layer) of the UART protocol itself. We’ll only mention both of the TTL-UART & RS-232 standards.

RS-232

The maximum cable length for RS-232 is 50ft. But in practice, it depends on the baud rate, cable specific capacitance, and ambient noise. The table below contains some rules-of-thumb from experiments done by Texas Instruments years ago.

UART RS-232 Baud Rate VS Cable Length

TTL-UART

TTL level Serial UART only has a 5V swing. Hence, you have to figure out the following 3 things.

1- Cable Resistance: all cables have an impedance that adds up as it goes longer. The longer the cable and higher the resistance, the more the voltage change is detected at one end compared to the other.

2- Cable Capacitance: Highly capacitive wires strongly resist changing from one voltage level to the other. The higher the capacitance of wires, the slower its state changes and more rounded-off the signal becomes. Therefore, the higher the speed and longer the distance, the signal will start to look less like a square wave and more like a noisy sine wave.

3- Noise: it does always exist and assumed to be existent in each environment. And due to the low voltage swing and without differential signaling, it gets harder to communicate farther. However, twisted-pair cables with shielding will greatly help.

Based on that, and my own information/experiments, as there is no sufficient info online in this area. TTL-UART can possibly go 50ft (15m) using a generic UTP Cat 5 cable. As well as the RS-232.

  6  

Overrun Error

An overrun error occurs when the receiver cannot process the data frame that has just arrived in the buffer before the next one arrives. Various devices have different amounts of buffer space to hold received data. So, let’s focus on our 8-Bit PIC MCU.

During asynchronous UART data reception, It is possible for two bytes of data to be received and transferred to the RCREG FIFO and a third byte to begin shifting to the RSR register. On the detection of the Stop bit of the third byte, if the RCREG register is still full, the Overrun Error bit, OERR, will be set to indicate that an Overrun Error has occurred.

The word in the RSR (the 3rd byte) will be lost. The RCREG register can be read twice to retrieve the two bytes in the FIFO. Overrun bit OERR has to be cleared in software. This is done by resetting the receive logic (CREN is cleared and then set). If bit OERR is set, transfers from the RSR register to the RCREG register are inhibited and no further data will be received. It is, therefore, essential to clear error bit OERR if it is set.

  7  

Framing Error

A UART receiver will detect a Framing Error when it does not see a stop bit at the expected time after a start bit. As the start bit is used to identify the beginning of an incoming data frame, its timing is a reference for the remaining bits. If the data line is not in the expected state (high) when the “stop” bit is expected (according to the number of data and parity bits for which the UART is set), the UART will signal a framing error. Which means the timing between data bits, start bit, and stop bit is somehow for whatever reason is just messed up! A break condition on the line is also signaled as a framing error.

There exist many reasons for which a framing error may occur such as:

  • Baud rate mismatches
  • A too long serial data line
  • Electrical noise on the serial cable

Framing error bit, FERR, is set if a Stop bit is detected as clear. Bit FERR and the 9th receive bit are buffered the same way as the receive data. Reading the RCREG will load bits RX9D and FERR with new values, therefore, it is essential for the programmer to read the RCSTA register before reading the RCREG register in order not to lose the old FERR and RX9D information.

  8  

Bus Contention

This happens when you attempt to connect more than 2 devices on the UART serial bus. it’s not allowed to have more than 2 devices on the UART serial bus, as it’s possible to have 2 devices writing data to the same TX line. Which will (at least) cause data corruption at the receiving end. And for worst, the transmitters involved may get damaged (it’s a rare condition, yet mostly protected against).

That’s why they use what’s called (Software Serial UART) in the Arduino ecosystem, in case you’ve got a previous experience with. There’s an FTDI USB-Serial converter connected to the hardware RX/TX pins of the MCU and mostly used for debugging via serial monitor. Hence, connecting any additional serial device (e.g. Bluetooth Module, GPS, etc.) to the same bus will definitely be a problematic act! Eventually, they tend to use software (emulated) serial UART instead. Due to the Bus Contention Error. We’ll briefly address the concept of the emulated-UART hereafter.

  9  

Software UART (Emulated)

The software can emulate a UART transmitter/receiver module using only some code and consuming a considerable amount of resources specifically CPU’s time and/or a hardware timer. It can extend your available on-chip UARTs or compensate for the lack of a hardware UART at all and to some extents. There is always fundamental limitations and drawbacks for what software can emulate.

All in all, if you’re in a situation where you need an additional UART serial module, you can emulate it using the software. Just in case your demand for a UART is moderately low. But if your application needs extensive UART communication, then you should look for a hardware solution. As overloading your CPU with unnecessarily expensive (in time) software will be a totally inefficient way to go.

 

 

SPI Tutorial - PIC MicrocontrollersYou may also need to check out the SPI (serial peripheral interface) tutorial. It’s another 10k words long-read kind of gigantic tutorial. Check it out and maybe keep it bookmarked as a guide for future work!

 

 

 


Disclaimer

It took me several days to craft this resource on that topic. And most of the information here represents my knowledge and point of view which may have some pitfalls. So, I’ll appreciate any comment, modifications or suggestions to polish this work a little bit more.

Some paragraphs, diagrams, tables are copy / pasted from datasheets / technical documentations specifically from Microchip 8-Bit PIC MCUs. Just for the sake of consistency in firmware implementations using these MCU chips. To keep the theoretical side more relevant to practice, I had to do so. It’s protected by fair use act. However, I just wanted to disclaim it for you.

 

References

In case you’re willing to go further.

serial port and Microcontrollers: Principles, Circuits, and Source Codes

Serial Port Complete: COM Ports, USB Virtual COM Ports, and Ports for Embedded Systems

 

 

 

Previous Tutorial Previous Tutorial Tutorial 18 Next Tutorial Next Tutorial
Share This Page With Your Network!
Join Our +25,000 Newsletter Subscribers!

Stay Updated With All New Content Releases. You Also Get Occasional FREE Coupon Codes For Courses & Other Stuff!

Photo of author
Author
Khaled Magdy
Embedded systems engineer with several years of experience in embedded software and hardware design. I work as an embedded SW engineer in the Automotive & e-Mobility industry. However, I still do Hardware design and SW development for DSP, Control Systems, Robotics, AI/ML, and other fields I'm passionate about.
I love reading, writing, creating projects, and teaching. A reader by day and a writer by night, it's my lifestyle. I believe that the combination of brilliant minds, bold ideas, and a complete disregard for what is possible, can and will change the world! I will be there when it happens, will you?

32 thoughts on “UART | Serial Communication With PIC Microcontrollers Tutorial”

  1. Hello Khaled,

    I found your tutorial to be really fascinating and well documented. Thank you so much for this hard work. Please keep it coming on other communication protocols as well.

    When you have sometime, can you please explain a bit about DSP and how well can it be implemented using PIC’s?

    Reply
  2. Dear Khaled Magdy
    I uses PIC microcontroller for about 10 years.
    Nowadays, my programming all done with PBASIC, compile into HEX file then program it using Universal Programmer.
    Please give me some better idea how I can program the PIC by using c++, compile it, and program it.

    This enquiry maybe not related to this post, but I hope it benefits all the readers.

    Thank you and best regards,
    Piau

    Reply
    • It’s written and compiled with XC8 and tested as shown in the video, so everything is ok.
      As for Hitech-c, I think it should also work with no problems. If you can tell me more about the specific error you’re getting, maybe i’ll be able to help you a little bit more.
      Regards,

      Reply
  3. Thank you so much Sir for better explanation of the above tutorial .
    sir, Can you explain how to implement the UART on FPGA in Verilog .

    Reply
    • In the near future, i’ll be explaining fpga hardware design. But for now, you can check nandland.com for amazing fpga tutorials. I’m pretty sure he has done a uart tutorial

      Reply
  4. hello sir,

    why you are not describing the controller part in UART.
    can you send me the controller design and baud generator design.
    i need to implement uart using only using gates and flipflops.

    thank you

    regards
    Bodasani Harinadha Reddy,
    reddyharinadha1@gmail.com

    Reply
  5. Hello!
    Thank you for sharing the knowledge!

    UART tutorial needs a little corrections.
    * RS-232 (correct) Logic Levels are: 0 (space) = +3 to +15V, 1 (mark) = -3 to -15V
    * RCIF = 0; // Clear The Flag
    -> RCIF flag can not be cleared that way, the only way to clear it is to read RCREG.

    regards

    Reply
    • Thanks for this reply, i was so busy lately but i’ve approved the comment immediately!
      I’ll correct these points. Thanks a lot! I really appreciate your contribution

      Reply
  6. Hello! Thanks for the very informative tutorial.

    In the receiving code, it is written RCIF=0;

    I remember you have stated that RCIF bit can only be clared by hardware.Then why did you clear this bit by writing 0 to it?

    Reply
    • Generally, interrupt flag bits have to be cleared in software after servicing the interrupt request inside the isr.
      Did i really state that it’s done in hardware? All in all, if that’s true we won’t have to clear it again in software as you say. Check it out and tell me what you will get!

      Reply
      • // Functions Declarations
        void UART_RX_Init(void);
        uint8_t UART_Read(void);

        These lines are from receiver firmware. Were these lines necessary? I mean we have declared the UART_RX_Init() function at the end of the firmware and we have not used UART_Read(void) function at all.

        Reply
        • That’s true. If you’ll be using the isr to receive the data so the read function can be removed completely from the entire code file.
          On the on the other hand, the init fubction can not be defined without declaring it at the bedinning. Just comment out that line and see the error message from the compiler ????
          The block of code at the end is the definition not a declaration. The declaration is still important. Unless you move the function definition block to be above the main. In this case, no declaration is needed.
          Hope this helps ^^

          Reply
  7. Thanks Khaled for such in depth tutorials. I am using them together with PIC micro-controller datasheet and I always come right. One question though, what is difference between computer science and computer engineering?

    Reply
  8. Many thanks for a beautifully clear explanation, which I am using to repurpose a PCB with PIC16F877A RS485 input and 4 large 7 segment LEDs as a slave clock. My code fails because I do not understand how to read a string rather than a single character. I expect I need to disable interrupts and reset pointers etc, but an example of receiving strings using the ISR would be very helpful.

    Reply
  9. Awesome Tutorial. I have come across a very long way to this. So far best Tutorial. UART explained very elaborately. USART also same, except one caveat:
    Master/Slave operation in Synchronous Mode, should had be given some more space.OR another tutorial may be :). Nine Bit Operation with Address Detection would be very useful for those who work in RS485.
    Thank you

    Reply
  10. السلام عليكم ورحمة الله وبركاته
    Hi Khaled , hope you are doing well
    I have a question about Data recovery in the receiver. you said “The data recovery block is actually a high-speed shifter, operating at x16 times the baud rate” , so what is its role??

    Reply
    • Hi Kareem!
      Nice question. I didn’t actually illustrate how this x16 times faster sampling rate works or contributes to considering a specific bit to be 1 or 0. However, i beleive that it’s illustrated much better in my STM32 UART Tutorial.
      You can also google this subject to get an idea how reading a uart bit 16 times is useful. It helps uart module to make sure that a specific received bit is a 0 or 1. There is a rule for this to happen and you’ll find it in my other article or on google results.
      All the best ^^

      Reply
  11. Greatings Khaled.
    First of thank you for this wonderful website.
    Just a quick remark:
    This did not work for me
    TRISC6 = 1;
    TRISC7 = 1;

    But this did :
    TRISC6 = 0; // RC6 should be an output
    TRISC7 = 1;

    Am I right ?

    Thx again. I will go through this whole website ????

    Reply
    • Hi Edward. Thx for your feedback. I actually still in doubt if that is the issue in your test setup.
      Because it’s stated in the datasheet that both pins should be in input “Hi-Z” mode. That’s why we move 1 to each of both bits TRISC6, 7
      I can’t confirm if this is global across all microchip pic mcu parts but as far as i know they are pretty much the same.

      Reply
      • HI Khaled
        Thank you for your time.
        Well you are right, it did not work at first because of my receiver (I’m using an Arduino as second board)

        Howerver I tried either TRISC6 as input or output, that works just the same.
        But I will follow your saying ????

        Right now
        PIC-> Arduino works
        Arduino -> Does not work yet …

        Reply
  12. Hi Khaled,
    Great body of work, well done and big Thank You, sir.

    In the uart tut you refer to your spi tut, however, when I follow the link – Page not Found-
    I see that on the Tut homepage, clicking on SPI points to the same link with – Page not Found-

    Did you complete the spi tut and where is it located, if you can kindly point me to the link.

    Thank you.

    Gerhard

    Reply

Leave a Comment