You are on page 1of 7

Chương 3: TỔ CHỨC NGẮT VÀ NGẮT NGOÀI (6 tiết)

3.1. Tổng quan về ngắt


Ngắt là một hoạt động khác chen vào một hoạt động đang thực thi mà không biết trước. Đối
với chương trình của vi điều khiển, chương trình đang thực thi là chương trình chính. Hoạt
động ngắt đã được cài đặt cho phép cho trước, nếu có dấu hiệu ngắt (cờ ngắt bật lên) chương
trình chính sẽ tạm dừng và con trỏ chương trình sẽ chỉ đến địa chỉ ngắt để thực hiện chương
trình ngắt.
Đối với hệ vi xử lý, tại mỗi thời điểm nhất định chỉ có một chương trình được thực thi, các
hoạt động giám sát vào ra của các thiết bị, giao tiếp với các thiết bị… được CPU thực hiện
bằng cách hỏi vòng tuần tự theo các công việc hành động đã được sắp đặt trước. Như vậy
trong một vài trường hợp sẽ ảnh hưởng đến chất lượng của hệ thống do hoạt động hỏi vòng
tốn mất nhiều thời gian nếu chương trình lớn, dẫn đến sự trể xử lý các tác vụ cần xử lý. Ví dụ
như để phát hiện và cảnh báo các trạng thái cảm biến nhiệt độ và chập mạch điện, CPU sẽ hỏi
vòng lần lượt để đưa ra các cảnh báo nếu có sự cố xảy ra, nếu khi CPU đang xử lý tác vụ kiểm
tra nhiệt độ hiện đang cao và đang điều khiển quạt để giảm nhiệt độ mà trong lúc đó xảy ra bị
chập điện dẫn đến phát nhiệt hỏa hoạn do CPU đang thực thi chương trình giảm nhiệt độ, còn
chương trình kiểm tra ngắn mạch chưa đến.
Do đó rất cần thiết có một hoạt động cưỡng bức chen vào các hoạt động khác, đó gọi là
ngắt. Như ở ví dụ trên, nếu chương trình thực hiện kiểm tra và điều khiển nhiệt độ đặt trong
chương trình chính (hỏi vòng), còn chương trình cần xử lý nhanh và ưu tiên thì để trong
chương trình ngắt. Nếu đang thực thi điều khiển quạt do nhiệt độ còn cao mà có sự cố ngắn
mạch điện xảy ra thì chương trình sẽ tạm dừng chương trình chính điều khiển nhiệt độ và nhảy
đến chương trình bảo vệ ngắn mạch điện vì hoạt động bảo vệ ngắn mạch quan trọng hơn.
Trong vi xử lý có rất nhiều nguồn ngắt khác nhau, tùy theo yêu cầu cần ngắt nào mà ta chỉ
cài đặt và sử dụng nó nếu thấy cần thiết
3.2. Các nguồn ngắt và sơ đồ ngắt
Một số ngắt cơ bản trong PIC16F887:
- Ngắt ngoài trên RB0 sẽ xảy ra khi có tác động cạnh lên hoặc cạnh xuống trên chân RB0
- Ngắt tràn bộ định thời Timer 0 xảy ra khi thanh ghi TMR0 thay đổi từ 255 về 0
- Ngắt trên sự thay đổi PORTB xảy ra khi có sự thay đổi 1 trong các chân của PORTD
- Ngắt chuyển đổi ADC xảy ra khi quá trình chuyển đổi ADC thực hiện xong
- Ngắt tràn Timer 1 xảy ra khi thanh ghi giá trị của TMR1L + TMR1H thay đổi từ 65535 về
0
- Ngắt tràn Timer 2 tương tự Timer0
- Ngắt truyền nhận EUSART xảy ra khi truyền hoặc nhận xong 1 byte dữ liệu qua EUSART
Từ sơ đồ ngắt trên cho thấy để xảy ra ngắt trên CPU (interrupt CPU) cần phải qua một hệ
thống các cổng logic
Ngõ ra cuối cùng bằng 1 thì sẽ xảy ra ngắt, trong chương trình ngắt muốn biết được ngắt
nào đang xảy ra thì phải kiểm tra xem trước đó đã cho phép ngắt nào và hiện tại cờ nào đang
được bật
3.3. Các bit cho phép ngắt và các bit cờ ngắt
Như trên đã trình bày, muốn có ngắt xảy ra phải qua hệ thống cổng logic, có các bit đứng
trước tại ngõ vào các cổng and có các chức năng khác nhau
- GIE_bit (Global Interrupt Enable): Bit cho phép ngắt toàn cục
- PEIE_bit (Peripheral Interrupt Enable): Bit cho phép ngắt ngoại vi. Các ngắt qua cổng and
với PEIE được gọi là các ngoại vi. Các ngoại vi hoạt động độc lập không phù thuộc vào CPU
cho đến khi nó xảy ra sự kiện ngắt
- T0IF_bit (Timer0 Interrupt Flag), T0IE_bit (Timer0 Interrupt Enable): bit cờ ngắt và bit
cho phép ngắt Timer0, khi có ngắt xảy ra, cờ ngắt sẽ bật lên 1
- INTF_bit (External Interrupt Flag), INTE_bit (External Interrupt Enable): bit cờ ngắt và
bit cho phép ngắt ngoài
- RBIF_bit (PORTB Change Interrupt Flag), RBIE_bit (PORTB Change Interrupt Enable):
bit cờ ngắt và bit cho phép ngắt thay đổi trên PORTB
- TXIF_bit (Transmit Interrupt Flag), TXIE_bit (Transmit Interrupt Enable): bit cờ ngắt và
bit cho phép ngắt truyền xong 1 byte dữ liệu EUSART.
- RXIF_bit (Receive Interrupt Flag), RXIE_bit (Receive Interrupt Enable): bit cờ ngắt và bit
cho phép ngắt nhận xong 1 byte dữ liệu EUSART
- TMR1IF_bit (Timer1 Interrupt Flag), TMR1IE_bit (Timer1 Interrupt Enable): bit cờ ngắt
và bit cho phép ngắt tràn Timer1
- TMR2IF_bit (Timer2 Interrupt Flag), TMR2IE_bit (Timer2 Interrupt Enable): bit cờ ngắt
và bit cho phép ngắt tràn Timer2
- ADIF_bit (ADC Interrupt Flag), ADIE_bit (ADC Interrupt Enable): bit cờ ngắt và bit cho
phép ngắt chuyển đổi xong kết quả ADC
3.4. Vec tơ ngắt và chương trình ngắt
Khi ngắt CPU xảy ra, chương trình chính đang thực thi sẽ tạm dừng, chương trình ngắt sẽ
thực thi, chương trình chính sẽ tiếp tục ở đoạn lúc nảy đã bị ngắt khi CPU thực hiện xong
chương trình ngắt.
Mỗi chương trình được định nghĩa ở một vị trí địa chỉ nhất định gọi là vec tơ. Chương trình
chính được bắt đầu ở 0x00, chương trình ngắt bắt đầu ở 0x04
Chương trình của vi điều khiển được chạy như sau: khi bật nguồn hoặc khi bị reset, chương
trình sẽ chạy qua các khai báo (thư viện, định nghĩa, biến) sau đó đến chương trình chính (void
main()) có địa chỉ 0x00 và sẽ thực hiện hỏi vòng ở vòng lặp vô tận. Nếu có ngắt xảy ra,
chương trình chính sẽ tạm dừng và nhảy đến địa chỉ 0x04 và thực hiện chương trình ngắt, thực
hiện xong chương trình ngắt sẽ trở về đoạn chương trình chính bị ngắt.
Như vậy vec tơ là địa chỉ vùng nhớ chương trình mà CPU sẽ trỏ đến để thực hiện các lệnh
bắt đầu ở đó, 0x00 là vec tơ bắt đầu chương trình chính, 0x04 là vec tơ bắt đầu chương trình
ngắt. Chương trình ngắt xử lý các nhiệm vụ ngắt với cơ ngắt tương ứng, chương trình ngắt cần
viết sao cho việc xử lý diễn ra nhanh chóng để còn trở về lại chương trình chính thực hiện các
nhiệm vụ khác
3.5. Ngắt ngoài RB0
Ngắt ngoài RB0 được thiết kế dạng ngắt cạnh, tức là khi có tín hiệu cạnh lên hoặc xuống
(tùy theo cài đặt trước) sẽ xảy ra ngắt
Để cấu hình cho ngắt này, ngoài cờ ngắt và cho phép ngắt còn phải bật bit cho phép ngắt
toàn cục GIE_bit, xác định cạnh ngắt INTEDG_bit bằng 0 nếu ngắt cạnh xuống hoặc bằng 1
nếu ngắt cạnh lên, cấu hình RB0_bit là ngõ vào
R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-x
GIE PEIE T0IE INTE RBIE T0IF INTF RBIF
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

