9.1 中斷系統知識介紹
在單片機中有兩個重要的概念分別叫做中斷、中斷系統,那么他們分別又代表什么意義呢?當單片機CPU正在運行主程序時外界發生了緊急事件請求,要求單片機停止當前的工作,而去處理這個緊急事件,處理完成之后,在回到主程序原來的地方繼續執行,這樣的過程稱之為中斷,實現中斷功能的部件稱為中斷系統。
一般單片機中都有多個中斷源,當多個中斷源同時發出請求的時候,單片機應該先響應哪一個呢?在單片機中可以設置中斷源的優先級,同時出現時單片機將優先響應優先級高的中斷源。另外一種情況,當單片機CPU正在響應某個中斷時,一個更高優先級的中斷請求產生了,這是CPU將暫停響應當前低優先級的中斷,轉而去響應高優先級的中斷源,響應完成后繼續處理低優先級中斷,之后再回到主程序繼續運行,這個過程稱之為中斷嵌套。
我們這里舉一個生活中的例子來解釋中斷嵌套的過程。當你在家中正在打掃衛生的時候,家里電話響了,這時你便會先放下手中的活,然后拿起電話接電話,在打電話的時候有人按門鈴了,這是你暫時先放下電話去開門,開完門之后你接著拿起電話繼續講,當掛斷電話后,你緊接著剛才繼續打掃衛生了。例子中打掃衛生相當于單片機CPU執行的主程序,電話相當于低優先級的中斷,門鈴相當于高優先級的中斷。在打電話的時候先去開門相當于中斷嵌套。
STC89C52單片機提供了8個中斷請求源,分別為:外部中斷0(INT0)、定時器0中斷,外部中斷1(INT1)、定時器1中斷、串口(UART)中斷、定時器2中斷、外部中斷2(INT2)、外部中斷3(INT3)。8個中斷請求源可以設置為4個中斷優先級,每一個中斷源都可以通過軟件設置為四級優先級的任一級。高優先級的中斷可以打斷低優先級的中斷,反之則不可。同一優先級的中斷同時來臨時,則根據中斷查詢的順序進行中斷響應。
如上表所示,在相同優先級內 ,外部中斷0的查詢次序最高,外部中斷3的查詢次序最低。傳統51系列單片機一般只配置上表所示的前5個中斷源,而且只有兩級中斷優先級。傳統51點單片機通過寄存器IP設置優先級,STC89C52通過新增加的寄存器IPH與IP寄存器共同設置4級優先級,與傳統兩級中斷優先級完全兼容。我們可以將上述8種中斷源分為3大類:
第一種: 外部中斷(INT0、1、2、3)
第二種: 定時器中斷(Timer0,1,2)
第三種: 串口中斷(UART)
每種類型中斷的使用方式都是相同的,只不過設置的寄存器不相同罷了。前面第六章講解的就是第二種的定時器0中斷。所有中斷的控制寄存器如下表所示,包括7個八位的寄存器。如下表所示,IP、IPH寄存器在單片機復位后值均為0,結合上表可知,在不對這兩個寄存器進行重新設置時,所有中斷均為優先級0。
單片機中斷系統結構圖如下圖所示,每一個中斷都有一個單獨中斷允許開關,INT0開關為EX0,Timer0為ET0,之后有一個中斷允許總開關EA,EA關閉才允許中斷,當EA斷開時,所有中斷將被屏蔽。在設置后中斷后,首先需要允許中斷。這一章我們將重點講解外部中斷的使用。
在C語言編程中,中斷又是怎么來實現的呢?在主程序中首先設置后中斷的工作方式,然后允許中斷,接著程序執行主程序,當中斷來臨時,程序跳轉到對應的中斷子函數中執行相應的操作,執行完之后繼續回到主程序。在C語言中,8個中斷源對應這8個中斷子程序函數,如下圖所示,將中斷要實現各功能編輯到相應的函數中即可。
如圖9-2所示,前面函數的名字可以根據需要進行更改,關鍵字interrupt x決定了這個行數屬于哪個中斷,在第六章中講到的定時器0中斷,即Timer0中斷,那么它對應的為”interrupt 1”。
9.2 外部中斷應用
STC89C52系列單片機對中斷源可開放或屏蔽,是有內部的特殊功能寄存器IE(中斷允許寄存器)進行控制的,IE寄存器格式如下:
中斷允許寄存器IE各位功能定義如下表所示:
單片機STC89C52復位后會將寄存器IE清零,需要有用戶對IE中相應的位清“0”或置“1”來實現中斷請求的允許或屏蔽。
傳統51單片機具有兩級中斷優先級,可實現中斷嵌套。通過中斷優先級寄存器IP可實現優先級的控制。IP寄存器格式如下:
中斷優先級控制寄存器IP各位功能定義如下表所示:
單片機復位后,優先級控制寄存器IP將清零,即所有中斷請求均為低優先級。
TCON寄存器在第六章定時器中斷時講解過,其中寄存器的高5位為與定時器/計數器相關的功能位,這里不再贅述。這里介紹與外部中斷相關的看控制位:
特殊功能寄存器TCON低4位功能介紹:
介紹了各控制寄存器的功能之后,下面我們講解外部中斷的實現。為了便于觀察我們設計的外部中斷0的功能為:當外部中斷0(P3.2)引腳出現下降延時,即設置為下降沿觸發模式,進入中斷后流水燈流動一次。在RY-51開發板中外部中斷0的P3.2引腳與獨立按鍵K19相連接,因此當按鍵按下一次給管腳P3.2一個下降沿,即產出一次中斷。實現的功能呢為按下一次按鍵,流水燈流動一次,設計程序如下:
/*----------------------------------------------------
** 外部中斷0試驗,功能:按下按鍵K19,流水燈流動一次。
----------------------------------------------------*/
#include< reg52.h >
#define uint unsigned int
uint Move = 0;
void main()
{
IT0 = 1; //設置外部中斷0為下降沿觸發方式
EX0 = 1; //允許外部中斷0中斷
EA = 1;//開全局中斷
while(1);
}
//外部中斷0中斷函數
void int0_r(void) interrupt 0
{
P1 = ~(0x01<
將程序下載到單片機中,每按一次按鍵K19觀察流水燈的變化情況。這個例子為外部中斷0的基本寫法,依此類推只要改變相應的寄存器設置,同樣可以對外部中斷1,2,3進行應用。
這里講解的只是單個中斷的應用,下面我們結合前面講過的定時器0中斷來看一個中斷嵌套的例子。我們將第8章最后的數碼管顯示的程序進行稍微的改造,將變量Sec每秒增加一次改為來一次外部中斷增加一次,即相當于上面的按鍵按一次Sec增加一次,那么數碼管顯示的將是按鍵的按下次數。程序的主要變化如下所示:
/*----------------------------------------------------
** 數碼管顯示任意數值
**
** case語句應用
----------------------------------------------------*/
#include< reg52.h >
#define uchar unsigned char
#define uint unsigned int
#define FOSC 11059200 //單片機晶振頻率
#define T_1ms (65536 - FOSC/12/1000) //定時器初始值計算
uint count = 0;
uint flag = 0;
uint Move = 0;
uint T_count = 0;
uint Sec = 0;
sbit DU = P2^7;
sbit WE = P2^6;
uchar Buf_LED[8] ={0};
//共陽型(0~9,A,b,C,d,E,F,全亮,全滅),字碼組
uchar code table_D[]={0xC0,0xF9,0xA4,0xB0,
0x99,0x92,0x82,0xF8,
0x80,0x90,0x88,0x83,
0xC6,0xA1,0x86,0x8E,
0x00,0xFF};
//位選數組
uchar code table_W[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0xFF,0x00};
void LED_disp(unsigned char Num_DU,unsigned char Num_WE);
void main()
{
TMOD = 0x01; //定時器工作模式配置
TL0 = T_1ms; //裝載初始值
TH0 = T_1ms >>8;
TR0 = 1; //啟動定時器
ET0 = 1; //允許定時器中斷
IT0 = 1; //設置外部中斷0為下降沿觸發方式
EX0 = 1; //允許外部中斷0中斷
EA = 1; //開總中斷
while(1) //循環
{
Buf_LED[7]= Sec%10;
Buf_LED[6]= Sec/10%10;
Buf_LED[5]= Sec/100%10;
Buf_LED[4]= Sec/1000%10;
Buf_LED[0]= 17;
Buf_LED[1]= 17;
Buf_LED[2]= 17;
Buf_LED[3]= 17;
}
}
//定時器0中斷函數
void timer0() interrupt 1
{
TL0 = T_1ms;//重裝初始值
TH0 = T_1ms >>8;
count++;
if(count >= 2)//每一毫秒進入一次中斷,達到2次則為2ms更新一次數碼管。
{
count = 0;
switch(flag)
{
case 0:LED_disp(Buf_LED[0],flag++);break;
case 1:LED_disp(Buf_LED[1],flag++);break;
case 2:LED_disp(Buf_LED[2],flag++);break;
case 3:LED_disp(Buf_LED[3],flag++);break;
case 4:LED_disp(Buf_LED[4],flag++);break;
case 5:LED_disp(Buf_LED[5],flag++);break;
case 6:LED_disp(Buf_LED[6],flag++);break;
case 7:LED_disp(Buf_LED[7],flag);flag=0;break;
default:break;
}
}
}
//外部中斷0中斷函數
void int0_r(void) interrupt 0
{
int i=0;
Sec++;
for( i =0;i<=5000;i++);
}
/*----------------------------------------------------
** 單個數碼管顯示函數
**
** Num_DU:顯示的字符
** Num_WE:顯示的位
----------------------------------------------------*/
void LED_disp(unsigned char Num_DU,unsigned char Num_WE)
{
//關閉所有數碼管,消隱處理
P0 =table_W[9];
WE = 1;
WE = 0;
//鎖存字符
P0 = table_D[Num_DU];
DU = 1;
DU = 0;
//鎖存位
P0 = table_W[Num_WE];
WE = 1;
WE = 0;
}
如上述代碼所示,增加了外部中斷0特殊功能寄存器的設置。
將Sec自加放到外部中斷函數中,并且在函數中增加了一個延時,讓中斷函數處理的時間長一點方便中斷嵌套現象的觀察。其它的代碼與數碼管顯示代碼相同,這里不再贅述。
將程序編譯下載到單片機中,觀察顯示效果。當按下一次按鍵K19,數碼管顯示數字加1。在觀察現象的時候,能發現數碼管顯示會出現閃爍,顯示受到干擾。下面分析一下產生閃爍的原因。
我們在程序中沒有對外部中斷0和定時器0中斷進行中斷優先級設置,所以均為低優先級,根據前面介紹在同一優先級條件下外部中斷0的查詢次序高于定時器0中斷,當定時器0中斷和外部中斷0同時產生時,將優先進入外部中斷0中斷函數。所以當按鍵按下和定時器中斷同時到來時,程序會先進入外部中斷函數,而造成沒有正常的進入定時器中斷刷新數碼管的顯示,因此數碼管顯示的閃爍。
那么,在程序中將定時器0中斷設置為高優先級中斷,外部中斷為低優先級中斷。因此,當定時器中斷到來時,不管程序有沒有正在執行外部中斷0函數,程序都會進入到定時器中斷函數中,保證了數碼管的刷新,因此消除了數碼管閃爍的現象,增加的程序代碼如下代碼所示:
void main()
{
TMOD = 0x01; //定時器工作模式配置
TL0 = T_1ms; //裝載初始值
TH0 = T_1ms >>8;
TR0 = 1; //啟動定時器
ET0 = 1; //允許定時器中斷
IT0 = 1; //設置外部中斷0為下降沿觸發方式
EX0 = 1; //允許外部中斷0中斷
PT0 = 1;//定時器0設置為高優先級 -----------------增加設置優先級代碼1
PX0 = 0;//外部中斷0設置為低優先級 -----------------增加設置優先級代碼2
EA = 1; //開總中斷
while(1) //循環
9.3 本章小節
本章詳細介紹了單片機中斷系統的工作原理以及部分中斷寄存器功能的定義。介紹了外部中斷0功能C語言程序的編寫,介紹了中斷嵌套的應用。
-
單片機
+關注
關注
6035文章
44554瀏覽量
634652 -
cpu
+關注
關注
68文章
10854瀏覽量
211584 -
定時器
+關注
關注
23文章
3246瀏覽量
114720 -
中斷系統
+關注
關注
1文章
96瀏覽量
61015 -
外部中斷
+關注
關注
1文章
131瀏覽量
15816
發布評論請先 登錄
相關推薦
評論