ngắt trong vi xử lý 8051

Màu nền
Font chữ
Font size
Chiều cao dòng

Mục tiêu

Kết thúc bài học này, bạn có thể:

Ø  Phân biệt cơ chế ngắt với hỏi vòng

Ø  Nắm rõ các loại ngắt trong 8051

·  Ngắt timer/counter

·    Ngắt ngoài

·     Ngắt truyền thông nối tiếp

Ø  Lập trình các ngắt

·        Trình phục vụ ngắt là gì?

·        Cho phép ngắt và cấm ngắt

·        Thiết lập mức ưu tiên của các ngắt

Giới thiệu

            Ngắt (Interrupt) - như tên của nó, là một số sự kiện khẩn cấp bên trong hoặc bên ngoài bộ vi điều khiển xảy ra, buộc vi điều khiển tạm dừng thực hiện chương trình hiện tại, phục vụ ngay lập tức nhiệm vụ mà ngắt yêu cầu – nhiệm vụ này gọi là trình phục vụ ngắt (ISR:Interrupt Service Routine).

Trong bài này ta tìm hiểu khái niệm ngắt và lập trình các ngắt trong bộ vi điều khiển 8051.

1. Các ngắt của 8051

1.1  Phân biệt cơ chế ngắt với hỏi vòng

Lấy ví dụ:Bộ vi điều khiển đóng vai trò như một vị bác sĩ, các thiết bị kiểm soát bởi vi điều khiển được coi như các bệnh nhân cần được bác sĩ phục vụ.

Bình thường, vị bác sĩ sẽ hỏi thăm lần lượt từng bệnh nhân, đến lượt bệnh nhân nào được hỏi thăm nếu có bệnh thì sẽ được bác sĩ phục vụ, xong lại đến lượt bệnh nhân khác, và tiếp tục đến hết. Điều này tương đương với phương pháp thăm dò - hỏi vòng (Polling) trong vi điều khiển.

Cứ như thế, nếu chúng ta có 10 bệnh nhân, thì bệnh nhân thứ 10 dù muốn hay không cũng phải xếp hàng chờ đợi 09 bệnh nhân trước đó. Giả sử tờng hợp bệnh nhân thứ 10 cần cấp cứu thì sao? Anh ta sẽ gặp nguy cấp trước khi đến lượt hỏi thăm của bác sĩ mất! L Nhưng, nếu anh ta sử dụng phương pháp “ngắt” thì mọi chuyện sẽ ổn ngay. Lúc đó vị bác sĩ sẽ ngừng mọi công việc hiện tại của mình, và tiến hành phục vụ trường hợp khẩn cấp này ngay lập tức, xong việc bác sĩ lại trở về tiếp tục công việc đang dở. Điều này tương đương với phương pháp ngắt (Interrupts) trong vi điều khiển.

            Trở lại với bộ vi điều khiển của chúng ta: 1 bộ vi điều khiển có thể phục vụ cho nhiều thiết bị, có 2 cách để thực hiện điều này đó là sử dụng các ngắt (Interrupts) và thăm dò(polling):

Ø  Trong phương pháp sử dụng ngắt: mỗi khi có một thiết bị bất kỳ cần được phục vụ thì nó báo cho bộ vi điều khiển bằng cách gửi một tín hiệu ngắt. Khi nhận được tín hiệu ngắt thì bộ vi điều khiển ngừng tất cả những gì nó đang thực hiện để chuyển sang phục vụ thiết bị gọi ngắt. Chương trình ngắt được gọi là trình phục vụ ngắt ISR(Interrupt Service Routine) hay còn gọi là trình quản lý ngắt (Interrupt handler). Sau khi phục vụ ngắt xong, bộ vi xử lý lại quay trở lại điểm bị ngắt trước đó và tiếp tục thực hiện công việc.

Ø  Trong phương pháp thăm dò: bộ vi điều khiển kiểm tra liên tục tình trạng của tất cả các thiết bị, nếu thiết bị nào có yêu cầu thì nó dừng lại phục vụ thiết bị đó. Sau đó nó tiếp tục kiểm tra tình trạng của thiết bị kế tiếp cho đến hết. Phương pháp thăm dò rất đơn giản, nhưng nó lại rất lãng phí thời gian để kiểm tra các thiết bị kể cả khi thiết bị đó không cần phục vụ. Trong trường hợp có quá nhiều thiết bị thì phương án thăm dò tỏ ra không hiệu quả, gây ra chậm trễ cho các thiết bị cần phục vụ.

