Use UART Interrupt of Pic Microcontroller with Examples (PIC18F4550)

In this tutorial, we will see how to use UART interrupt of pic microcontroller. We will use the PIC18F4550 microcontroller to receive data serially. Unlike, a polling method, a UART interrupt method doesn’t wait for the data and keep executing or doing other tasks. As soon as UART receives register raises a full capacity interrupt (RCIF), an interrupt service routine (ISR) will be called. ISR routine used to read data from the receiver register (RCREG).

This PIC18F4550 tutorial is a part of UART Communication using Pic Microcontroller.  I recommend you to read this tutorial first. Because in that guide, we explain the following concepts of UART Module:

  • PIC UART Module Registers
  • Send data serially ( send string with uart)
  • Receive data Serially (receive string with pic uart)

Why do we need to use PIC UART Interrupt?

But we used a polling method to receive string or data with pic UART module. But now we will see an interrupt method to receive data. Because polling is not an efficient method and it halts microcontroller execution at the same location waiting for the condition to meet. The polling method is kind of a round-robin method.  The main disadvantage of this technique is the wastage of microcontroller time and resources.

Difference between Polling and Interrupt Method

This figure shows the comparison of the polling vs interrupt technique. In the first case, it keeps waiting until the specified condition is met. But in another case, the microcontroller will keep doing something else and as soon as interrupt response comes, it executes interrupt and return to the original program location where it left execution.

interrupt vs polling

PIC18F4550 UART Interrupt Registers

As we have seen in the last tutorial, three main registers that are associated with the serial communication module of PIC18F4550 are:

  • Transmit Status and Control (TXSTA)
  • Receive Status and Control (RCSTA)
  • Baud Rate Control (BACON)

For more information and How to configure these registers, check this tutorial

Furthermore, to use pic uart interrupt, we need to configure some bits of these registers also.

PIC18F4550 Interrupt Registers

INTCON: Interrupt Control Register

Two bits of the interrupt control register should be enabled. The first bit (GIE) enables global interrupt and the second bit (PEIE) enables peripheral interrupts. Peripherals examples are UART, ADC, DAC, etc. We are using UART. Therefore, we also enable all unmasked peripheral interrupts with PEIE. We can configure them in MPLAB XC8 compiler like this:

INTCONbits.GIE=1;  // Enable all unmasked global INT
INTCONbits.PEIE=1; // Enabel Peripheral interrupt

PIR1: PERIPHERAL INTERRUPT REQUEST (FLAG) REGISTER 1

This register provides information on transmitter and receiver data flags. These two bits are used from the PIR1 register.

  • RCIF: This flag_bit shows that the UART receive register(RCREG) is full and the data is ready to read.

If this RCIF=1 that means receive register is full and If RCIF=0, that means either data is not available or not fully received.

  • TXIF: It shows the status of the UART transmit buffer (TXREG).

If TXREG buffer is empty, TXIF=0 ( that means data transmitted). Otherwise TXIF=1; that means transmit buffer is full.

PIE1 : PIE1: PERIPHERAL INTERRUPT ENABLE REGISTER 1

This register is used to enable peripherals interrupts just like UART. Two bits of PIE1 are associated with the serial communication transmitter and receiver module of PIC18F4550 microcontroller.

  • RCIE: It enables the UART receive interrupt. If we want to receive data with UART receive interrupt. We must enable this bit.
  • Similarly, TXIE enables/disables transmitter INT.

We can simply configure these registers in MPLAB XC8 compiler like this:

  PIE1bits.RCIE=1; 
  PIE1bits.TXIE=1;

IPR1: PERIPHERAL INTERRUPT PRIORITY REGISTER 1

PIC18F4550 microcontroller also supports the setting of high/low priority for peripherals. This is an optional configuration setting. For example, if you are using more than one peripherals such as ADC and DAC in your project and you want to give high priority to ADC. You can enable a high priority bit of ADC using this register. By doing this, if both ADC and DAC generate interrupt at the same time, the microcontroller will give preference to the ADC ISR call.

 IPR1bits.RCIP=1; //  Set USART Receive Interrupt Priority bit
 IPR1bits.TXIP=1; //  Set USART Transmit Interrupt Priority bit

PIC UART Interrupt Receive Data Serially

In this section, we will see an example code to receive data interrupt. Unlike a polling method, the pic microcontroller will keep executing its normal program. But whenever PIC18F4550 receives data on the RC7/RX pin, interrupt will occur. A program stops the normal execution and starts to execute the ISR routine.

