PIC18 Interrupt Programming
Interrupt Programming
• Contra and compare interrupts versus polling
• Explain the purpose of the ISR
• List all the major interrupts of the PIC18
• Explain the purpose of the IVT
• Enable and disable PIC18 interrupts
• Program the interrupt using c language
Interrupt
• Whenever any device needs the
microcontroller’s service the device notifies it by
sending an interrupt signal. Upon receiving an
interrupt signal, the microcontroller stops
whatever it is doing and serve the device. The
program associated with the interrupt is called
ISR (interrupt service routine) or interrupt
handler.
• Each device can get the attention of the
microcontroller based on the priority assign to it.
• Can ignore a device request for service
Polling
• The microcontroller continuously monitors the status
of a given device; when the status condition met, it
performs the service. After that, it moves on to
monitor the next device until each one is service.
• Cannot assign priority because it checks all devices in
a round-robin fashion.
• Cannot ignore a devices for service
Interrupt Service Routine (ISR)
Interrupt ROM Location (hex)
Power-on-Reset 0000
High Priority Interrupt 0008 (Default upon power-on
reset)
Low Priority Interrupt 0018
Interrupt Vector Table
Fixed Location in Memory
Step in Executing an Interrupt
1. It finishes the instruction it is executing and saves
the address of the next instruction (program
counter) on the stack
2. It jumps to a fixed location in memory (interrupt
vector table (IVT)). The IVT directs the
microcontroller to the address of the ISR
3. The microcontroller gets the address of the ISR
from the IVT and jumps to it. It start to execute
the interrupt service subroutine until it reaches
the last instruction of the subroutine - RETFIE
(Return from Interrupt Exit)
4. Upon executing the RETFIE instruction, the
microcontroller returns to the place where it was
interrupted
Sources of Interrupt
• Each Timers
• 3 interrupts for external hardware. Pin RB0 (INT0),
RB1 (INT1) and RB2 (INT2)
• 2 interrupts for serial communication (Receive and
Transmit)
• The PORTB-Change interrupt (RB4-RB7)
• The ADC
• The CCP
Enable and Disable an Interrupt
BSF INTCON,GIE
BCF INTCON,GIE
Timer Interrupts
Interrupt Flag Bit Register Enable Bit Register
Timer0 TMR0IF INTCON TMR0IE INTCON
Timer1 TMR1IF PIR1 TMR1IE PIE1
Timer2 TMR2IF PIR1 TMR3IE PIE1
Timer3 TMR3IF PIR3 TMR3IE PIE2
Timer Interrupt Flag Bits and Associated Registers
INTCON Register with Timer0 Interrupt Enable and Interrupt Flag
Interrupt vector to control the ISR
Because C18 does not place ISR at IVT automatically, we use
ASM instruction GOTO at IV to transfer control to ISR
#pragma code high_vector=0x0008 //High priority int location
void My_HiVect_int(void)
{
_asm
GOTO my_isr
_endasm
}
#pragma code //end of code
Redirect from 0008 to another program to find interrupt source
and the ISR
#pragma interrupt my_isr //interrupt is a reserved word
void my_isr(void)
{
//C18 places RETFIE here automatically due to interrupt
//keyword
Note : “pragma” , “code” and “interrupts” reserved keyword
EX. Use T0 and T1 to generate square-wave on pins RB1
and RB7, while data being transfer from PC to PD.
#include <P18f458.h>
#define MyPB1bit PORTBbits.RB1 //input switch
#define MyPB1bit PORTBbits.RB7 //input switch
void T0_ISR(void);
void T1_ISR(void);
#pragma interrupt my_isr
void chk_isr(void)
{
If(INTCONbits.TMR0IF==1) //T0 causes int ?
T0_ISR //yes, execute T0 ISR
If(INTCONbits.TMR1IF==1) //T1 causes int ?
T1_ISR //yes, execute T0 ISR
}
#pragma code My_HiPrio=0x0008 //High priority int loc
void My_HiPrio_int(void)
{
_asm
GOTO chk_isr
_endasm
}
#pragma code
void main(void)
{
TRISBbits.TRISB1=0; //PB1 as output;
TRISBbits.TRISB7=0; //PB7 as output;
TRISC = 0xFF //PC as intput;
TRISD = 0x00 //PD as output;
T0CON = 0x00; //T0, 16-bit , no pre-scale
TMR0H = 0x35;
TMR0L = 0x00;
T1CON = 0x08; //T1, 16-bit , no pre-scale
TMR0H = 0x35;
TMR0L = 0x00;
INTCONbits.TMR0IF=0; //clear TF0;
PIR1bits.TMR1IF=0; //clear TF1;
INTCONbits.TMR0IE=1; //enable T0 int;
INTCONbits.TMR1IE=1; //enable T1 int;
INTCONbits.TMR0ON=1; //turn on T0;
INTCONbits.TMR1ON=1; //turn on T1;
INTCONbits.PEIE=1; //enable all pheperal int;
INTCONbits.GIE=1; //enable all int globally;
While(1) //keep looping until int occur
{
PORTD=PORTC //send data fromPC to PD
}
}
void T0_ISR(void)
{
myPB1bit=~myPB1bit; //toggle PB.1;
TMR0H = 0x35;
TMR0L = 0x00;
INTCONbits.TMR0IF=0; //clear TF0;
}
void T1_ISR(void)
{
myPB7bit=~myPB7bit; //toggle PB.7;
TMR1H = 0x35;
TMR1L = 0x00;
INTCONbits.TMR1IF=0; //clear TF1;
}
External Hardware Interrupts
Interrupt Flag Bit Register Enable Bit Register
INT0(RB0) INT0IF INTCON INT0IE INTCON
INT1 (RB1) INT1IF INTCON3 INT1IE INTCON3
INT2 (RB2) INT2IF INTCON3 INT2IE INTCON3
Hardware Interrupt Flag Bits and Associated Registers
Positive-edge-
triggered interrupt
EX. When ↑ (rise-edge) on pin INT0, LED will toggle.
#include <P18f458.h>
#define Mybit PORTBbits.RB7
void chk_isr(void);
void INT0_ISR(void);
#pragma interrupt chk_isr
void chk_isr(void)
{
If(INTCONbits.INT0IF==1 ) //INT0 causes int ?
INT0_ISR(); //yes, execute INT0 prg
}
#pragma code My_HiPrio_Int=0x08 //high-priority int loc
void My_HiPrio_int(void)
{
_asm
GOTO chk_isr
_endasm
}
#pragma code
void main(void)
{
TRISBbits.TRISB7=0; //PB7 as output;
TRISBbits.TRISB0=1; //PB1 as input;
TRISC = 0xFF //PC as intput;
TRISD = 0x00 //PD as output;
INTCONbits.INT0IF=0; //clear TF0;
INTCONbits.INT0IE=1 //enable T0 interrupt
INTCONbits.GIE=1; //enable all int globally;
While(1) //keep looping until int occur
{
PORTD=PORTC //send data fromPC to PD
}
}
void INT0_ISR(void)
{
mybit=~mybit; //toggle mybit;
INTCONbits.INT0IF=0; //clear INT0 flag;
}
Serial Communication Interrupts
Interrupt Flag Bit Register Enable Bit Register
TXIF TXIF PIR1 TXIE PIE1
(Trasmit)
RCIF RCIF PIR1 RCIE PIE1
(Receive)
Serial Port Interrupt Flag Bits and Associated Registers
PIE1 Register Bits Holding TXIE and RCIE
EX. Get data from PD and send to TXREG continuously while
incoming data from serial is send to PB. Assume XTAL 10
MHz and baud rate is 9600.
#include <P18f458.h>
void chk_isr(void);
void TX_ISR(void);
void RC_ISR(void);
#pragma code My_HiPrio_Int=0x08 //high-priority int loc
void My_HiPrio_int(void)
{
_asm
GOTO chk_isr
_endasm
}
#pragma code
#pragma interrupt chk_isr //used for high prioity int
void chk_isr(void)
{
If(PIR1bits.TXIF==1) //Tx causes int ?
TX_ISR(); /yes, execute Tx prg
If(PIR1bits.RCIF==1) //RC causes int ?
RC_ISR(); /yes, execute RC prg
}
void main(void)
{
TRISD = 0xFF //PD as intput;
TRISB = 0x00 //PB as output;
TRISBbits.TRISC6=0; //TX pin output;
TRISBbits.TRISC7=1; //RC pin input;
TXSTA=0x20 //low baud rate, 8-bit
SPBRG=15 //9600 baud rate (XTA =10
RCSTAbits.CREN=1;
RCSTAbits.SPEN=1;
TXSTAbits.TXEN=1;
PIE1bits.RCIE= 1; //enable RC int
PIE1bits.TXIE= 1; //enable TX int
INTCONbits.PIE=1; //enable peripheral int;
INTCONbits.GIE=1; //enable all int globally;
While(1); //keep looping until int occur
}
void TX_ISR(void)
{
TXREG=PORTD;
}
void RC_ISR(void)
{
PORTB=RCREG;
}
}
PORTB-Change Interrupt
Differences Between External Hardware and
PORTB-Change Interrupt
External Hardware PORTB-Change
This (RB0-RB2) interrupts has its own pin Use all four (RB4-RB7) and considered to be
and is independent each other a single interrupt even though it can use up
to four pins
Has it own flag (INTxIF) and independent Single flag only (RBIF)
each other
Can be programmed to trigger on the Cause an interrupt either pin changes
negative or positive edge status from HIGH-LOW or LOW-HIGH
EX. Connect SW1 and SW2 to pins RB4 and RB5
respectively. SW1 and SW2 will change LED1 and LED2.
#include <P18f458.h>
#define LED1 PORTCbits.RC1
#define LED2 PORTCbits.RC2
void chk_isr(void);
void RBINT_ISR(void);
#pragma code My_HiPrio_Int=x08 //high-priority int loc
void My_HiPrio_int(void)
{
_asm
GOTO chk_isr
_endasm
}
#pragma code
#pragma interrupt chk_isr //used for high prio int
void chk_isr(void)
{
If(INTCONbits.RBIF==1 //RBIF causes int ?
RBINT_ISR(); //yes, execute INT0 prg
}
void main(void)
{
TRISCbits.TRISC1=0; //PC4 as output;
TRISCbits.TRISC2=0; //PC5 as ouput;
TRISBbits.TRISB4=1; //PB4 input for int;
TRISBbits.TRISB5=1; //PB5 input for int;
INTCONbits.RBIF=0; //clear RIF;
INTCONbits.RBIE=1; //enable RB int;
INTCONbits.GIE=1; //enable all int globally;
}
void RBINT_ISR(void)
{
LED1 = PORTBbits.RB4;
LED2 = PORTBbits.RB5;
INTCONbits.RBIF=0; //clear RBIF flag;
}
Interrupt Priority
Interrupt ROM Location (hex)
Power-on-Reset 0000
High Priority Interrupt 0008 (Default upon power-on reset)
Low Priority Interrupt 0018
RCON Register
IPR1 Peripheral Interrupt Priority Register