Điểm mạnh của phương pháp ngắt là:

Ø  Bộ vi điều khiển có thể phục vụ được rất nhiều thiết bị (tất nhiên là không tại cùng một thời điểm). Mỗi thiết bị có thể nhận được sự chú ý của bộ vi điều khiển dựa trên mức ưu tiênđược gán cho nó. Đối với phương pháp thăm dò thì không thể gán mức ưu tiên cho các thiết bị vì nó kiểm tra tất cả mọi thiết bị theo kiểu hỏi vòng

Ø  Quan trọng hơn, trong phương pháp ngắt thì bộ vi điều khiển còn có thể che(làm lơ) một yêu cầu phục vụ của thiết bị. Điều này lại một lần nữa không thể thực hiện được trong phương pháp thăm dò.

Ø  Lý do quan trọng nhất mà phương pháp ngắt được ưu chuộng là vì nó không lãng phí thời gian cho các thiết bị không cần phục vụ. Còn phương pháp thăm dò làm lãng phí thời gian của bộ vi điều khiển bằng cách hỏi dò từng thiết bị kể cả khi chúng không cần phục vụ.

Ví dụ trong các bộ định thời được bàn đến ở các bài trước ta đã dùng một vòng lặp kiểm tra và đợi cho đến khi bộ định thời quay trở về 0. Trong ví dụ đó, nếu sử dụng ngắt thì ta không cần bận tâm đến việc kiểm tra cờ bộ định thời, do vậy không lãng phí thời gian để chờ đợi, trong khi đó ta có thể làm việc khác có ích hơn.

1.2 Sáu ngắt trong 8051

            Thực tế chỉ có 5ngắt dành cho người dùng trong 8051 nhưng các nhà sản xuất nói rằng có 6 ngắt vì họ tính cả lệnh RESET. Sáu ngắt của 8051 được phân bố như sau:

1.      RESET: Khi chân RESET được kích hoạt từ 8051, bộ đếm chương trình nhảy về địa chỉ 0000H.  Đây là địa chỉ bật lại nguồn.

2.      2 ngắt dành cho các bộ định thời: 1 cho Timer0 và 1 cho Timer1. Địa chỉ tương ứng của các ngắt này là 000BH001BH.

3.      2 ngắt dành cho các ngắt phần cứng bên ngoài: chân 12 (P3.2) và 13 (P3.3) của cổng P3 là các ngắt phần cứng bên ngoài INT0INT1 tương ứng. Địa chỉ tương ứng của các ngắt ngoài này là 0003H0013H.

4.      Truyền thông nối tiếp: có 1 ngắt chung cho cả nhận và truyền dữ liệu nối tiếp. Địa chỉ của ngắt này trong bảng vector ngắt là 0023H.

1.3 Trình phục vụ ngắt

            Đối với mỗi ngắt thì phải có một trình phục vụ ngắt (ISR) hay trình quản lý ngắt để đưa ra nhiệm vụ cho bộ vi điều khiển khi được gọi ngắt. Khi một ngắt được gọi thì bộ vi điều khiển sẽ chạy trình phục vụ ngắt. Đối với mỗi ngắt thì có một vị trí cố định trong bộ nhớ để giữ địa chỉ ISR của nó. Nhóm vị trí bộ nhớ được dành riêng để lưu giữ địa chỉ của các ISR được gọi là bảng vector ngắt. Xem Hình 1.

Hình 1:Bảng vector ngắt của 8051.

Trong lập trình C trên Keil c cho 8051, chúng ta khai báo trình phục vụ ngắttheo cấu trúc sau:

Void  Name(void) interrupt X                 //( X: là số thứ tự của ngắt

         // chương trình phục vụ ngắt

Khi đó địa chỉ ngắt sẽ được tự động tính bằng:

Interrupt Address = (X * 8) + 3

1.4 Quy trình khi thực hiện một ngắt

            Khi kích hoạt một ngắt bộ vi điều khiển thực hiện các bước sau:

Ø  Nó hoàn thành nốt lệnh đang thực hiện và lưu địa chỉ của lệnh kế tiếpvào ngăn xếp.

Ø  Nó cũng lưu tình trạng hiện tạicủa tất cả các ngắt.

Ø  Nó nhảy đến một vị trí cố định trong bộ nhớ được gọi là bảng vector ngắt, nơi lưu giữ địa chỉ của một trình phục vụ ngắt.

