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.
An interrupt request is associated with a particular code sequence is called as an Interrupt Service Routine(ISR) or interrupt vector. Upon receiving a valid interrupt, the processor will halt current code execution, save next instruction address and status to stack, execute the ISR and then resume the previous code sequence execution after restoring data from the stack.
An external interrupt happens due to an interference by some external hardware on specific pins of the microcontroller. PIC18F4550 can handle up to three external interrupts.
To configure the processor to receive and process interrupt request we use the following registers associated with the external interrupt. We will focus only on bits relevant to an external interrupt.
INTCON
INTCON3
The response of the processor to an interrupt signal will depend on these enable, priority and flag bits.
To obtain a response to the interrupt we will use the 16*2 LCD connected to PORT A and PORT D as configured in our previous chapter on 16*2 Character LCD Interfacing with PIC Microcontroller in 8-bit Mode. We will also need the following functions to use the LCD
Now, let’s configure the processor to receive all three external interrupts INT0, INT1, and INT2. The external interrupt pins are configured to input pins and use TRISB register to receive the interrupt request. We will be using priority mode and will configure INT1 as a high priority interrupt and INT2 as a low priority interrupt. So also enable the GIEH and GIEL bits.
Firmware Example:
TRISB=0x07; //Configuring interrupt pins as input INTCONbits.GIEH=1; //Enabling High priority interrupts INTCONbits.GIEL=1; //Enabling Low priority interrupts RCONbits.IPEN=1; //Enabling Interrupt priority
Enable the INTo interrupt and clear the flag bit.
INTCONbits.INT0IE=1; //Enabling INT0 interrupt INTCONbits.INT0IF=0; //clearing INT0 interrupt flag
Enable the INT1 interrupt, set the priority bit to high and clear the flag bit
INTCON3bits.INT1IE=1; //Enabling INT1 interrupt INTCON3bits.INT1IF=0; //Clearing INT1 interrupt flag INTCON3bits.INT1IP=1; //Setting INT1 interrupt priority as high
Enable the INT2 interrupt, set the priority bit to low and clear the flag bit
INTCON3bits.INT2IE=1; //Enabling INT2 interrupt INTCON3bits.INT2IF=0; //clearing INT2 interrupt flag INTCON3bits.INT2IP=0; //Setting INT2 interrupt priority as low
A code sequence to display a character at a particular rate is implemented with interrupt configuration.
ISR(Interrupt Service Routine) defines both high priority and low priority interrupts.ISR of XC8 compiler as in this format
__interrupt(<type>) void <ISR_identifier> (void) { <ISR code sequence> //Clear the interrupt flag <Interrupt_flag_bit> = 0; }
Here we will be defining the INT0 ISR to display the character ‘b’ three times with 200ms interval. To clear display use INT1 ISR. To display the character ‘c’ three times at a 200ms interval use INT2 ISR.
Polling inside the ISR with the help of flag bit detecting interrupt. At the end of the code sequence, the interrupt flag must be clear.
High priority interrupt vector occupies the position 008h in the program memory. They are defined with <type> parameter as high_priority.
__interrupt(high_priority) void ISR1(void) //High priority interrupt ISR { if(INTCONbits.INT0IF==1) //polling for INT0 interrupt { for(int i=0;i<3;i++) { lcd_data('b'); __delay_ms(200); } INTCONbits.INT0IF=0; //clearing INT0 interrupt flag } if(INTCON3bits.INT1IF==1) //polling for INT1 interrupt { lcd_cmd(0x01); INTCON3bits.INT1IF=0; //clearing INT1 interrupt flag } }
Low priority interrupt vector occupies the position 018h in the program memory. They are defined with <type> parameter as low_priority.
__interrupt(low_priority) void ISR2(void) //Low priority interrupt ISR { if(INTCON3bits.INT2IF==1) //polling for INT2 interrupt { for(int i=0;i<3;i++) { lcd_data('c'); __delay_ms(200); } INTCON3bits.INT2IF=0; //clearing INT2 interrupt flag } }
In this program, we can observe that any of the three interrupts can interrupt a normal code sequence execution. A high priority interrupt can interrupt a low priority interrupt without the converse being true. The normal program execution will resume after the ISR execution.