R/W-0 R/W-1 R/W-1 R/W-1 R/W-1 R/W-1 R/W-1 R/W-1


!(RBPU) INTEDG T0CS T0SE PSA PS2 PS1 PS0
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

Cấu hình ngắt RBx:


- Cấu hình ngõ vào cho chân RB0
- Cho phép ngắt toàn cục
- Xác định cạnh ngắt INTEDG_bit
- Xóa cờ ngắt INTF_bit và cho phép ngắt RB0 bằng cách set INTE_bit
Chương trình ngắt:
- Kiểm tra cờ ngắt để xác định loại ngắt
- Xóa cờ ngắt
- Thực hiện nội dung ngắt

Ví dụ của 1 đoạn chương trình ngắt ngoài


void interrupt() {
if (INTF_BIT==1)&& (INTE_BIT==1{ // kiểm tra có phải là ngắt ngoài RB0
INTF_BIT=0;// Xóa cờ ngắt ngoài
led=1;// nội dung ngắt: bật 1 đèn led khi có ngắt
ngoài
}
}
void main() {
// cấu hình ngắt
TRISB0_bit=1;// RB0 là ngõ vào
GIE_BIT=1; // cho phép ngắt toàn cục
INTEDG_BIT=1;// ngắt cạnh lên
INTF_BIT=0;// Xóa cờ ngắt
INTE_BIT=1;// cho phép ngắt ngoài
// chương trình lặp vô tận
while(1) {
}
}
3.6. Ngắt thay đổi trên RB (RB On Change Interrupt)
Khi có 1 sự thay đổi mức logic trên chân RBx sẽ xảy ra ngắt, CPU sẽ biết được sự thay đổi
bằng cách so sánh giá trị cũ của RBx với giá trị hiện tại để phát hiện. Do đó, mỗi lần xảy ra
ngắt, yêu cầu người dùng phải đọc/ghi lại giá trị PORTB để lần sau còn biết để so sánh tiếp.
Để cấu hình ngắt này, ngoài các cấu hình RBIF và RBIE còn phải cấu hình cho phép ngắt thay
đổi trên từng chân cụ thể ở IOCBx. Còn IOC-Bx là bit phát hiện có sự thay đổi mức logic so
với trước đó
R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0
IOCB7 IOCB6 IOCB5 IOCB4 IOCB3 IOCB2 IOCB1 IOCB0
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-x
GIE PEIE T0IE INTE RBIE T0IF INTF RBIF
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

Cấu hình ngắt RBx:


- Cấu hình ngõ vào cho chân cần ngắt hay PORTB
- Cho phép ngắt toàn cục
- Cho phép ngắt thay đổi trên các chân bằng cách set IOCBx_bit tương ứng với chân chọn
ngắt
- Đọc PORTB, xóa cờ ngắt RBIF_bit (lưu ý phải đọc PORTB trước khi xóa cờ ngắt nếu
không sẽ xảy ra lỗi) và cho phép ngắt RBx bằng cách set RBIE_bit
Chương trình ngắt:
- Kiểm tra cờ ngắt để xác định loại ngắt
- Đọc PORTB, xóa cờ ngắt (đọc PORTB trước khi xóa cờ ngắt nếu không sẽ xảy ra lỗi)
- Thực hiện nội dung ngắt

Ví dụ của 1 đoạn chương trình ngắt RBx


char i;
void interrupt()
{
if((RBIF_BIT==1)&&(RBIE_BIT==1)){
i=portb;// Đọc PORTB trước khi xóa cờ ngắt
RBIF_BIT=0;// Xóa cờ ngắt RBx
}
}
void main() {
anselh=0; ansel=0;// vô hiệu hóa chức năng analog trên PORTA và PORTB
trisb=255;
GIE_BIT=1;
IOCB=0b11111101;// Cho phép ngắt thay đổi RB0, RB2, RB3, RB4,…., RB7
i=portb;
RBIF_bit=0;// Xóa cờ ngắt RBx
RBIE_bit=1;// Cho phép cờ ngắt RBx
i=0;
while(1){ }
}
3.7. Bài tập ứng dụng
3.7.1. Bài tập 1
- Kết nối cảm biến với chân RB0, cảm biến phát hiện có vật sẽ lên mức 1
- Lập trình đếm số vật mỗi khi vật đi qua, hiển thị số vật đếm được trên PORTD
3.7.2. Bài tập 2
- Kết nối cảm biến với chân RB0, cảm biến phát hiện có vật sẽ lên mức 1
- Lập trình đếm số vật mỗi khi vật đi qua, hiển thị số vật đếm được trên 1 led 7 đoạn
3.7.3. Bài tập 3
- Kết nối cảm biến với chân RB0, cảm biến phát hiện có vật sẽ lên mức 1
- Lập trình đếm số vật mỗi khi vật đi qua, hiển thị số vật đếm được trên LCD 16x2
3.7.3. Bài tập 3
- Kết nối cảm biến với chân RB2, cảm biến phát hiện có vật sẽ lên mức 1
- Lập trình ngắt thay đổi RB2 để đếm số vật mỗi khi vật đi qua, hiển thị số vật đếm được
trên PORTD
3.7.4. Bài tập 4
- Kết nối cảm biến với chân RB3, cảm biến phát hiện có vật sẽ lên mức 0
- Lập trình ngắt thay đổi RB3 để đếm số vật mỗi khi vật đi qua, hiển thị số vật đếm được
trên 1 led 7 đoạn
3.7.5. Bài tập 5
- Kết nối cảm biến 1 với chân RB3, cảm biến 2 với chân RB4, cảm biến 3 với chân RB6,
các cảm biến phát hiện có vật sẽ lên mức 1
- Lập trình ngắt thay đổi RB3, RB4, RB6 để đếm số vật đi qua trên mỗi cảm biến, hiển thị
số vật đếm được trên PORTA, PORTC, PORTD
3.7.6. Bài tập 6
- Kết nối cảm biến 1 với chân RB2, cảm biến 2 với chân RB4, cảm biến 3 với chân RB6,
cảm biến 1 phát hiện có vật sẽ lên mức 1, cảm biến 2 và cảm biến 3 phát hiện có vật sẽ lên
mức 0
- Lập trình ngắt thay đổi RB2, RB4, RB6 để đếm số vật đi qua trên mỗi cảm biến, hiển thị
số vật đếm được trên LCD
3.7.7. Bài tập 7
- Kết nối cảm biến 1 với chân RB0, cảm biến 2 với chân RB4, cảm biến 3 với chân RB6,
cảm biến 2 phát hiện có vật sẽ lên mức 1, cảm biến 1 và cảm biến 3 phát hiện có vật sẽ lên
mức 0
- Lập trình ngắt ngoài RB0 và ngắt thay đổi RB4, RB6 để đếm số vật đi qua trên mỗi cảm
biến, hiển thị số vật đếm được trên LCD
3.7.8. Bài tập 8
- Kết nối 8 cảm PORTB, 4 cảm biến đầu tiên phát hiện có vật sẽ lên mức 1, 4 cảm biến sau
phát hiện có vật sẽ lên mức 0
- Lập trình ngắt thay đổi PORTB để đếm số vật đi qua trên mỗi cảm biến, hiển thị số vật
đếm được trên LCD
3.7.9. Bài tập 9
Động cơ DC được trang bị endocer có 200 xung/vòng dùng cảm biến quang và khe hở để
nhận biết vị trí. Dùng ngắt ngoài để đếm số vòng của động cơ khi chạy
3.7.10. Bài tập 10
Thực hiện như bài 9 nhưng yêu cầu đếm 400 lần trên 1 vòng đối với encoder 200 xung/vòng
(gợi ý: dùng vừa ngắt cạnh lên vừa ngắt cạnh xuống)

You might also like