Ø  Bộ vi điều khiển nhận địa chỉ ISR từ bảng vector ngắt và nhảy tới đó. Nó bắt đầu thực hiện trình phục vụ ngắt cho đến lệnh cuối cùng của ISRvà trở về chương trình chính từ ngắt.

Ø  Khi bộ vi điều khiển quay trở về nơi nó đã bị ngắt. Trước hết nó nhận địa chỉ của bộ đếm chương trình PC từ ngăn xếp bằng cách kéo 02 byte trên đỉnh của ngăn xếp vào PC. Sau đó bắt đầu thực hiện tiếp các lệnh từ địa chỉ đó.

1.5 Các bước cho phép và cấm ngắt

            Khi bật lại nguồn thì tất cả mọi ngắt đều bị cấm(bị che), có nghĩa là không có ngắt nào được bộ vi điều khiển đáp ứng trừ khi chúng được kích hoạt.

Các ngắt phải được kích hoạt bằng phần mềm để bộ vi điều khiển đáp ứng chúng. Có một thanh ghi được gọi là thanh ghi cho phép ngắt IE (Interrupt Enable) – ở địa chỉ A8H chịu trách nhiệm về việc cho phép và cấm các ngắt. Hình 2 trình bày chi tiết về thanh ghi IE.

Hình 2: Thanh ghi cho phép ngắt IE.            Để cho phép một ngắt ta phải thực hiện các bước sau:

Ø  Nếu EA = 0 thì không có ngắt nào được đáp ứng cho dù bit tương ứng của nó trong IE có giá trị cao. Bit D7 - EA của thanh ghi IEphải được bật lên cao để cho phép các bit còn lại của thanh ghi hoạt động được

Ø  Nếu EA = 1 thì tất cả mọi ngắt đều được phép và sẽ được đáp ứng nếu các bit tương ứng của chúng trong IEmức cao.

Để hiểu rõ điểm quan trọng này ta hãy xét ví dụ 1.

Ví dụ 1:

            Hãy lập trình cho 8051:

a) cho phép ngắt nối tiếp, ngắt Timer0ngắt phần cứng ngoài 1(EX1)

b) cấm ngắt Timer0

c) sau đó trình bày cách cấm tất cả mọi ngắtchỉ bằng một lệnh duy nhất.

Lời giải:

#include<at89x51.h>                     

main()         

            IE=0x96;        //1001 0110: lệnh này tương đương với 4 lệnh phía dưới

            EA=1;             //Cho phép sử dụng ngắt

            ES=1;             //Cho phép ngắt cổng nối tiếp

            ET0=1;           //Cho phép ngắt timer0

            EX1=1;          //Cho phép ngắt ngoài

            ET0=0;           //Cấm ngắt timer

EA=0;             //Cấm tất cả các ngắ

            while(1)              

                        //Chương trìn

2. Lập trình các ngắt bộ định thờ

            Trong các bài trước ta đã biết cách sử dụng các bộ định thời Timer0Timer1 bằng phương pháp thăm dò. Trong phần này ta sẽ sử dụng các ngắtđể lập trình cho các bộ định thời của 8051

2.1 Cờ quay về 0 của bộ định thời và ngắt

            Chúng ta đã biết rằng cờ bộ định thời TF được bật lên cao khi bộ định thời đạt giá trị cực đại và quay về 0 (Roll - over). Trong các bài trước chúng ta cũng chỉ ra cách kiểm tra cờ TF bằng một vòng lặp. Trong khi thăm dò cờ TF thì ta phải đợi cho đến khi cờ TF được bật lên. Vấn đề với phương pháp này là bộ vi điều khiển bị trói buộc trong khi chờ cờ TFđược bật và không thể làm được bất kỳ việc gì khác.

Sử dụng các ngắt sẽ giải quyết được vấn đề này và tránh được sự trói buộc bộ vi điều khiển. Nếu bộ ngắt định thời trong thanh ghi IE được phép thì mỗi khi nó quay trở về 0 bộ vi điều khiển sẽ bị ngắt, bất chấp nó đang thực hiện việc gì và nhảy tới bảng vector ngắt để phục vụ ISR. Bằng cách này thì bộ vi điều khiển có thể làm những công việc khác cho đến khi nó được thông báo rằng bộ định thời đã quay về 0. Xem hình 3ví dụ 2.

Hình 3: Ngắt bộ định thời TF0TF1.

