外部引腳中斷


外部中斷作為處理器響應外部事件的通道,在控制系統中起着非常重要的作用。從前面的討論中我們知道,在NVIC中有8個外部中斷源,下面就來討論一下這8個外部中斷的使用情況。
LPC824的每一根引腳都可以響應一個外部中斷,所以理論上有多少個引腳就有多少個外部中斷。但由於LPC824采用了引腳掛接外部中斷源的形式,所以並不是所有的引腳都可以同時設置為外部中斷引腳。在LPC824中,可同時響應的外部中斷源只有8個(即NVIC的8路引腳中斷),所以同時只能有8個外部中斷引腳在工作,但這8個外部中斷引腳可選擇從PIO0_0至PIO0_28中的任意一根。

LPC824外部引腳中斷所涉及到的寄存器如下表所示。

從上表中可以看到,在LPC824的引腳中斷控制中,一共使用了13個寄存器。下面是這些寄存器組所對應的結構體形式(位於頭文件LPC82x.h中)。
typedef struct {       
  __IO uint32_t  ISEL; 
  __IO uint32_t  IENR; 
  __O  uint32_t  SIENR;
  __O  uint32_t  CIENR;
  __IO uint32_t  IENF; 
  __O  uint32_t  SIENF;
  __O  uint32_t  CIENF;
  __IO uint32_t  RISE; 
  __IO uint32_t  FALL; 
  __IO uint32_t  IST;  
  __IO uint32_t  PMCTRL;
  __IO uint32_t  PMSRC;
  __IO uint32_t  PMCFG;
} LPC_PIN_INT_Type;
因為引腳中斷寄存器組的基址為0xA0004000,所以要將基址指針強制轉換為上述結構體,還必須要加上下面的定義。
#define LPC_PIN_INT_BASE                0xA0004000UL
#define LPC_PIN_INT                     ((LPC_PIN_INT_Type *) LPC_PIN_INT_BASE)
下面先對其中與外部引腳中斷相關的10個寄存器的功能進行討論,另外3個與模式匹配相關的寄存器后面再專門討論。先來看引腳中斷模式寄存器ISEL,其字節地址為0xA0004000,下表給出了它的全部位結構。
(1)第0到7位為8個外部中斷引腳的模式選擇位,置0時,對應的外部中斷被設置為邊沿觸發型,置1時,設置為電平觸發型,默認為邊沿觸發型。
(2)第8到31位為保留位。
下表給出的是 引腳中斷電平或上升沿中斷使能寄存器IENR的全部位結構,其字節地址為0xA0004004。
(1)第0到7位為引腳中斷的上升沿或電平中斷選擇位,置0時,對應的外部中斷被禁用上升沿或電平中斷,置1時,使能上升沿或電平中斷,默認為禁用上升沿或電平中斷。
(2)第8到31位為保留位。
下表給出的是引腳中斷電平或上升沿中斷置位寄存器SIENR的全部位結構,其字節地址為0xA0004008。SIENR寄存器實際上為了對IENR寄存器進行單獨的置位操作而設立的,如果是按字(或字節)操作直接寫IENR寄存器即可。
(1)在第0到7位中寫入1會置位IENR寄存器中相對應的位,從而使能上升沿或電平中斷,置0時無影響。
(2)第8到31位為保留位。
下表給出的是引腳中斷電平或上升沿中斷清零寄存器CIENR的全部位結構,其字節地址為0xA000400C。CIENR寄存器實際上為了對IENR寄存器進行單獨的清零操作而設立的,如果是按字(或字節)操作直接寫IENR寄存器即可。
(1)在第0到7位中寫入1會清零IENR寄存器中相對應的位,從而禁用上升沿或電平中斷,置0時無影響。
(2)第8到31位為保留位。
下表給出的是引腳中斷有效電平或下降沿中斷使能寄存器IENF的全部位結構,其字節地址為0xA0004010。
(1)第0到7位為引腳中斷的下降沿或有效中斷電平選擇位,置0時,對應的外部中斷被禁用下降沿中斷或置位有效中斷電平為低電平,置1時,使能下降沿中斷使能或置位有效中斷電平為高電平,默認為禁用下降沿中斷或置位有效中斷電平為低電平。
(2)第8到31位為保留位。
下表給出的是引腳中斷有效電平或下降沿中斷置位寄存器SIENF的全部位結構,其字節地址為0xA0004014。SIENF寄存器實際上為了對IENF寄存器進行單獨的置位操作而設立的,如果是按字(或字節)操作直接寫IENF寄存器即可。
(1)在第0到7位中寫入1會置位IENF寄存器中相對應的位,從而使能下降沿中斷或置位有效中斷電平為高電平,寫0時無影響。
(2)第8到31位為保留位。
下表給出的是引腳中斷有效電平或下降沿中斷清零寄存器CIENF的全部位結構,其字節地址為0xA0004018。CIENF寄存器實際上為了對IENF寄存器進行單獨的清零操作而設立的,如果是按字(或字節)操作直接寫IENF寄存器即可。
(1)在第0到7位中寫入1會清零IENF寄存器中相對應的位,從而禁用下降沿中斷或置位有效中斷電平為低電平,寫0時無影響。
(2)第8到31位為保留位。
下表給出的是引腳中斷上升沿寄存器RISE的全部位結構,其字節地址為0xA000401C。
(1)在第0到7位中寫入1會清除相應引腳的上升沿檢測標記,從而為下一次上升沿檢測作准備,寫0時無影響。若在相應的位上讀取到1,則表示自復位或上一次向該位寫1清除起,對應的引腳上檢測到了上升沿,讀取到0,則表示對應引腳上未檢測到上升沿。
(2)第8到31位為保留位
下表給出的是引腳中斷下降沿寄存器FALL的全部位結構,其字節地址為0xA0004020。
(1)在第0到7位中寫入1會清除相應引腳的下降沿檢測標記,從而為下一次下降沿檢測作准備,寫0時無影響。若在相應的位上讀取到1,則表示自復位或上一次向該位寫1清除起,對應的引腳上檢測到了下降沿,讀取到0,則表示對應引腳上未檢測到下降沿。
(2)第8到31位為保留位。
下表給出的是引腳中斷狀態寄存器IST的全部位結構,其字節地址為0xA0004024。
(1)在第0到7位中寫入1時,對於邊沿觸發型中斷,將會清除對應引腳的上升和下降沿檢測,對於電平觸發型中斷,將會切換對應引腳上的有效電平,寫0時無影響。若在相應的位上讀取到1,則表示對應的中斷引腳上有正在請求的外部中斷,讀取到0,則表示對應的中斷引腳上無正在請求的外部中斷。
(2)第8到31位為保留位。
注意,電平觸發的中斷會由硬件在有效電平消失時自動清除標志,並沒有軟件清除電平中斷標志的操作。
以上10個寄存器就是LPC824中與外部引腳中斷相關寄存器,其實除了這10個寄存器以外,還有1個名為PINTSEL的寄存器也與外部引腳中斷密切相關,只不過它不在上述寄存器組中,而是位於SYSCON模塊中。下表就給出了引腳中斷選擇寄存器PINTSEL的全部位結構,這樣的寄存器一共有8個(PINTSEL0~PINTSEL7),其字節地址從0x40048178到0x40048194。
(1)第0到5位用來選擇外部中斷的引腳編號,范圍從PIO0_0到PIO0_28共29根引腳。
(2)第6到31位為保留位。
注意,PINTSEL寄存器一共有8個,也即LPC824的外部引腳中斷同時最多只能使用8個,但每一個外部中斷都可以在全部PIO0_0到PIO0_28端口中選擇引腳。 相當於PINTSEL0~PINTSEL7是8個外部中斷源,具體哪個中斷源使用哪個引腳,是根據PINTSEL寄存器的配置來確定的。
在討論完了寄存器的功能后,下面就來分解一下把某個引腳配置為外部中斷模式的具體步驟:
1、確定要配置為中斷模式的引腳,然后在SYSCON模塊的PINTSEL寄存器中進行選擇設置,一共可以配置8個外部中斷引腳。例如,執行“LPC_SYSCON->PINTSEL0 |= 0x01;”語句后,就把PIO0_1引腳設置為了外部中斷引腳。
2、確定是電平觸發還是邊沿觸發,通過ISEL寄存器進行選擇配置。例如,執行“LPC_PIN_INT->ISEL &= ~0x01;”語句后,就把PIO0_1引腳設置為邊沿觸發方式(其實默認就是邊沿觸發方式,此句也可不寫)。
3、若上一步配置成電平觸發,則需要確定是低電平觸發還是高電平觸發,若是邊沿觸發,則需要確定是上升沿觸發還是下降沿觸發,通過IENR或IENF寄存器進行執行配置。例如,執行“LPC_PIN_INT->IENR |= 0x01;”語句后,就把PIO0_1引腳設置為上升沿觸發方式;執行“LPC_PIN_INT->IENF |= 0x01;”語句后,就把PIO0_1引腳設置為下降沿觸發方式。
4、在第3步中,還可以通過訪問SIENR和CIENR寄存器來更改IENR寄存器中的某一位,通過訪問SIENF和CIENF寄存器來更改IENF寄存器中的某一位。SIENR、CIENR和SIENF、CIENF這四個寄存器其實是IENR和IENF寄存器的伴侶寄存器,用來優化位操作,以避免對IENR和IENF寄存器直接執行“讀—改—寫”的操作,提高效率。
5、使能NVIC中的相關外部中斷。例如,執行“NVIC_EnableIRQ(PIN_INT0_IRQn);”語句后,就使能了PIO0_1上的外部引腳中斷。
6、在中斷服務程序中,需要清除原有的外部中斷標記,以保證下一次外部中斷順利觸發,通過訪問RISE寄存器來清除上升沿中斷標記,通過訪問FALL寄存器來清除下降沿標記。例如,執行“LPC_PIN_INT->RISE |= 0x01;”語句后,PIO0_1原來的上升沿中斷標記就被清除了。執行“LPC_PIN_INT->FALL |= 0x01;”語句后,PIO0_1原來的下降沿中斷標記就被清除了。
7、在第6步中,也可以通過訪問IST寄存器來清除邊沿(包括上升沿和下降沿)觸發的標記。執行“LPC_PIN_INT->IST |= 0x01;”語句后,PIO0_1原來的邊沿中斷標記就被清除了。
上述步驟也可通過下圖來描述。
最后需要說明一點,即使某個引腳並不作為GPIO使用,也能配接到PININT的中斷源上。比如:要自動探測4個I2C接口中哪一個被連接到主機上,即可以把它們4個的SCL線所在的IO引腳分別配接到4路PININT中斷上。通信時,發生哪個中斷,就認為連接到了哪個I2C接口上。而此時,IO引腳並沒有作為GPIO使用,而是作為I2C的SCL信號接口。
此外,對於外部引腳中斷,在MDK5的開發環境中有特定的入口函數形式,比如對於PINTSEL0的中斷,函數形式如下所示。
 void PIN_INT0_IRQHandler(void)
{
       PINTSEL0中斷服務程序部分
}
下面來看一個外部引腳中斷的實際例子,電路原理圖如下所示。
在上面的電路中,兩個按鍵S1和S2分別接到了引腳PIO0_4和PIO0_1上,並且都為其配置了上拉阻。現在要求按下S1時,對LED1狀態進行取反,按下S2時,對LED2狀態進行取反,其中S1采用上升沿方式檢測,S2采用下降沿方式檢測。完整代碼如下:

