UART Communication

Universal Asynchronous Receiver/Transmitter or UART is a simple and common serial communication protocol. It uses separate transmission and reception lines making it a full duplex communication.

A simple full-duplex UART communication requires the following registers as explained in our previous chapter UART Interfacing with PIC Microcontroller. We will focus only on the bits relevant to our cause.


UART Interrupt in PIC18F4550

  • TXEN- This bit is set high to enable the transmission.
  • SYNC- The mode of communication is selected by this bit. The bit is made set for synchronous mode and is cleared for asynchronous mode.
  • BRGH- Configured to determine the asynchronous communication, set for high speed and clear for low speed.
  • TRMT Status (read-only ) bit shows the status of transmit shift register. The bit is set when a transmission is complete and gets cleared when a transmission is in progress.
  • TX9- This bit is set to high while sending 9-bit long data (set for 9-bit data and cleared for 8-bit data).



UART Interrupt in PIC18F4550

  • SPEN- This bit is used to enable/disable the serial port. (Tx and Rx pins). Set to enable the port and is cleared to disable the serial port.
  • RX9- This bit is used when 9-bit long data is to be received. The bit is set to select 9-bit reception cleared to select 8-bit reception.
  • SREN– This bit is used only in synchronous mode.
  • CREN – Set to enable continuous reception. Clearing this bit will stop reception.
  • ADDEN– Address detection enable bit used in 9-bit data format.
  • FERR & OERR – Framing error bit and overrun error bit. Bits are set when corresponding errors occur.



UART Interrupt in PIC18F4550

This register controls the baud rate generation and some other UART features such as automatic baud rate generation, inversion of receiving data etc.

  • BRG16- This bit enables the 16-bit baud rate generation. When this bit is set baud rate is generated by both SPBRG and SPBRGH registers when it is cleared the baud rate is generated by SPBRG register only.



  • RCIF – Receive interrupt flag sets when data received in the RCREG register. Receive interrupt occur if enabled.
  • TXIF – Transmit interrupt flag sets when data in the TXREG register is transmitted and is empty.



  • RCIE – Setting this bit will enable the receiver  interrupt.
  • TXIE– Setting this bit will enable the transmission interrupt.



TXREG is the transmit buffer register in which data to be transmitted is stored.


RCREG is the receive buffer register in which the received data is stored.


These registers are used to specify the baud rate. When BRG16 is cleared the baud rate is calculated with the formula
Baud rate = FOSC/[64 x (SPBRG+1)]

The data direction of the Transmitter and Receiver pins must also be set with the TRISC register.

Here we intend to use the UART in both transmit and receive mode at a baud rate of 9600 bits per second with 20Mhz clock frequency. We need to set the registers accordingly.

Firmware Example:

TRISC |= 0x80;                  //Rx-Input   Tx-Output
TXSTA = 0x20;                   //TXEN enabled
RCSTA = 0x90;                   //SPEN and CREN enabled
SPBRG = 31;                     //9600 baud rate @20Mhz clock freq

We also need functions to send and receive data

Firmware Example:

char rx_char(void)
    while(!RCIF);                   //Wait till RCREG is full
    return RCREG;                   //Return value in received data

void tx_char(char a)
    TXREG=a;                        //Load TXREG register with data to be sent
    while(!TRMT);                   //Wait till transmission is complete


UART Interrupt Handling

An interrupt is a signal to the processor of the occurrence of an event by hardware or software. The processor may choose to accept or ignore this signal. The response of the processor to an interrupt is configured with the help of registers such as INTCON, PIR, PIE and IPR registers as specified in our previous chapter on Interrupt Handling in PIC18F4550. Upon receiving the interrupt the processor branches to a vector called Interrupt vector or Interrupt Service Routine(ISR), which is executed before resuming previous code sequence.

The UART Interrupt is used to detect the completion of data transmission or reception without continuously polling the flag bit, thus saving processor time. The interrupt is detected with the help of the TXIF and RCIF bits. To use these interrupts, we must first enable GIE and PEIE bits in the INTCON register.


  • GIE/GIEH: Global Interrupt Enable bit
    • When IPEN is disabled, GIE enables all interrupts when set
    • When IPEN is enabled, GIEH enables all high priority interrupts when set
  • PEIE/GIEL: Peripheral Interrupt Enable bit
    • When IPEN is disabled, PEIE enables all peripheral interrupts when set
    • When IPEN is enabled, GIEL enables all low priority interrupts when set

Reception Interrupt

Reception interrupt is requested when the receiver buffer RCREG is full. The flag bit used is RCIF and it is automatically cleared by hardware when the buffer is read. This helps us in receiving UART data without continuously checking for data in the RCREG.

To enable Reception interrupt we need to enable the RCIE bit.


In the ISR, we need to poll for the RCIF flag and receive the data in RCREG if the flag is set. Here we are sending the data received back through the transmission channel.

__interrupt() void ISR(void)
    char a;
    if(RCIF==1)                     //Polling for reception interrupt
        a=rx_char();                //Receiving data
        tx_char(a);                 //Transmitting back received data

Transmission Interrupt

In UART transmission, the data uploaded to the TXREG register is first transferred to a buffer register called TSR. In a specified baud rate, the data is shifted out to the transmission line. A transmission interrupt is obtained when the data in the register TXREG is fully transferred to the TSR register and becomes empty. The application of transmission interrupt is mainly for transmitting a string of data without manually polling for completion of each character transmitted.

This can be done by first enabling the transmission interrupt and disabling it after transmission of complete data. Since interrupt does not accept any input parameters, a global variable is used instead. To initiate the data transfer after loading the global variable, the interrupt flag is manually set once.

Firmware Example:

char *str;                          //Global variable used for interrupt

void tx_str(char *a)
    TXIE = 1;                       //Enable transmission interrupt
    str = a;                        //pointing str pointer to data to send
    TXIF = 1;                       //Manually enabling interrupt
    while(*(str-1));                //Wait for transmission of complete string
    TXIE = 0;                       //Disable transmission interrupt
    tx_char(0x0D);                  //New Line

Note: We wait till *(str-1) is null (and not *str) since disabling the interrupt immediately at last character will prevent transmission of the last character.

In the ISR, we need to poll for the TXIF flag, send data addressed by a pointer to the TXREG register and increment the pointer to the next data.

Firmware Example:

__interrupt() void ISR(void)
    char a;
    if(TXIF==1)                     //Polling for transmission interrupt
        TXREG=*str;                 //Load data to TXREG register
        str++;                      //increment pointer to next data

The tx_str() function used to send a string directly in the format

tx_str((char *)"Sending string through UART");

Note: String is an array of characters, here we are explicitly converting it to a character pointer type.

Spread the love, share this