裸奔程序之外部中斷檢測按鍵
實驗實驗功能:在TQ2440開發板上,利用外部中斷模式檢測按鍵是否按下,
本文引用地址:http://www.104case.com/article/201611/318703.htm如果某按鍵被按下則點亮對應某個LED。
——————————————————————————————————
#include"2440addr.h"
#include"option.h" //這個文件中定義了中斷服務程序的起始地址
#define LED1_ON (rGPBDAT &=~(1<<5))
#define LED1_OFF (rGPBDAT |=(1<<5) )
#define LED2_ON (rGPBDAT &=~(1<<6))
#define LED2_OFF (rGPBDAT |=(1<<6))
#define LED3_ON (rGPBDAT &=~(1<<7))
#define LED3_OFF (rGPBDAT |=(1<<7))
#define LED4_ON (rGPBDAT &=~(1<<8))
#define LED4_OFF (rGPBDAT |=(1<<8))
void Delay(void)
{
int i;
for(i=0;i<100000;i++);
}
/外部中斷處理函數/
void __irq IRQ_KEY1(void)
{
rSRCPND |=(1<<1); //清除中斷標志位
rINTPND |=(1<<1);
LED1_ON;
Delay();
LED1_OFF;
}
void __irq IRQ_KEY2(void)
{
rSRCPND |=(1<<4); //清除中斷標志位
rINTPND |=(1<<4);
rEINTPEND |=(1<<4); //清除ENIT4的中斷標志位
LED2_ON;
Delay();
LED2_OFF;
}
void __irq IRQ_KEY3(void)
{
rSRCPND |=(1<<2); //清除中斷標志位
rINTPND |=(1<<2);
LED3_ON;
Delay();
LED3_OFF;
}
void __irq IRQ_KEY4(void)
{
rSRCPND |=1<<0; //清除中斷標志位
rINTPND |=1<<0;
LED4_ON;
Delay();
LED4_OFF;
}
/外部中斷初始化函數/
void Eint_Init(void)
{
rGPFCON &=~(0x33f);
rGPFCON |=0x22a; //設置GPF0、1、2、4為中斷輸入功能
rEXTINT0 = 0x20222; //ENIT0、1、2、4下降沿觸發中斷
rSRCPND = 0x17; //清除ENIT0、1、2、4的中斷標志位
rINTPND = 0x17; //清除ENIT0、1、2、4的中斷標志位
rEINTPEND=(1<<4); //清除ENIT4的中斷標志位
rINTMOD=0x0; //所有中斷為IRQ中斷
rINTMSK &= ~0x17; //ENIT0、1、2、4中斷服務有效(這里就是使能外部中斷)
rEINTMASK &= ~(1<<4); //EINT4中斷服務有效
pISR_EINT0 = (unsigned)IRQ_KEY4; //設置各中斷服務子程序地址
pISR_EINT1 = (unsigned)IRQ_KEY1;
pISR_EINT2 = (unsigned)IRQ_KEY3;
pISR_EINT4_7 = (unsigned)IRQ_KEY2;
}
void Main(void)
{
rGPBCON &=~((3<<10)|(3<<12)|(3<<14)|(3<<16)); //對GPBCON[10:17]清零
rGPBCON |=((1<<10)|(1<<12)|(1<<14)|(1<<16)); //設置GPB5~8為輸出
rGPBUP &=~((1<<5)|(1<<6)|(1<<7)|(1<<8)); //設置GPB5~8的上拉功能
rGPBDAT |=(1<<5)|(1<<6)|(1<<7)|(1<<8); //關閉LED
Eint_Init();
while(1);
}
——————————————————————————————————
我們來簡單描述一下S3C2440的中斷內容,它總共有60個中斷源,分為中斷源和子中斷源;下圖為中斷源種類:
下圖為子中斷源種類:
中斷控制器所用到的中斷寄存器有八個:
中斷處理框圖如下所示(重點):
現在主要說下外部中斷(其寄存器使用說明在數據手冊的輸入輸出端口章節)
S3C2440有24個外部中斷,GPF0--GPF7對應于外部中斷EINT0--EINT7,GPG0--GPG15對應于外部中斷EINT8--EINT23,支持上升沿、下降沿、高電平、低電平、雙邊沿觸發。
設置外部中斷的一般步驟
1、選擇管腳功能為外部中斷功能
2、設置觸發方式
3、清中斷源掛起寄存器,中斷服務寄存器(可選,防止原有中斷干擾)
4、設置中斷模式(IRQ、FRQ, 默認為IRQ)
5、設置中斷優先級(可選,一般默認)
6、打開外部中斷屏蔽
7、設置中斷服務入口程序
下面我們開始分析main.c這個程序,首先從main函數開始;
進入main函數后,首先是初始化LED,這四條語句在前面LED已經講過,這里不再重復;接著調用Eint_Init();我們進入Eint_Init();函數看到,
首先是 rGPFCON &=~(0x33f); rGPFCON |=0x22a; 執行完這二句后,GPF0、1、2、4被設置為中斷輸入功能。
接著執行rEXTINT0 = 0x20222; 意思是將ENIT0、1、2、4配置為下降沿觸發中斷。
再執行rSRCPND = 0x17; 意思是清除ENIT0、1、2、4的中斷標志位,SRCPND這個寄存器是中斷請求標識的寄存器,如果SRCPND中哪一位置為1表示相應中斷源有請求,如果要清除某一位則向相應位置寫入1。
rINTPND = 0x17; 也是清除ENIT0、1、2、4的中斷標志位 INTPND同樣也是中斷源請求寄存器,如果有中斷發生,對應位會自動置1,如果要清除某一位也是向相應位寫入1。
rEINTPEND=(1<<4); //清除ENIT4的中斷標志位
rINTMOD=0x0; //所有中斷為IRQ中斷 ,INITMOD為中斷模式寄存器,有FIQ快速中斷模式,當INTMOD被置1時為FIQ模式,否則為IRQ模式,默認為IRQ模式。
rINTMSK &= ~0x17; //ENIT0、1、2、4中斷服務有效(這里就是使能外部中斷) INTMSK負責總的中斷向量屏蔽,當被置1時則被屏蔽,否則沒有被屏蔽。
rEINTMASK &= ~(1<<4);//EINT4中斷服務有效 EINTMASK負責具體某一中斷向量是否被屏蔽,當被置1時則被屏蔽,否則沒有被屏蔽。
pISR_EINT0 = (unsigned)IRQ_KEY4; //設置各中斷服務子程序地址
我們在2440addr.h頭文件里面找到 #define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
我們在option.inc匯編頭文件里面找到 _ISR_STARTADDRESS EQU 0x33ffff00 從上面二句我們知道,這是中斷服務的起始地址。
pISR_EINT0是一個中斷入口地址變量,把該中斷處理函數的首地址傳遞給該變量,即中斷入口地址。
一般來說,使用__irq這個關鍵詞來定義中斷處理函數,這樣系統會為我們自動保存一些必要的變量,并能夠在中斷處理函數執行完后正確地返回。還需要注意的是,中斷處理函數不能有返回值,也不能傳遞任何參數。
void __irq IRQ_KEY4(void)
{
rSRCPND |=1<<0; //清除中斷標志位
rINTPND |=1<<0;
LED4_ON;
Delay();
LED4_OFF;
}
這是一個外部中斷0的處理函數,
rSRCPND |=1<<0;
rINTPND |=1<<0;
執行完這二句后表示源掛起中斷標志和具體某中斷掛起標志都被清楚,其他外部中斷1、2、4處理函數亦是如此。
———————————————————————————————————
到這里,這個main.c程序就講解完畢啦。你懂了嗎?
評論