How to Use Interrupts in PIC16F877A Microcontroller - Cách sử dụng ngắt trong Vi điều khiển PIC16F877A
QC
How to Use Interrupts in PIC16F877A Microcontroller - Cách sử dụng ngắt trong Vi điều khiển PIC16F877A
Thursday, April 7, 2022
Trong hướng dẫn này, chúng ta sẽ học cách sử dụng Ngắt ngoài trong Vi điều khiển PIC và tại sao / ở đâu chúng ta sẽ cần chúng. Đây là một phần của chuỗi Hướng dẫn PIC trong đó chúng ta bắt đầu học Vi điều khiển PIC từ đầu; do đó, hướng dẫn này giả định rằng bạn đã quen với cách lập trình MCU PIC bằng MPLABX và cách giao tiếp màn hình LCD với PIC. Nếu không, vui lòng quay trở lại các liên kết tương ứng của họ và đọc hết chúng, vì tôi sẽ bỏ qua hầu hết các thông tin đã được đề cập ở đó.
Materials Required:
PIC16F877A Perf Board
16x2 LCD Display
Push Button
Connecting Wires
Bread Board
PicKit 3
What are interrupts and where to use them:
Trước khi tìm hiểu cách lập trình ngắt của vi điều khiển PIC, chúng ta hãy hiểu Ngắt thực sự là gì và chúng ta cần sử dụng chúng ở đâu. Hơn nữa, có rất nhiều kiểu ngắt trong Vi điều khiển và PIC16F877A có khoảng 15 kiểu ngắt trong số đó. Hãy để chúng tôi không nhầm lẫn tất cả chúng trong đầu của chúng tôi bây giờ.
Cho nên! ngắt trong Vi điều khiển là gì?
Như chúng ta đã biết vi điều khiển được sử dụng để thực hiện một tập hợp các kích hoạt được xác định trước (được lập trình) để kích hoạt các kết quả đầu ra cần thiết dựa trên đầu vào. Tuy nhiên, trong khi Bộ vi điều khiển của bạn bận thực thi một đoạn mã, có thể xảy ra tình huống khẩn cấp mà đoạn mã khác của bạn cần được chú ý ngay lập tức. Đoạn mã khác cần được chú ý ngay lập tức này nên được coi là một đoạn mã ngắt.
Ví dụ: Hãy để chúng tôi xem xét rằng bạn đang chơi trò chơi yêu thích của mình trên điện thoại di động và bộ điều khiển (giả định) bên trong điện thoại của bạn đang bận rộn ném tất cả đồ họa cần thiết để bạn thưởng thức trò chơi. Nhưng, đột nhiên bạn gái của bạn gọi đến số của bạn. Bây giờ, điều tồi tệ nhất xảy ra là bộ điều khiển điện thoại di động của bạn bỏ qua cuộc gọi của bạn gái vì bạn đang bận chơi game. Để ngăn cơn ác mộng này xảy ra, chúng tôi sử dụng một thứ gọi là ngắt.
Các ngắt này sẽ luôn là danh sách hoạt động cho một số hành động cụ thể xảy ra và khi chúng xảy ra, chúng thực thi một đoạn mã và sau đó quay trở lại chức năng bình thường. Đoạn mã này được gọi là quy trình dịch vụ ngắt (ISR). Một dự án thực tế bắt buộc phải ngắt là “Mạch đồng hồ đo tốc độ kỹ thuật số và đồng hồ đo tốc độ sử dụng vi điều khiển PIC”
Trong Vi điều khiển có hai loại ngắt chính. Chúng là Ngắt ngoài và Ngắt trong. Các ngắt bên trong xảy ra bên trong Microntroller để thực hiện một tác vụ, ví dụ như Ngắt bộ hẹn giờ, Ngắt bộ ADC, v.v. Những ngắt này được phần mềm kích hoạt để hoàn thành hoạt động Bộ định thời hoặc hoạt động ADC tương ứng.
Ngắt bên ngoài là ngắt có thể được kích hoạt bởi người dùng. Trong chương trình này, chúng ta sẽ học cách sử dụng Ngắt ngoài bằng cách sử dụng nút nhấn để kích hoạt ngắt. Chúng tôi sẽ sử dụng một màn hình LCD để hiển thị các số tăng dần từ 0 đến 1000 và khi một ngắt được kích hoạt, chúng tôi phải thông báo về nó từ ISR của Quy trình Dịch vụ Ngắt và sau đó tiếp tục quay lại để tăng các số.
Circuit Diagram and Explanation:
Sơ đồ mạch để sử dụng ngắt PIC16F877 được cho trong hình trên. Bạn chỉ cần kết nối màn hình LCD với PIC như chúng tôi đã làm trong hướng dẫn giao tiếp màn hình LCD.
Bây giờ để kết nối chân ngắt, chúng ta nên xem biểu dữ liệu để biết chân nào của PIC được sử dụng cho ngắt ngoài. Trong trường hợp của chúng tôi trong PIC16F877A, chân thứ 33 RBO / INT được sử dụng cho ngắt bên ngoài. Bạn không thể sử dụng bất kỳ ghim nào khác ngoài ghim này. Kết nối chân cho sơ đồ mạch này được hiển thị trong bảng dưới đây.
S.No:
Pin Number
Pin Name
Connected to
1
21
RD2
RS of LCD
2
22
RD3
E of LCD
3
27
RD4
D4 of LCD
4
28
RD5
D5 of LCD
5
29
RD6
D6 of LCD
6
30
RD7
D7 of LCD
7
33
RBO/INT
Push button
Chúng tôi đã bật điện trở kéo lên bên trong trên Cổng B, do đó chúng tôi có thể kết nối trực tiếp chân RB0 với đất thông qua một nút Đẩy. Vì vậy, bất cứ khi nào chân này bị THẤP, một ngắt sẽ được kích hoạt.
Các kết nối có thể được thực hiện trên bảng bánh mì như hình dưới đây.
Nếu bạn đã theo dõi các hướng dẫn của chúng tôi, bạn nên làm quen với bảng Perf này mà tôi đã sử dụng ở đây. Nếu không, bạn không cần phải suy nghĩ nhiều về nó, chỉ cần làm theo sơ đồ mạch và bạn sẽ có được mọi thứ hoạt động.
Simulation of Interrupts in PIC Microcontroller:
Mô phỏng cho dự án này được thực hiện bằng Proteus.
Khi bạn mô phỏng dự án, bạn sẽ thấy một dãy số được tăng dần trên màn hình LCD. Điều này xảy ra bên trong vòng lặp chính và bất cứ khi nào nhấn nút nhấn, màn hình LCD sẽ hiển thị rằng nó đã được đưa vào ISR. Bạn có thể thực hiện các sửa đổi của mình trong mã và thử kiểm tra nó tại đây.
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
//LCD Functions Developed by Circuit Digest.
void Lcd_SetBit(char data_bit) //Based on the Hex value Set the Bits of the Data Lines
{
if(data_bit& 1)
D4 = 1;
else
D4 = 0;
if(data_bit& 2)
D5 = 1;
else
D5 = 0;
if(data_bit& 4)
D6 = 1;
else
D6 = 0;
if(data_bit& 8)
D7 = 1;
else
D7 = 0;
}
void Lcd_Cmd(char a)
{
RS = 0;
Lcd_SetBit(a); //Incoming Hex value
EN = 1;
__delay_ms(4);
EN = 0;
}
void Lcd_Clear()
{
Lcd_Cmd(0); //Clear the LCD
Lcd_Cmd(1); //Move the curser to first position
}
void Lcd_Set_Cursor(char a, char b)
{
char temp,z,y;
if(a== 1)
{
temp = 0x80 + b - 1; //80H is used to move the curser
z = temp>>4; //Lower 8-bits
y = temp & 0x0F; //Upper 8-bits
Lcd_Cmd(z); //Set Row
Lcd_Cmd(y); //Set Column
}
else if(a== 2)
{
temp = 0xC0 + b - 1;
z = temp>>4; //Lower 8-bits
y = temp & 0x0F; //Upper 8-bits
Lcd_Cmd(z); //Set Row
Lcd_Cmd(y); //Set Column
}
}
void Lcd_Start()
{
Lcd_SetBit(0x00);
for(int i=1065244; i<=0; i--) NOP();
Lcd_Cmd(0x03);
__delay_ms(5);
Lcd_Cmd(0x03);
__delay_ms(11);
Lcd_Cmd(0x03);
Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
Lcd_Cmd(0x08); //Select Row 1
Lcd_Cmd(0x00); //Clear Row 1 Display
Lcd_Cmd(0x0C); //Select Row 2
Lcd_Cmd(0x00); //Clear Row 2 Display
Lcd_Cmd(0x06);
}
void Lcd_Print_Char(char data) //Send 8-bits through 4-bit mode
{
char Lower_Nibble,Upper_Nibble;
Lower_Nibble = data&0x0F;
Upper_Nibble = data&0xF0;
RS = 1; // => RS = 1
Lcd_SetBit(Upper_Nibble>>4); //Send upper half by shifting by 4
EN = 1;
for(int i=2130483; i<=0; i--) NOP();
EN = 0;
Lcd_SetBit(Lower_Nibble); //Send Lower half
EN = 1;
for(int i=2130483; i<=0; i--) NOP();
EN = 0;
}
void Lcd_Print_String(char *a)
{
int i;
for(i=0;a[i]!='\0';i++)
Lcd_Print_Char(a[i]); //Split the string using pointers and call the Char function
}
/*****End of LCD Functions*****/
/****Interrupt function ****/
void interrupt ISR_example()
{
if (INTF==1) //External Interrupt detected
{
Lcd_Clear();
Lcd_Set_Cursor(1,1);
Lcd_Print_String(" Entered ISR");
INTF = 0; // clear the interrupt flag after done with it
__delay_ms(2000);
Lcd_Clear();
}
}
/****End of Interrupt Function****/
int number =0;
char ch1,ch2,ch3,ch4;
int main()
{
TRISD = 0x00; //PORTD declared as output for interfacing LCD
TRISB0 = 1; //DEfine the RB0 pin as input to use as interrupt pin