第3課 CC2530的中斷系統及外部中斷應用
廣東職業技術學院 歐浩源
一、中斷相關的基礎概念
內核與外設之間的主要交互方式有兩種:輪詢和中斷。 輪詢的方式貌似公平,但實際工作效率很低,且不能及時響應緊急事件;中斷系統使得內核具備了應對突發事件的能力。
在執行CPU當前程序時,由於系統中出現了某種急需處理的情況,CPU暫停正在執行的程序,轉而去執行另外一段特殊程序來處理出現的緊急事務,處理結束后,CPU自動返回到原來暫停的程序中去繼續執行。 這種程序在執行過程中由於外界的原因而被中間打斷的情況,稱為中斷。
兩個重要的概念:
<1> 中斷服務函數: 內核響應中斷后執行的相應處理程序。
<2> 中斷向量:中斷服務程序的入口地址。每個中斷源都對應一個固定的入口地址。當內核響應中斷請求時,就會暫停當前的程序執行,然后跳轉到該入口地址執行代碼。
二、CC2530的中斷系統
CC2530具有18個中斷源,每個中斷源都由各自的一系列特殊功能寄存器來進行控制。可以編程設置相關特殊功能寄存器,設置18個中斷源的優先級以及使能中斷申請響應等。我們常用的中斷源有下面幾個:
三、CC2530的中斷處理函數編寫方法
中斷服務函數與一般自定義函數不同,有特定的書寫格式:
<1> 在每一個中斷服務函數之前,都要加上一句起始語句:
#pragma vector = <中斷向量>
<中斷向量>表示接下來要寫的中斷服務函數是為那個中斷源服務的,該 語句有兩種寫法:
#pragma vector = 0x7B 或者 #pragma vector = P1INT_VECTOR
前者是中斷向量的入口地址,后者是頭文件“ioCC2530.h”中的宏定義。
<2> _ _interrupt關鍵字表示該函數是一個中斷服務函數,<函數名稱>可以 自定義,函數體不能帶有參數,也不能有返回值。
四、CC2530的外部中斷
CC2530的P0、P1和P2端口中的每個引腳都具有外部中斷輸入功能,要使某些引腳具有外部中斷功能,需要對IENx寄存器、PxIEN寄存器和PICTL寄存器進行適當的設置。 除了各個中斷源都有自己的中斷使能開關之外,中斷系統還有一個總開關,可以同“EA = 1;”來打開總中斷。
P0、P1和P2端口分別使用P0IF、P1IF和P2IF作為中斷標志位,任何一個端口組上的引腳產生外部中斷時,都會將對應端口組的中斷標志自動置位。注意,外部中斷標志必須在中斷服務函數中手工清除,否則CPU會反復進入中斷。 端口狀態標志寄存器P0IFG、P1IGF和P2IFG,分別對應3個端口中各引腳的中斷觸發狀態,當某引腳發生外部中斷觸發時,對應的標志位會自動置位,這個標志同樣需要手工清除。
五、實訓案例:外部中斷輸入控制LED燈
【1】設計外部中斷初始化函數Init_INTP()
外部中斷初始化函數,主要是完成跟中斷相關的特殊功能寄存器配置工作:
<1> 配置IENx寄存器,使能端口組的中斷功能。
<2> 配置PxIEN寄存器,使能具體的外部中斷引腳。
<3> 配置PICTL寄存器,設置中斷觸發方式。
【2】設計外部中斷服務函數Int1_Sevice()
在編寫中斷服務函數的時候,書寫格式要正確,中斷向量不能搞錯。特別要注意:在函數里面把端口組和引腳的標志位清除,否則CPU將會反復進入中斷,必須先清除引腳標志位PxIFG,再清除端口組標志位PxIF。
【3】實訓項目源代碼及注釋
1 #include "ioCC2530.h" 2 3 #define LED6 P1_4 4 #define LED3 P1_0 5 #define LED4 P1_1 6 /*===================延時函數=========================*/ 7 void Delay(unsigned int t) 8 { 9 while(t--); 10 } 11 /*==================端口初始化函數=====================*/ 12 void Init_Port() 13 { 14 //將P1_0、P1_1和P1_4設置為通用I/O端口功能 15 P1SEL &= ~0x13; 16 //將P1_0、P1_1和P1_4的端口傳輸方式設置為輸出 17 P1DIR |= 0x13; 18 LED6 = 0; 19 LED3 = 0; 20 LED4 = 0; 21 } 22 /*==================跑馬燈子函數=====================*/ 23 void LED_Running() 24 { 25 LED3 = 1; 26 Delay(50000); 27 LED4 = 1; 28 Delay(50000); 29 LED3 = 0; 30 Delay(50000); 31 LED4 = 0; 32 Delay(50000); 33 } 34 /*===============外部中斷初始化函數==================*/ 35 void Init_INTP() 36 { 37 IEN2 |= 0x10; //端口1中斷使能 38 P1IEN |= 0x04; //端口P1_2外部中斷使能 39 PICTL |= 0x02; //端口P1_0到P1_3下降沿觸發 40 EA = 1; //使能總中斷 41 } 42 /*================外部中斷1服務函數====================*/ 43 #pragma vector = P1INT_VECTOR //外部中斷1的向量入口 44 __interrupt void Int1_Sevice() 45 { 46 LED6 = ~LED6; 47 /*先清除引腳標志位,再清除端口標志位,否則會不斷進入中斷*/ 48 P1IFG &= ~ 0x04; //軟件清除P1_2引腳的標志位 49 P1IF = 0; //軟件清除P1端口組的標志位 50 } 51 /*====================主函數==========================*/ 52 void main() 53 { 54 Init_Port(); //初始化通用I/O端口 55 Init_INTP(); //初始化外部中斷 56 while(1) 57 { 58 LED_Running(); //跑馬燈 59 } 60 }