飛書文檔https://x509p6c8to.feishu.cn/wiki/A5gcwyL5giq1JOkkcsscn8eLnzf
一、中斷的作用
中斷是為使單片機具有對外部或內部隨機發生的事件實時處理而設置的,中斷功能的存在,很大程度上提高了單片機處理外部或內部事件的能力。它也是單片機最重要的功能之一,是我們學習單片機必須要掌握的。
為了能讓大家更容易理解中斷概念, 我們先來舉一個生活事例:
你打開火,燒上一壺水。然后去洗衣服,在洗衣服的過程中,突然聽到水壺發出水開的報警聲,這時,你停止洗衣服動作,立即去關掉火,然后才回去繼續洗衣服。 |
二、那中斷是如何解決實際問題的呢?
回到按鍵章節,如果我們在while循環中,沒有耗時的代碼需要執行,這段代碼是能夠實時記錄按鍵值的,但如果我們的程序設計復雜后,有耗時的任務需要處理,例如下方的Delay1ms(20000);延時20s,那在這20s內我們按下按鍵,芯片就無法讀取到信號的變化了。
#include <reg52.h>sfr P4??? = 0xe8;?????????????????? //for 89C5xRC/RD+ series and 90C5xRc/RD+, location at 0E8H
sbit INT2 = P4^3;
sbit INT3 = P4^2;sfr XICON = 0xc0;?????????????????? //for 89C5xRC/RD+ series and 90C5xRc/RD+, location at 0C0H
sbit PX3? = XICON^7;
sbit EX3? = XICON^6;
sbit IE3? = XICON^5;
sbit IT3? = XICON^4;
sbit PX2? = XICON^3;
sbit EX2? = XICON^2;
sbit IE2? = XICON^1;
sbit IT2? = XICON^0;sbit key1 = P4^3;
sbit led1 = P2^7;void delay_ms(unsigned int xms)?? //@12MHz
{unsigned int i, j;for(i=xms;i>0;i--){for(j=124;j>0;j--){}}
}void main()
{while(1){//當按鍵按下時燈切換if(key1 == 0){led1= ~led1;delay_ms(1000);}delay_ms(20000);}???????????????
}
這時候,我們就需要用中斷的功能,幫我們實時記錄。
三、51單片機的中斷
STC89C5X 系列單片機提供了 8 個中斷請求源,它們分別是:外部中斷O(INT0)、外部中斷 1(INT1)、外部中斷 2(INT2)、外部中斷 3(INT3)、定時器 0中斷、定時器 1 中斷、定時器 2 中斷、串口(UART)中斷。
外部中斷:由外部引腳觸發的中斷
定時器中斷:由定時器觸發的中斷
串口中斷:通訊過程中發送或接收數據完畢觸發的中斷
外部中斷
這個章節我們先來看下外部中斷,也就是INT0、INT1、INT2、INT3。
下面這個框圖很重要,它會給我們介紹,如果我們需要使用單片機的某個中斷,需要配置哪些寄存器,我們通過框圖、再結合寄存器表格和示例程序,就能知道怎么使用單片機中斷。
中斷寄存器
TCON.0/IT0:中斷觸發行為設置
IE0:外部中斷0請求源,IE0=1外部中斷向CPU請求中斷,中斷響應后,IE0=0。
不需要手動設置,由CPU處理即可。
EX0:外部中斷0允許寄存器
EA:總中斷允許寄存器
中斷初始化
void exti0_init(void)
{IT2=1;//觸發方式:下降沿EX2=1;//打開 INT2 的中斷允許EA=1;//打開總中斷
}
中斷服務程序(回調函數)
//在中斷函數中 exti0 是函數名,可自定義,interrupt 是一個關鍵字,表示 51 單片機中斷。
//后面的“0”是中斷號
//外部中斷 0 中斷號為 0
//定時器中斷0,中斷號為1
//外部中斷 1,則中斷號為 2。
void exti0() interrupt 0 //外部中斷 0 中斷函數
{//執行所需的功能
}
外部中斷代碼:
#include <reg52.h>sfr P4??? = 0xe8;?????????????????? //for 89C5xRC/RD+ series and 90C5xRc/RD+, location at 0E8H
sbit INT2 = P4^3;
sbit INT3 = P4^2;sfr XICON = 0xc0;?????????????????? //for 89C5xRC/RD+ series and 90C5xRc/RD+, location at 0C0H
sbit PX3? = XICON^7;
sbit EX3? = XICON^6;
sbit IE3? = XICON^5;
sbit IT3? = XICON^4;
sbit PX2? = XICON^3;
sbit EX2? = XICON^2;
sbit IE2? = XICON^1;
sbit IT2? = XICON^0;sbit key1 = P4^3;
sbit led1 = P2^7;void delay_ms(unsigned int xms)?? //@12MHz
{unsigned int i, j;for(i=xms;i>0;i--){for(j=124;j>0;j--){}}
}void exit2() interrupt 6
{//當按鍵按下時燈切換if(key1 == 0){led1= ~led1;delay_ms(1000);}
}void main()
{IT2 = 1; //設置中斷觸發條件為下降沿EX2 = 1; //運行中斷2經過EA = 1;? //使能中斷while(1){delay_ms(20000);}???????????????
}
要注意:
標準的單片機頭文件reg52.h是沒有P4,我們可以參考工具自行添加。
中斷優先級
每一個中斷的優先級別均可用軟件設置。高優先級的中斷請求可以打斷低優先級的中斷,反之,低優先級的中斷請求不可以打斷高優先級及同優先級的中斷。當兩個相同優先級的中斷同時產生時,將由查詢次序來決定系統先響應哪個中斷。
默認情況下所有中斷優先級被設置為最高優先級3,當系統開啟了多個中斷,根據具體的業務設置對應的優先級即可。例如系統開啟了外部中斷INT0和INT1,默認情況下INT0的優先級是比INT1要高的,假設系統觸發了INT0,INT0在執行中斷服務程序時,INT1將不會被及時響應。 |
IP XICON IPH 中斷優先級控制寄存器
IP、IPH - PX0H PX0
0b0000 0001
0b0100 0000
0*8+1*4+0*2+0*1 = 4
0*8+0*4+0*2+0*1=0
0x40
注意:
IPH這個寄存器是不可位尋址的,
如要想讓PX0H這位置一的話,直接 PX0H=1;這個寫法是錯誤的,因為它不能位尋址。
只能 IPH= 0x01(0000 0001)
//STC單片機的中斷優先級需要設置IP和IPH寄存器,IP寄存器可以位操作,IPH只能寄存器操作 |
0x01是16進制的表示
在Keil C51中數不能直接以二進制形式賦值,所以需要設置寄存器某一位為1,用10進制或16進制顯示,這里涉及到進制轉換:
一個寄存器8位,相當于一個字節。
十進制:十進制是我們平常使用的數字系統,包含0到9這10個數字。
二進制:二進制是一種數值表示方式,只包含0和1兩個數字。常常這樣表示:0b0000 0000
十六進制:十六進制是一種數值表示方式,包含0到9和A到F這16個數字,常常這樣表示0x01
A可以理解為十進制的10,B=11,C=12,D=13,E=14,F=15
二進制 | 二進制轉十六進制 | 十六進制 | 十進制 | |
0b0000 0001 | 0*8+0*4+0*2+0*1=0 0*8+0*4+0*2+1*1=1 | 0x01 | 0×161+1×16? 0×16+1×1 = 1 | 1 |
0b0000 0100 | 0*8+0*4+0*2+0*1=0 0*8+1*4+0*2+0*1=4 | 0x04 | 0×161+4×16? 0×16+4×1 = 4 | 4 |
0b0001 0000 | 0*8+0*4+0*2+1*1=1 0*8+0*4+0*2+0*1=0 | 0x10 | 1×161+0×16? 1×16+0×1 = 16 | 16 |
0b0001 1111 | 0*8+0*4+0*2+1*1=1 1*8+1*4+1*2+1*1=15=f | 0x1f | 1×161+f×16? f=15 1×16+15×1 = 31 | 31 |