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.
External Interrupt in PIC18F4550
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.
Configuration bits for External Interrupt
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.
RCON
- IPEN: Interrupt Priority Enable bit. Enables priority levels when set.
INTCON
- GIE/GIEH: Global Interrupt Enable bit
- When IPEN is disabled, GIE enables all interrupts that sets
- When IPEN is enabled, GIEH enables all high priority interrupts that sets
- PEIE/GIEL: Peripheral Interrupt Enable bit
- When IPEN is disabled, PEIE enables all peripheral interrupts that sets
- When IPEN is enabled, GIEL enables all low priority interrupts
- INT0IE: INT0 External Interrupt Enable bit. Enables the INT0 external interrupt that sets
- INT0IF: INT0 External Interrupt Flag bit. Sets when INT0 external interrupt occur
INTCON3
- INTxIP: INTx External Interrupt Priority bit. INTx External Interrupt is set as a High priority interrupt
- INTxIE: INTx External Interrupt Enable bit. Enables the INTx external interrupt when set
- INTxIF: INTx External Interrupt Flag bit. Sets when INTx external interrupt occur
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
- lcd_init() – To initialise the LCD in 8 bit mode
- lcd_data(char) – To display a given character
- lcd_cmd(int) – To execute an LCD command
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
INT0
Enable the INTo interrupt and clear the flag bit.
INTCONbits.INT0IE=1; //Enabling INT0 interrupt INTCONbits.INT0IF=0; //clearing INT0 interrupt flag
INT1
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
INT2
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.
Interrupt Service Routine
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
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
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.