#include <LPC82x.h>
//************************端口初始化***********************************
void Port_init(void)
{
LPC_GPIO_PORT->DIRSET0 = (1<<7) | (1<<13); //設置端口為輸出方向
LPC_GPIO_PORT->SET0 = (1<<7) | (1<<13); //熄滅LED
}
//***************************主函數************************************
int main(void)
{
Port_init(); //調用端口初始化
LPC_SYSCON->PINTSEL0 = 0x1;//選擇PIO0_1作為外部中斷引腳
LPC_SYSCON->PINTSEL1 = 0x4;//選擇PIO0_4作為外部中斷引腳
// LPC_PIN_INT->ISEL &= ~0x3; //邊沿觸發
LPC_PIN_INT->IENR |= 0x1; //PINTSEL0上升沿使能
LPC_PIN_INT->IENF |= 0x2; //PINTSEL1下降沿使能
NVIC_EnableIRQ(PIN_INT0_IRQn);//使能PINTSEL0中斷
NVIC_EnableIRQ(PIN_INT1_IRQn);//使能PINTSEL1中斷
while(1)
{
;
}
}
//*********************PINTSEL0中斷(S2)*****************************
void PIN_INT0_IRQHandler(void)
{
LPC_GPIO_PORT->NOT0 = 0x2000; //LED2取反
LPC_PIN_INT->RISE |= 0x1;
}
//*********************PINTSEL1中斷(S1)*****************************
void PIN_INT1_IRQHandler(void)
{
LPC_GPIO_PORT->NOT0 = 0x80; //LED1取反
LPC_PIN_INT->FALL |= 0x2;
}

把程序編譯后下載到LPC824中,初始狀態LED都不亮,按下S1,LED1仍然不亮,松開S1,LED1亮,證明上升沿有效,再次按下S1,LED1仍然亮,松開S1,LED1熄滅,證明上升沿有效。 按下S2,LED2亮,松開S2,LED2仍然亮,證明下降沿有效,再次按下S2,LED2熄滅,松開S2,LED2仍然熄滅,證明下降沿有效。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM