Bài 3: Ngắt ngoài (interrupt external)
Trong dspic33fj32mc202 hỗ trợ 3 kênh ngắt ngoài: INT0, INT1 và INT2.
Với INT0, Chip hỗ trợ ngắt trên chân INT0 là chân số 16.
Với INT1 và INT2, chip hỗ trợ ngắt ngoài trên bất kì chân nào từ
RP0 đến RP15, được cấu hình bởi bit INT1R và INT2R trong các thanh ghi RPINR0 và RPINR1.
Ta xét ví dụ để sử dụng 3 ngắt ngoài: Dùng 3 ngắt ngoài để đổi trạng thái 3 led đơn.
Ta thực hiện mô phỏng như sau:
Ban đầu, ta phải cấu hình tần số dao động cho chip:
_FOSCSEL(FNOSC_FRC); // sử dụng dao động nội FRC 7.37MHz
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF); // tắt WDT
ở trong hàm main ta phải thực hiện các lệnh chờ để kích hoạt dao động:
__builtin_write_OSCCONH(0x01);
__builtin_write_OSCCONL(0x01);
Tiếp theo, ta cấu hình vào ra cho các chân sử dụng, với các chân nối với led được cấu hình output, các chân sử dụng ngắt cấu hình input:
_TRISB7 = 1;
_TRISB11 = 1;
_TRISB14 = 1;
_TRISB0 = 0;
_TRISB1 = 0;
_TRISB2 = 0;
_LATB0 = 1;
_LATB1 = 1;
_LATB2 = 1;
Tiếp theo ta cấu hình để sử dụng các ngắt, đối với ngắt INT0, ta cần cấu hình 3 bit:
INTCON2bits.INT0EP = 0 : ngắt cạnh tiêu cực // cạnh xuống
1: ngắt cạnh tích cực // cạnh lên
IFS0bits.INT0IF = 0: yêu cầu xảy ra gián đoạn (ngắt có hiệu lực)
= 1: không yêu cầu gián đoạn (ngắt không có hiệu lực)
IEC0bits.INT0IE = 0: cho phép ngắt
= 1: không cho phép ngắt
ta cấu hình như sau:
void INT0init()
{
_INT0EP = 1; //ngat canh len
_INT0IF = 0; //reset flag
_INT0IE = 1; //enable interrupt
}
Đối với ngắt INT1 và INT2, ta cần cấu hình thêm bit lựa chọn chân được sử dụng ngắt
void INT1init()
{
_INT1R = 11; //set pin RP11 as interrupt 1
_INT1EP = 1; //ngat canh len
_INT1IF = 0; /*Reset INT1 interrupt flag */
_INT1IE = 1; /*Enable INT1 Interrupt Service Routine */
}
void INT2init()
{
_INT2R = 14; //set pin RP14 as interrupt 1
_INT2EP = 1; //ngat canh len
_INT2IF = 0; /*Reset INT1 interrupt flag */
_INT2IE = 1; /*Enable INT1 Interrupt Service Routine */
}
Trong hàm ngắt, ta thực hiện đảo xung của các chân nối với led:
void __attribute__((interrupt, no_auto_psv)) _INT0Interrupt(void)
{
_LATB0 = ~_LATB0;
_INT0IF = 0; //reset flag
}
void __attribute__((interrupt, no_auto_psv)) _INT1Interrupt(void)
{
_LATB1 = ~_LATB1;
_INT1IF = 0; //reset flag
}
void __attribute__((interrupt, no_auto_psv)) _INT2Interrupt(void)
{
_LATB2 = ~_LATB2;
_INT2IF = 0; //reset flag
}
Ta có full code như sau:
#include<p33fj32mc202.h>
_FOSCSEL(FNOSC_FRC);
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF);
void INT0init();
void INT1init();
void INT2init();
void __attribute__((interrupt, no_auto_psv)) _INT0Interrupt(void)
{
_LATB0 = ~_LATB0;
_INT0IF = 0; //reset flag
}
void __attribute__((interrupt, no_auto_psv)) _INT1Interrupt(void)
{
_LATB1 = ~_LATB1;
_INT1IF = 0; //reset flag
}
void __attribute__((interrupt, no_auto_psv)) _INT2Interrupt(void)
{
_LATB2 = ~_LATB2;
_INT2IF = 0; //reset flag
}
int main()
{
// Initiate Clock Switch to Internal FRC with PLL (NOSC = 0b001)
__builtin_write_OSCCONH(0x01);
__builtin_write_OSCCONL(0x01);
// Wait for Clock switch to occur
while (OSCCONbits.COSC!= 0b001);
// Wait for PLL to lock
while(OSCCONbits.LOCK!= 1) {};
INT0init();
INT1init();
INT2init();
_TRISB7 = 1;
_TRISB11 = 1;
_TRISB14 = 1;
_TRISB0 = 0;
_TRISB1 = 0;
_TRISB2 = 0;
_LATB0 = 1;
_LATB1 = 1;
_LATB2 = 1;
while(1)
{
}
}
void INT0init()
{
_INT0EP = 1; //ngat canh len
_INT0IF = 0; //reset flag
_INT0IE = 1; //enable interrupt
}
void INT1init()
{
_INT1R = 11; //set pin RP11 as interrupt 1
_INT1EP = 1; //ngat canh len
_INT1IF = 0; /*Reset INT1 interrupt flag */
_INT1IE = 1; /*Enable INT1 Interrupt Service Routine */
}
void INT2init()
{
_INT2R = 14; //set pin RP11 as interrupt 1
_INT2EP = 1; //ngat canh len
_INT2IF = 0; /*Reset INT1 interrupt flag */
_INT2IE = 1; /*Enable INT1 Interrupt Service Routine */
}
Với INT0, Chip hỗ trợ ngắt trên chân INT0 là chân số 16.
Với INT1 và INT2, chip hỗ trợ ngắt ngoài trên bất kì chân nào từ
RP0 đến RP15, được cấu hình bởi bit INT1R và INT2R trong các thanh ghi RPINR0 và RPINR1.
Ta xét ví dụ để sử dụng 3 ngắt ngoài: Dùng 3 ngắt ngoài để đổi trạng thái 3 led đơn.
Ta thực hiện mô phỏng như sau:
Ban đầu, ta phải cấu hình tần số dao động cho chip:
_FOSCSEL(FNOSC_FRC); // sử dụng dao động nội FRC 7.37MHz
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF); // tắt WDT
ở trong hàm main ta phải thực hiện các lệnh chờ để kích hoạt dao động:
__builtin_write_OSCCONH(0x01);
__builtin_write_OSCCONL(0x01);
Tiếp theo, ta cấu hình vào ra cho các chân sử dụng, với các chân nối với led được cấu hình output, các chân sử dụng ngắt cấu hình input:
_TRISB7 = 1;
_TRISB11 = 1;
_TRISB14 = 1;
_TRISB0 = 0;
_TRISB1 = 0;
_TRISB2 = 0;
_LATB0 = 1;
_LATB1 = 1;
_LATB2 = 1;
Tiếp theo ta cấu hình để sử dụng các ngắt, đối với ngắt INT0, ta cần cấu hình 3 bit:
INTCON2bits.INT0EP = 0 : ngắt cạnh tiêu cực // cạnh xuống
1: ngắt cạnh tích cực // cạnh lên
IFS0bits.INT0IF = 0: yêu cầu xảy ra gián đoạn (ngắt có hiệu lực)
= 1: không yêu cầu gián đoạn (ngắt không có hiệu lực)
IEC0bits.INT0IE = 0: cho phép ngắt
= 1: không cho phép ngắt
ta cấu hình như sau:
void INT0init()
{
_INT0EP = 1; //ngat canh len
_INT0IF = 0; //reset flag
_INT0IE = 1; //enable interrupt
}
Đối với ngắt INT1 và INT2, ta cần cấu hình thêm bit lựa chọn chân được sử dụng ngắt
void INT1init()
{
_INT1R = 11; //set pin RP11 as interrupt 1
_INT1EP = 1; //ngat canh len
_INT1IF = 0; /*Reset INT1 interrupt flag */
_INT1IE = 1; /*Enable INT1 Interrupt Service Routine */
}
void INT2init()
{
_INT2R = 14; //set pin RP14 as interrupt 1
_INT2EP = 1; //ngat canh len
_INT2IF = 0; /*Reset INT1 interrupt flag */
_INT2IE = 1; /*Enable INT1 Interrupt Service Routine */
}
Trong hàm ngắt, ta thực hiện đảo xung của các chân nối với led:
void __attribute__((interrupt, no_auto_psv)) _INT0Interrupt(void)
{
_LATB0 = ~_LATB0;
_INT0IF = 0; //reset flag
}
void __attribute__((interrupt, no_auto_psv)) _INT1Interrupt(void)
{
_LATB1 = ~_LATB1;
_INT1IF = 0; //reset flag
}
void __attribute__((interrupt, no_auto_psv)) _INT2Interrupt(void)
{
_LATB2 = ~_LATB2;
_INT2IF = 0; //reset flag
}
Ta có full code như sau:
#include<p33fj32mc202.h>
_FOSCSEL(FNOSC_FRC);
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF);
void INT0init();
void INT1init();
void INT2init();
void __attribute__((interrupt, no_auto_psv)) _INT0Interrupt(void)
{
_LATB0 = ~_LATB0;
_INT0IF = 0; //reset flag
}
void __attribute__((interrupt, no_auto_psv)) _INT1Interrupt(void)
{
_LATB1 = ~_LATB1;
_INT1IF = 0; //reset flag
}
void __attribute__((interrupt, no_auto_psv)) _INT2Interrupt(void)
{
_LATB2 = ~_LATB2;
_INT2IF = 0; //reset flag
}
int main()
{
// Initiate Clock Switch to Internal FRC with PLL (NOSC = 0b001)
__builtin_write_OSCCONH(0x01);
__builtin_write_OSCCONL(0x01);
// Wait for Clock switch to occur
while (OSCCONbits.COSC!= 0b001);
// Wait for PLL to lock
while(OSCCONbits.LOCK!= 1) {};
INT0init();
INT1init();
INT2init();
_TRISB7 = 1;
_TRISB11 = 1;
_TRISB14 = 1;
_TRISB0 = 0;
_TRISB1 = 0;
_TRISB2 = 0;
_LATB0 = 1;
_LATB1 = 1;
_LATB2 = 1;
while(1)
{
}
}
void INT0init()
{
_INT0EP = 1; //ngat canh len
_INT0IF = 0; //reset flag
_INT0IE = 1; //enable interrupt
}
void INT1init()
{
_INT1R = 11; //set pin RP11 as interrupt 1
_INT1EP = 1; //ngat canh len
_INT1IF = 0; /*Reset INT1 interrupt flag */
_INT1IE = 1; /*Enable INT1 Interrupt Service Routine */
}
void INT2init()
{
_INT2R = 14; //set pin RP11 as interrupt 1
_INT2EP = 1; //ngat canh len
_INT2IF = 0; /*Reset INT1 interrupt flag */
_INT2IE = 1; /*Enable INT1 Interrupt Service Routine */
}
Nhận xét
Đăng nhận xét