PIC UART Interrupt Code Example

This example code keeps executing normal microcontroller operations. But upon ISR, it stops the normal operation and executes ISR function. Inside void __interrupt() myISR() , we receive data from receive buffer. If received data is a capital letter ‘A’, it turns on PORTDbits.RD0. Otherwise, whatever data will be received, the RD0 pin will remain active low.

#include <xc.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "pic18f4550_config.h" // Include configuration file 
#define F_CPU 8000000/64 // value to calculate baud rate
char data;

void __interrupt() myISR()
{
if(RCIF==1) 
{
if(RCSTAbits.OERR)
{ 
CREN = 0;
NOP();
CREN=1;
} 
data = RCREG;
if(data=='A')
PORTDbits.RD0=1;
else
PORTDbits.RD0=0;
RCIF=0;
}

}


void MSdelay(unsigned int val)
{
unsigned int i,j;
for(i=0;i<=val;i++)
for(j=0;j<81;j++); 
}
void UART_Initial(long baud_rate)
{
float bps; 
TRISCbits.RC6=1;
TRISCbits.RC7=1;
bps = (( (float) (F_CPU) / (float) baud_rate) - 1); // sets baud rate
SPBRG=(int)bps; // store value for 9600 baud rate
TXSTAbits.CSRC = 0; // Don't care for asynchronous mode
TXSTAbits.TX9 = 0; // Selects 8-bit data transmission
TXSTAbits.TXEN = 1; // Enable Data tranmission on RC6 pin
TXSTAbits.SYNC = 0; // Selects Asynchronous Serial Communication Mode
TXSTAbits.BRGH = 0; // Default Baud rate speed 
BAUDCONbits.BRG16 = 0; // selects only 8 bit register for baud rate 
RCSTA = 0x90; // Enables UART Communication PORT

}

void main(void) 
{

OSCCON=0x72; // Select internal oscillator with frequency = 8MHz
TRISDbits.RD0=0; //Make RD0 pin as a output pin
PORTDbits.RD0=0; //initialize RD0 pin to logic zero
INTCONbits.GIE=1;
INTCONbits.PEIE=1;
PIR1bits.RCIF=0;
PIE1bits.RCIE=1;
IPR1bits.RCIP=1;

UART_Initial(9600);
while(1)
{

}
return;
}
  • Now copy this copy and make a new project with the MPLAB XC8 compiler.
  • Select PIC18F4550 microcontroller and internal frequency of 8MHz.
  • Don’t forget to add the configuration bits header file. You can generate a configuration file with an MPLAB XC8 compiler easily.
  • After that compile the code and upload code to PIC18F4550 microcontroller.

Simulation Result

When you will send ‘A’ to serial pin RX, LED will glow and otherwise, it will remain off for all data.

 

UART Interrupt PIC Microcontroller PIC18F4550 Receive data SERIALLY

Code Working

Now we will see the working of the program. These lines include the header files for PIC18F4550 microcontroller registers and the header file of configuration bits.

#include <xc.h>
#include "pic18f4550_config.h" // Include configuration file

We use one #define to calculate the baud rate and one character type variable to store received data.

#define F_CPU 8000000/64 // value to calculate baud rate
char data;

This is an interrupt service routine function. In the MPLAB XC8 compiler ( latest version), we define ISR with keyword void __interrupt(). But we can give any name to this function after void __interrupt() keyword. Inside this function, RCIF bits checks, if data is available to read. If it is available, first it checks overrun error and there is no error, we get data from RCREG register and store it inside a character type variable ‘Data’.

void __interrupt() myISR()
{
if(RCIF==1)
{
if(RCSTAbits.OERR)
{
CREN = 0;
NOP();
CREN=1;
}
data = RCREG;
if(data=='A')
PORTDbits.RD0=1;
else
PORTDbits.RD0=0;
RCIF=0;
}

}

If condition evaluates if data received is equal to ‘A’ and it is true, the RD0 pin will be active high. Otherwise, it will remain active low. The rest of the code is same as we have seen in UART Communication with PIC18F4550 microcontroller tutorial.

You can also check:

2 thoughts on “Use UART Interrupt of Pic Microcontroller with Examples (PIC18F4550)”

  1. Actually i have a question, How does a micro controller know “if an interrupt comes we have execute this ISR”, does the __interrupt() keyword plays the role here?, can anyone help me?

    Reply

Leave a Comment