關於C51的中斷函數要注意的幾個問題(高手繞行)
最近在蝦潭逛,發現一些小蝦米對C51中斷函數有些不瞭解,今天週末,抽空發個技術帖子,希望對小蝦米有所幫助,如
有錯誤之處,還請指正,就當拋磚引玉吧!
C51的中斷函數的格式爲:
void FuncIr(void) interrupt x [using y]
以下是夢遊的一些分析:
一、中斷函數是一個特殊的函數,沒有參數,也沒有返回值;但是程序中允不允許使用return呢?答案是允許的,不過
只能用"return;",不能用"return(z);";用在一些需要快速返回的地方,對應的彙編會有多個ret語句,相對效率會高一
些。
二、using的用法,using可以修飾任何函數,不過個人建議只用來修飾中斷函數;簡單的說,“using”會指定工作寄存
器組,由於中斷函數一般都是比較緊急的事情,有時一條語句都會斤斤計較,所以使用using切換寄存器組可以省去一些壓棧
的動作,由於51只有兩級中斷,同級中斷不能被打斷,因此,我們可以同級中斷設成同樣的寄存器組,從某種意義上來說,
有一組寄存器是多餘的。同時個人建議中斷函數應該使用using這個關鍵字。
三、中斷中調用函數,首先要討論中斷函數中調用函數的必要性,前天在論壇上我和別人爭論過這個問題,現在我還是
這個觀點:有些情況中斷中調用函數還是必要的,這個時候是不是該調用函數,其實和普通函數差不多,首先是這個函數如
果調用多次,或者要帶一些參數什麼的就更加必要的;前天有人跟我叫勁,說假如只調用一次且無參數無返回的函數要直接
寫,因爲如果用函數,至少會增加CALL和RET兩條語句,我不敢苟同,我是實際調試發現的,當你程序比較複雜時,你將那部
分單獨拉出來做成函數,可能代碼和時間都會更好
四、中斷中調用的函數最好不要被中斷外的其它函數調用,因爲會出現“重複調用”的警告,有時這種調用是很致命
的,有人說這個函數可以用reentrant來修飾,是的,的確可以這樣解決,不過個人不建議這麼做,也許這樣會跟你減少很多
堆棧空間,並且整個程序的優化要差很多,個人建議出現這種情況就把這個函數寫兩遍,分成兩個函數分別調用。
五,中斷調用了函數,會出現一些莫名其妙的問題,一些數據不對。其實一般是因爲彙編中使用了絕對寄存器引起的,有人說中斷函數使用那個寄存器組,被中斷調用的
函數就使用哪個寄存器組,我認爲這樣不好:
這樣會增加額外的消耗,使用using會增加一下語句:
PUSH PSW
MOV PSW, #XX
....
POP PSW
更重要的是,使用using的函數不能有返回值,這是致命傷
個人推薦的方法有兩種:
1、使用“#pragma NOAREGS”禁止使用絕對寄存器
2、使用“#pragme RB(x)”來指定本文件的工作寄存器組
六、一般說來,要求中斷函數儘可能的短,但也有特殊情況,有些前/後臺的系統中,就會把很多相對重要的事情放到定
時中斷(這個定時中斷類似實時操作系統中的時鐘節拍)去做,而且程序很長。我單獨提出來這點是想告訴大家,中斷函數
也是一個函數而已,只要系統有必要,可以做一些看似不合理的事情,該出手時就出手,就像goto語句一樣。
51單片機的中斷函數
中斷使用interrupt 關鍵字和中斷編號0-4來實現:
返回值 函數名 interrupt n
n對應中斷源的編號,中斷編號告訴中斷器中斷程序的入口地址,它對應着IE寄存器中的使能位,即IE寄存器中的0位對應着外部中斷0。
8051單片機的中斷源以及終端編號如下:
中斷編號 中斷源 入口地址
0 外部中斷0 0003H
1 定時器/計數器0 溢出 000BH
2 外部中斷1 0013H
3 定時器/計數器1 溢出 001BH
4 串行口中斷 0023H
在51系列單片機中,有的單片機多達32箇中斷源,所以中斷編號是0-31.
當正在執行一個特定的任務時,可能有更緊急的事情需要CPU處理,這就涉及到了中斷優先級。高優先級中斷可以中斷正在處理的低優先級中斷程序,因而最好給每種優先級程序分配不同的寄存器組。在C51中可使用using指定寄存器組,using後的變量爲0-3的常整數,分別表示51單片機內的4哥寄存器組。中斷函數的完整語法如下:
返回值 函數名([參數])[模式][重入]interrupt n[usingn]
unsigned int interruptcnt;
unsigned char second;
void timer0(void) interrupt 1 using 2
if(++interruptcnt==4000) // 計數到4000
second++; //另一個計數器
interruptcnt=0; //計數器清零