Ví dụ 2:

            Hãy viết chương trình nhận liên tục dữ liệu 8 Bit ở cổng P0 và gửi nó đến cổng P1 trong khi nó cùng lúc tạo ra một sóng vuông chu kỳ 200ms trên chân P2.1. Hãy sử dụng bộ Timer0 để tạo ra sóng vuông, tần số của 8051 là XTAL = 11.0592MHz.

Lời giải:

Chu kỳ 200ms, vậy nửa chu kỳ là 100ms

Ta có: 100ms/1,085ms=92

Suy ra giá trị cần nạp cho timer0 là: -92 <=> A4H. Ta sử dụng timer0 8 bit.

#include<at89x51.h>                      //khai báo thu viện cho VÐK 89x51

main()

{

            TMOD=0x02;           //chọn timer0, chế độ 2, 8Bit tự nạp lại

            TL0=0xA4;               //nạp giá trị cho TL0

            TH0=0xA4;              //nạp giá trị cho TH0

            TR0=1;                        //khởi động timer0

            IE=0x82;                     //cho phép ngắt timer0

            while(1)                    //vòng lặp vô hạn

            {

                        P1=~P0;         //Cập nhật giá trị cho cổng P1 từ P0.

            }

}

void songvuong(void) interrupt 1   //Khai báo trình phục vụ ngắt cho timer0

{

            TR0=0;                       //Ngừng timer0

            P2_1=~P2_1;                        //Đảo trạng thái chân P2_1.

            TR0=1;                       //Khởi động timer0

                                                //Không cần xóa cờ TF0, 8051 tự động xóa.

  1.      Chúng ta cho phép ngắt bộ Timer0 với lệnh IE=0x82; trong chương trình chính main(). 2.      Trong khi dữ liệu ở cổng P0 được nhận vào và chuyển liên tục sang cổng P1 thì mỗi khi bộ Timer0 trở về 0, cờ TF0 được bật lên và bộ vi điều khiển thoát ra khỏi hàm main() và đi đến địa chỉ 000BH để thực hiện ISR gắn liền với bộ Timer0. 3.      Trong trình phục vụ ngắt ISR của Timer0 ta thấy rằng không cần đến lệnh xóa cờ TF0 của timer0. Lý do này là vì 8051 đã tự xoá cờ TF0 ngay khi thoát khỏi ISR.   Ví dụ 3:             Hãy viết lại chương trình ở ví dụ 2 để tạo sóng vuông với mức cao kéo dài 1085ms và mức thấp dài 15ms với giả thiết tần số XTAL = 11.0592MHz. Hãy sử dụng bộ định thời Timer1. Lời giải:             Vì 1085ms/1.085ms=1000 nên ta cần sử dụng chế độ 1 của bộ định thời Timer1. Các giá trị cần nạp cho timer1 là: 1085/1.085=1000 , -1000óFC18H 15/1.085=14 , -14óFFF2H   #include<at89x51.h> bit a=0;  main() {             TMOD=0x10;          //chọn timer1, chế độ 1, 16Bit             TL1=0x18;               //nạp giá trị cho TL1             TH1=0xFC;             //nạp giá trị cho TH1             TR1=1;                       //khoi dong timer1             IE=0x88;                    //cho phép ngat timer1              while(1)                     //vòng lặp vô hạn             {                         P1=~P0;         //Cập nhật cổng P1             } } void songvuong(void) interrupt 3        //Khai báo trình phục vụ ngắt timer1 {             TR1=0;                                   //Dừng timer1                        if(a==0)                                 //Nếu Xung vuông đang ở mức thấp             {                         P2_1=1;                     //Bật xung vuông lên cao                         a=1;                            //Đặt lại bit kiểm tra                         TL1=0x18;                //Nạp lại TL1: Ứng với mức trễ phần cao                         TH1=0xFC;               //Nạp lại TH1             }             Else                                         //Nếu Xung vuông đang ở mức cao             {                                  P2_1=0;                     //Lật xung xuống thấp                         a=0;                            //Đặt lại bit kiểm tra                         TL1=0xF2;                //Nạp lại TL1: Ứng với mức trễ phần thấp                       TH1=0xFF;                //Nạp lại TH1             }             TR1=1;                                   //Khởi động lại timer1                                                             //Không cần xóa cờ TF1, 8051 tự động xóa }

Bạn đang đọc truyện trên: Truyen2U.Pro

#quang