前面我們學(xué)習(xí)了定時(shí)器的簡(jiǎn)單用法,并且設(shè)計(jì)了幾個(gè)有趣的小項(xiàng)目
今天我們學(xué)習(xí)進(jìn)階操作——中斷
1 認(rèn)識(shí)中斷
一個(gè)生活的小場(chǎng)景……
你拿著手機(jī),屏幕上顯示著Zi Jin Code的最新文章,一旁的藍(lán)牙音響播放著悠揚(yáng)的古風(fēng)音樂(lè)……目不轉(zhuǎn)睛之刻,朋友給你打來(lái)一個(gè)電話……你調(diào)小了藍(lán)牙音箱的音量,接起了電話,你聊得正歡時(shí),門外傳來(lái)敲門聲,班主任來(lái)了……
相信這樣的場(chǎng)景,你應(yīng)該也遇到不少,我們常常正在做一件事情,突然另一件事冒出來(lái)打斷我們,讓我們不得不趕快去處理這件事
事實(shí)上,單片機(jī)的世界里,這樣的事件比比皆是。舉個(gè)最簡(jiǎn)單的例子,在一個(gè)秒表電路中,單片機(jī)一直輸出數(shù)碼管掃描顯示,這時(shí)候定時(shí)器溢出了,單片機(jī)不得不先放下手中的活,去處理時(shí)器溢出的操作,處理完后又返回到剛剛停下來(lái)的位置繼續(xù)來(lái)執(zhí)行輸出顯示的操作。這個(gè)過(guò)程中,單片機(jī)放下輸出顯示的任務(wù),先跑去執(zhí)行定時(shí)器溢出的一些操作,就是一次中斷的過(guò)程,用圖表示如下
單片機(jī)正常執(zhí)行程序的過(guò)程中,一個(gè)特殊的事件讓單片機(jī)停下現(xiàn)在正在執(zhí)行的任務(wù),跳轉(zhuǎn)去處理這個(gè)事件的任務(wù),處理完之后再返回到剛剛停下來(lái)的地方,繼續(xù)執(zhí)行最初放下來(lái)的任務(wù),這個(gè)過(guò)程就叫中斷,觸發(fā)的這個(gè)事件叫做中斷源
到此,相信我們已經(jīng)初步了解中斷的過(guò)程,思考以下,那之前我們寫的代碼(如下)是使用了定時(shí)器中斷嗎
#include< reg52.h >
sbit LED = P1^0;//LED接在P1.0
unsigned char Counter = 0;//溢出次數(shù)記錄
void main()
{
TH0 = 0x00;
TL0 = 0x00;
TR0 = 1;//Timer0初始值設(shè)置,使能定時(shí)器
LED = 1;//初始化LED引腳電平值
while(1)
{
if(TF0 == 1)
{
Counter++;//定時(shí)器溢出次數(shù)++
TH0 = 0x00;//溢出以后要對(duì)定時(shí)器進(jìn)行簡(jiǎn)單的重新裝載初始值
TL0 = 0x00;
TF0 = 0;//重新設(shè)置定時(shí)器溢出位的數(shù)值
}
if(counter == 256)//定時(shí)器累計(jì)溢出256次
{
Counter = 0;//復(fù)位
LED = !LED;//LED電平取反
}
}
}
從程序運(yùn)行流程分析,這并不是一個(gè)中斷
我們的程序運(yùn)行到while(1)的時(shí)候就進(jìn)入我們?cè)O(shè)計(jì)的死循環(huán),在這個(gè)死循環(huán)中有兩個(gè)任務(wù),第一個(gè)是判斷Timer0有沒(méi)有溢出以及如果溢出后的操作,第二個(gè)是判斷定時(shí)器溢出次數(shù)是否累計(jì)達(dá)到我們的需求。
這個(gè)代碼中,只有執(zhí)行到if(TF0==0)的時(shí)候才會(huì)執(zhí)行判斷定時(shí)器是否溢出,倘若我們的程序執(zhí)行到if(Counter==256)的代碼的時(shí)候定時(shí)器已經(jīng)溢出,那么機(jī)器也會(huì)繼續(xù)執(zhí)行完這個(gè)if的語(yǔ)句,直到再次執(zhí)行到if(TF0==0)才會(huì)對(duì)timer溢出做出處理。顯然不是定時(shí)器中斷
這種使用定時(shí)器的優(yōu)點(diǎn)是代碼簡(jiǎn)單,而且應(yīng)對(duì)簡(jiǎn)單的定時(shí)器任務(wù)的時(shí)候可以簡(jiǎn)潔的代碼完成任務(wù)(比如說(shuō)一秒點(diǎn)亮一個(gè)led燈),但是應(yīng)對(duì)稍微復(fù)雜的任務(wù)(例如做一個(gè)單片機(jī)電子時(shí)鐘,只有執(zhí)行到判斷Timer溢出的代碼才做出判斷,這樣就可能發(fā)生定時(shí)不準(zhǔn)確的問(wèn)題了)
至此,希望你跟我一樣,也明白了定時(shí)器和中斷不是一回事,也希望大家不要把定時(shí)器和中斷搞混
2 中斷使用第一步, 中斷的分類,認(rèn)識(shí)中斷源
C51中的中斷,可以這樣分類
中斷符號(hào) | 中斷名稱 | 作用 |
---|---|---|
IE0 | 外部中斷0 | 對(duì)應(yīng)外部中斷INT0 |
IE1 | 外部中斷1 | 對(duì)應(yīng)外部中斷INT1 |
T0 | Timer0中斷 | 定時(shí)器溢出后觸發(fā)的中斷 |
T1 | Timer1中斷 | |
T2 | Timer2中斷 | |
ES | uart串口中斷 | 串口中斷 |
不難發(fā)現(xiàn),按照功能分,一共有三類:
Timer中斷,當(dāng)定時(shí)器溢出的時(shí)候觸發(fā)這個(gè)中斷
外部中斷,C51提供兩組外部中斷,當(dāng)外部中斷引腳的電平變化的時(shí)候觸發(fā)中斷
分別是外部中斷0,對(duì)應(yīng)INT0,在P3.2引腳
分別是外部中斷0,對(duì)應(yīng)INT1,在P3.3引腳
串口中斷
串口中斷等到我們使用串口的時(shí)候再介紹,這里先放一放。
在單片機(jī)中,凡是能觸發(fā)中斷信號(hào)就叫中斷源,以上的定時(shí)器,外部中斷,串口都是中斷源。
換句話說(shuō),就是這些信號(hào)觸發(fā)了單片機(jī)的中斷。
3 中斷使用第二步,打開(kāi)中斷
中斷使能寄存器,地址0xA8,可位尋址
位 | 符號(hào) | 復(fù)位值 | 功能說(shuō)明 | 操作說(shuō)明 |
---|---|---|---|---|
7 | EA | 0 | 總中斷使能開(kāi)關(guān) | EA = 1使能中斷總開(kāi)關(guān) |
6 | - | 0 | - | - |
5 | ET2 | 0 | Timer2中斷使能開(kāi)關(guān) | 寫1的時(shí)候啟用中斷,寫0的時(shí)候不使用中斷 |
4 | ES | 0 | 串口中斷使能 | |
3 | ET1 | 0 | Timer1中斷使能 | |
2 | EX1 | 0 | 外部中斷INT1使能 | |
1 | ET0 | 0 | Timer0中斷使能 | |
0 | EX0 | 0 | 外部中斷INT0使能 |
下面說(shuō)明一下,假設(shè)我們要使用Timer0中斷,需要這樣操作:
EA = 1;//中斷總使能開(kāi)關(guān)
//現(xiàn)在先對(duì)中斷使能,確保我們能使用中斷
ET0 = 1;//使能timer0中斷
4 中斷使用第三步,認(rèn)識(shí)外部中斷
前面我們知道了,C51的外部中斷INT0,INT1和串口中斷ES分別在P3.2,P3.3,P3.1。這里我們先不介紹串口中斷,我們介紹兩個(gè)外部中斷INT0和INT1,串口中斷我們學(xué)串口的時(shí)候再研究。
還記得我們之前學(xué)習(xí)定時(shí)器的時(shí)候提到的TCON寄存器嗎
TCON寄存器
位 | 符號(hào) | 功能描述 | 操作 | 復(fù)位值 |
---|---|---|---|---|
7 | TF1 | Timer1溢出檢測(cè) | 定時(shí)器中斷標(biāo)志 | 0 |
6 | TR1 | Timer1使能 | TR1=1開(kāi)啟定時(shí)器,寫0關(guān)閉定時(shí)器 | 0 |
5 | TF0 | Timer0溢出檢測(cè) | 定時(shí)器中斷標(biāo)志 | 0 |
4 | TR0 | Timer0使能 | TR0=1開(kāi)啟定時(shí)器,寫0關(guān)閉定時(shí)器 | 0 |
3 | IE1 | INT1外部中斷請(qǐng)求標(biāo)志 | 請(qǐng)求標(biāo)識(shí),值為1的時(shí)候表明中斷向機(jī)器請(qǐng)求中斷。機(jī)器響應(yīng)后,自動(dòng)寫0 | 0 |
2 | IT1 | INT1中斷觸發(fā)設(shè)置 | 外部中斷觸發(fā)模式設(shè)置 | 0 |
1 | IE0 | INT0外部中斷請(qǐng)求標(biāo)志 | 請(qǐng)求標(biāo)識(shí),值為1的時(shí)候表明中斷向機(jī)器請(qǐng)求中斷。機(jī)器響應(yīng)后,自動(dòng)寫0 | 0 |
0 | IT0 | INT0中斷觸發(fā)設(shè)置 | 外部中斷觸發(fā)模式設(shè)置 | 0 |
上次我們沒(méi)有介紹低四位的功能,這回我們?cè)敿?xì)的介紹一下:
首先,IE1,IT1屬于外部中斷1,也就是外部中斷INT1。IE0,IT0屬于外部中斷0,也就是外部中斷INT0。
相信這點(diǎn)不難理解,接下來(lái)介紹IE,IT的功能
IE是外部中斷請(qǐng)求標(biāo)識(shí),當(dāng)外部中斷被觸發(fā)的時(shí)候,IE會(huì)變成1,表示外部中斷在向CPU請(qǐng)求中斷。當(dāng)CPU響應(yīng)這個(gè)外部中斷的時(shí)候,IE會(huì)自動(dòng)變成0。所以,IE就是用于中斷請(qǐng)求的標(biāo)識(shí),一般使用的時(shí)候我們不用操作這一位寄存器
IT是中斷觸發(fā)方式,一共有兩種觸發(fā)方式
觸發(fā)方式 | 說(shuō)明 | IT設(shè)置值 |
---|---|---|
低電平觸發(fā) | 當(dāng)外部中斷引腳電平為低電平的時(shí)候觸發(fā) | 0 |
負(fù)跳變觸發(fā) | 當(dāng)引腳電平由高電平轉(zhuǎn)換到低電平的這個(gè)過(guò)程中觸發(fā)(保持在高電平或者低電平都不會(huì)觸發(fā)) | 1 |
這里講一下什么叫負(fù)跳變,假設(shè)現(xiàn)在中斷引腳電平為高電平,外部電路變化讓外部中斷觸發(fā)引腳從高電平變化成低電平,這個(gè)時(shí)候外部中斷引腳的電平變化是1—>0,這就是個(gè)負(fù)跳變的變化過(guò)程。就在這個(gè)過(guò)程中,觸發(fā)了中斷。1—>0的負(fù)跳變過(guò)程后,單片機(jī)外部中斷IO但凡是保持在1或者保持在0都不會(huì)觸發(fā)中斷,只有再次發(fā)生電平1—>0的變化才會(huì)再次觸發(fā)外部中斷
而低電平觸發(fā),只要中斷引腳的電平為低電平就能直接觸發(fā)中斷。
靈活使用外部中斷IT模式的設(shè)置,配合我們的程序,玩出新花樣?。?!
這里不得不聲明一下,之前我們學(xué)習(xí)定時(shí)器的時(shí)候,我們總是會(huì)寫這樣一行代碼
這個(gè)代碼之前我們說(shuō)是判斷定時(shí)器是否溢出的標(biāo)志,溢出后需要我們手動(dòng)清零
事實(shí)上,當(dāng)我們使用定時(shí)器的時(shí)候,就已經(jīng)不再需要我們手動(dòng)清零了,如果我們使能定時(shí)器的中斷,這里的TF就相當(dāng)于IE一樣的中斷請(qǐng)求信號(hào),當(dāng)CPU接受請(qǐng)求(也就是CPU處理中斷函數(shù)之后,這個(gè)TF就自動(dòng)清零了)
所以我們使用定時(shí)器中斷的時(shí)候就不必要使用
來(lái)進(jìn)行手動(dòng)清零了。
5 中斷使用第四步,中斷索引和中斷函數(shù)的使用
前面我們學(xué)習(xí)了中斷源和中斷觸發(fā)的配置。
中斷觸發(fā)了,我們總要讓單片機(jī)做一點(diǎn)事情。單片機(jī)依靠中斷索引知道是哪個(gè)中斷觸發(fā)了,并且找到中斷函數(shù),執(zhí)行中斷函數(shù)的內(nèi)容。
先來(lái)看中斷函數(shù)的格式,這個(gè)是一個(gè)典型的中斷函數(shù)
void Timer1Interrupt() interrupt 1
{
counter++;
}
void 【中斷函數(shù)名字】() interrupt 【中斷索引編號(hào)】
{
counter++;
}
【中斷函數(shù)名字】可以是任何符合函數(shù)名規(guī)則的函數(shù)名
但是括號(hào)后的關(guān)鍵字“interrupt”一定不能寫錯(cuò),這個(gè)是中斷函數(shù)的關(guān)鍵字,關(guān)鍵字后面的數(shù)字是中斷索引
中斷索引,單片機(jī)靠這個(gè)找到中斷
索引 | 中斷名稱 | 符號(hào) | 功能 |
---|---|---|---|
0 | 外部中斷0 | IE0 | 外部中斷引腳INT0電平變化符合我們?cè)O(shè)置觸發(fā)的類型的時(shí)候觸發(fā)外部中斷 |
1 | Timer0中斷 | T0 | Timer0溢出的時(shí)候觸發(fā)中斷 |
2 | 外部中斷1 | IE1 | 外部中斷引腳INT1電平變化符合我們?cè)O(shè)置觸發(fā)的類型的時(shí)候觸發(fā)外部中斷 |
3 | Timer1中斷 | T1 | Timer1溢出的時(shí)候觸發(fā)中斷 |
4 | UART | ES | 串口中斷 |
5 | Timer2 | T2 | Timer2溢出的時(shí)候觸發(fā)中斷 |
單片機(jī)靠這個(gè)索引,知道是哪個(gè)中斷被觸發(fā)了,并且找到這個(gè)中斷觸發(fā)要執(zhí)行的對(duì)應(yīng)函數(shù)上
小總結(jié)(一)中斷的初始化
到這里,我們來(lái)簡(jiǎn)單總結(jié),對(duì)中斷進(jìn)行初始化,中斷初始化在main函數(shù)中完成,值得一提,必須放在main函數(shù)的死循環(huán)前面
中斷使能寄存器,0xA8,可位尋址
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
符 | EA | - | ET2 | ES | ET1 | EX1 | ET0 | EX0 |
功能 | 中斷總開(kāi)關(guān) | - | Timer2中斷使能開(kāi)關(guān) | UART串口中斷使能開(kāi)關(guān) | Timer1中斷使能開(kāi)關(guān) | 外部中斷1中斷使能開(kāi)關(guān) | Timer0中斷使能開(kāi)關(guān) | 外部中斷0中斷使能開(kāi)關(guān) |
操作 | 1:打開(kāi) | - | 1:打開(kāi),0:關(guān)閉 |
中斷控制寄存器,0x88,可位尋址
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
符 | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE 0 | IT0 |
功能 | 檢測(cè)/復(fù)位定時(shí)1器溢出 | 使能定時(shí)器1 | 檢測(cè)/復(fù)位定時(shí)器0溢出 | 使能定時(shí)器0 | 外部中斷1請(qǐng)求信號(hào) | 外部中斷1觸發(fā)信號(hào)設(shè)置 | 外部中斷0請(qǐng)求信號(hào) | 外部中斷觸0發(fā)信號(hào)設(shè)置 |
操作 | 定時(shí)器中斷信號(hào) | TR0 = 1使能定時(shí)器 | 定時(shí)器中斷信號(hào) | TR1 = 1使能定時(shí)器 | 自動(dòng)處理,無(wú)需干預(yù) | 設(shè)置觸發(fā)模式 | 自動(dòng)處理,無(wú)需干預(yù) | 設(shè)置觸發(fā)模式 |
這里還是再次說(shuō)明一次
IE是中斷請(qǐng)求觸發(fā)器,當(dāng)中斷觸發(fā)的時(shí)候自動(dòng)寫1,CPU請(qǐng)求后自動(dòng)寫0
IT設(shè)置中斷觸發(fā)模式
IT=1 | 負(fù)跳變模式,電平由1—>0觸發(fā) |
---|---|
IT=0 | 低電平觸發(fā)模式,低電平的時(shí)候自動(dòng)觸發(fā) |
我們使用了timer的中斷,這時(shí)候TF相當(dāng)于Timer的中斷請(qǐng)求位,cpu響應(yīng)中斷后就自動(dòng)清零,所以我們就不需要在中斷函數(shù)里面對(duì)TF進(jìn)行干預(yù)
小總結(jié)(二)中斷索引與中斷函數(shù)
索引 | 中斷符號(hào) | 說(shuō)明 |
---|---|---|
0 | IE0 | 外部中斷引腳INT0電平變化符合我們?cè)O(shè)置觸發(fā)的類型的時(shí)候觸發(fā)外部中斷 |
1 | T0 | Timer0溢出的時(shí)候觸發(fā)中斷 |
2 | IE1 | 外部中斷引腳INT1電平變化符合我們?cè)O(shè)置觸發(fā)的類型的時(shí)候觸發(fā)外部中斷 |
3 | T1 | Timer1溢出的時(shí)候觸發(fā)中斷 |
4 | ES | 串口中斷 |
5 | T2 | Timer2溢出的時(shí)候觸發(fā)中斷 |
中斷函數(shù)格式
void [中斷函數(shù)名] () interrupt [中斷索引編號(hào)]
{
}
這里再次說(shuō)明,中斷函數(shù)寫在main函數(shù)后面
[中斷函數(shù)名]可以是任何一個(gè)符合函數(shù)名規(guī)則的函數(shù)名
interrupt是中斷函數(shù)的關(guān)鍵字,必須寫對(duì)
[中斷索引編號(hào)參考以上的編號(hào)]
實(shí)踐(一)timer中斷
下面我們就來(lái)實(shí)踐一下吧
這個(gè)程序里面對(duì)定時(shí)器Timer0初始化(設(shè)置一個(gè)基本的16位定時(shí)器),并且設(shè)置定時(shí)器中斷
#include< reg51.h >
void main ()
{
EA = 1;//【第一步】總中斷開(kāi)關(guān)使能
TMOD = 0x01;//【第二步】設(shè)置定時(shí)器T0的模式為標(biāo)準(zhǔn)的16位定時(shí)器
TH0 = 0x00;//【第三步】設(shè)置定時(shí)器初始值
TL0 = 0xEE;
ET0 = 1;//【第四步】定時(shí)器Timer0中斷使能
TR0 = 1;//【第五步】激活定時(shí)器
while(1)
{
}
}
void Tmr0Int () interrupt 1
{
TH0 = 0x00;
TL0 = 0xFF;//只需要重新設(shè)置初始值,不需要復(fù)位TF
}
分析一下代碼,我們很容易的發(fā)現(xiàn),新的代碼里面多了兩個(gè)對(duì)中斷的操作:
EA = 1;//【第一步】總中斷開(kāi)關(guān)使能
ET0 = 1;//【第四步】定時(shí)器Timer0中斷使能
EA=1使能總中斷開(kāi)關(guān)
ET0=1打開(kāi)Timer0中斷開(kāi)關(guān)
還有一些注意事項(xiàng):
定時(shí)器中斷設(shè)置的順序
EA=1 > TMOD設(shè)置 > 定時(shí)器初始值設(shè)置 > ET=1使能定時(shí)器中斷 > TR=1使能定時(shí)器
初始化在main函數(shù)的死循環(huán)前
中斷函數(shù)一般寫在main函數(shù)后面
我們使用了timer的中斷,這時(shí)候TF相當(dāng)于Timer的中斷請(qǐng)求位,cpu響應(yīng)中斷后就自動(dòng)清零,所以我們就不需要在中斷函數(shù)里面對(duì)TF進(jìn)行干預(yù)
使用16位定時(shí)器中斷,模式1,定時(shí)器溢出中斷后我們?nèi)匀恍枰獙?duì)定時(shí)器初始值進(jìn)行干預(yù)
實(shí)踐(二)timer中斷 ****
下面我們就來(lái)實(shí)踐一下吧
這里我們要用上外部中斷0,設(shè)置外部中斷觸發(fā)的方式是低電平觸發(fā)
以下是代碼
#include< reg51.h >
void main ()
{
EA = 1;//【第一步】總中斷開(kāi)關(guān)使能
IT0 = 0;//【第二步】設(shè)置外部中斷模式,低電平觸發(fā)
EX0 = 1;//【第三步】打開(kāi)外部中斷0的使能開(kāi)關(guān)
while(1)
{
}
}
void ExInit0 () interrupt 0
{
}
不難發(fā)現(xiàn),這段代碼比設(shè)置定時(shí)器中斷的代碼更簡(jiǎn)單,不過(guò)仍然有兩個(gè)地方需要注意:
第一個(gè)當(dāng)然是初始化操作的順序
第二個(gè)是注意中斷函數(shù)的索引編號(hào)絕對(duì)不能錯(cuò)
好了,介紹就到這里了,希望能幫助你更好的了解單片機(jī),如果您覺(jué)得還不錯(cuò)的話歡迎關(guān)注我
-
單片機(jī)
+關(guān)注
關(guān)注
6030文章
44489瀏覽量
631996 -
中斷
+關(guān)注
關(guān)注
5文章
895瀏覽量
41349 -
定時(shí)器
+關(guān)注
關(guān)注
23文章
3232瀏覽量
114329 -
C51單片機(jī)
+關(guān)注
關(guān)注
12文章
164瀏覽量
34699
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論