<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > LPC1114外部中斷

          LPC1114外部中斷

          作者: 時間:2016-11-13 來源:網(wǎng)絡 收藏
          外部中斷作為處理器響應外部事件的通道,在控制系統(tǒng)中起著非常重要的作用。下面就來討論一下LPC1114外部中斷的使用情況。

          LPC1114的每一個引腳都可以響應一個外部中斷,所以有多少個引腳就有多少個外部中斷。但LPC1114的中斷系統(tǒng)非常強大,外部中斷只是它其中的一小部分。因此,要用好外部中斷,就必須先來了解LPC1114的整個中斷系統(tǒng)。下面就來看一下它的中斷系統(tǒng)。

          本文引用地址:http://www.ex-cimer.com/article/201611/316324.htm

          在LPC11xx系列處理器中,有一個部分被稱為“私有外設總線”(Private peripheral bus),它位于Memory map中地址為0xE0000000~0xE0100000的地方,包含有下表中的幾個核心外設。

          其中的Nested Vectored Interrupt Contorller(NVIC)就是中斷系統(tǒng),被稱為“內(nèi)嵌套向量中斷控制器”。它與處理器內(nèi)核緊密耦合,可實現(xiàn)低中斷延遲及對新中斷的有效處理。它具有以下特征:

          擁有32路向量中斷;每個中斷的優(yōu)先級均可編程設置為0~192(步長64),數(shù)值越小優(yōu)先級越高,0級為最高優(yōu)先級;支持電平和邊沿觸發(fā)中斷;支持中斷尾鏈;擁有一個外部不可屏蔽中斷NMI。

          NVIC所涉及到的寄存器如下表所示。

          從表中可以看出,每個寄存器都是32位的結構,都具有可讀可寫的屬性,復位值都為全0。其中ISER寄存器是設置中斷的使能,32位對應32路中斷,值為1使能中斷,值為0不使能中斷。ICER寄存器是設置中斷的禁能,32位對應32路中斷,值為1禁能中斷,值為0不禁能。ISPR寄存器是設置中斷的掛起,32位對應32路中斷,值為1掛起,值為0不掛起。ICPR寄存器是清除中斷的掛起,32位對應32路中斷,值為1清除掛起,值為0不清除掛起。IPR0~7寄存器是設置中斷優(yōu)先級。

          下面是NVIC寄存器組所對應的結構體形式(位于頭文件core_cm0.h中)。

          typedef struct
          {
          __IO uint32_t ISER[1]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
          uint32_t RESERVED0[31];
          __IO uint32_t ICER[1]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
          uint32_t RSERVED1[31];
          __IO uint32_t ISPR[1]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
          uint32_t RESERVED2[31];
          __IO uint32_t ICPR[1]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
          uint32_t RESERVED3[31];
          uint32_t RESERVED4[64];
          __IO uint32_t IP[8]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */
          } NVIC_Type;

          因NVIC寄存器組的基址為0xE000E100,所以要將基址指針強制轉(zhuǎn)換為上述結構體,還必須要加上下面的定義。

          #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
          #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */
          #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */

          接下來給出的是上面NVIC32位寄存器所對應的32路中斷向量的中斷源。

          為了能描述上面的32路中斷源,在C語言中運用了枚舉類型,代碼如下所示(位于頭文件lpc11xx.h中)。

          typedef enum IRQn
          {
          /****** Cortex-M0 Processor Exceptions Numbers ***************************************************/
          NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
          HardFault_IRQn = -13, /*!< 3 Cortex-M0 Hard Fault Interrupt */
          SVCall_IRQn = -5, /*!< 11 Cortex-M0 SV Call Interrupt */
          PendSV_IRQn = -2, /*!< 14 Cortex-M0 Pend SV Interrupt */
          SysTick_IRQn = -1, /*!< 15 Cortex-M0 System Tick Interrupt */
          /****** LPC11xx/LPC11Cxx Specific Interrupt Numbers **********************************************/
          WAKEUP0_IRQn = 0, /*!< All I/O pins can be used as wakeup source. */
          WAKEUP1_IRQn = 1, /*!< There are 13 pins in total for LPC11xx */
          WAKEUP2_IRQn = 2,
          WAKEUP3_IRQn = 3,
          WAKEUP4_IRQn = 4,
          WAKEUP5_IRQn = 5,
          WAKEUP6_IRQn = 6,
          WAKEUP7_IRQn = 7,
          WAKEUP8_IRQn = 8,
          WAKEUP9_IRQn = 9,
          WAKEUP10_IRQn = 10,
          WAKEUP11_IRQn = 11,
          WAKEUP12_IRQn = 12,
          CAN_IRQn = 13, /*!< CAN Interrupt */
          SSP1_IRQn = 14, /*!< SSP1 Interrupt */
          I2C_IRQn = 15, /*!< I2C Interrupt */
          TIMER_16_0_IRQn = 16, /*!< 16-bit Timer0 Interrupt */
          TIMER_16_1_IRQn = 17, /*!< 16-bit Timer1 Interrupt */
          TIMER_32_0_IRQn = 18, /*!< 32-bit Timer0 Interrupt */
          TIMER_32_1_IRQn = 19, /*!< 32-bit Timer1 Interrupt */
          SSP0_IRQn = 20, /*!< SSP0 Interrupt */
          UART_IRQn = 21, /*!< UART Interrupt */
          Reserved0_IRQn = 22, /*!< Reserved Interrupt */
          Reserved1_IRQn = 23,
          ADC_IRQn = 24, /*!< A/D Converter Interrupt */
          WDT_IRQn = 25, /*!< Watchdog timer Interrupt */
          BOD_IRQn = 26, /*!< Brown Out Detect(BOD) Interrupt */
          FMC_IRQn = 27, /*!< Flash Memory Controller Interrupt */
          EINT3_IRQn = 28, /*!< External Interrupt 3 Interrupt */
          EINT2_IRQn = 29, /*!< External Interrupt 2 Interrupt */
          EINT1_IRQn = 30, /*!< External Interrupt 1 Interrupt */
          EINT0_IRQn = 31, /*!< External Interrupt 0 Interrupt */
          } IRQn_Type;

          從上述代碼中可以看出,除了32路中斷源外,還加入了優(yōu)先級更高5個中斷源。這里先不進行說明,在后面用到時再來討論。定義好上述代碼后,就可以來寫中斷所需要的函數(shù)了。下面就是依據(jù)CMSIS規(guī)范所定義的8個中斷操作函數(shù)(位于頭文件core_cm0.h中)。

          1.允許某個中斷或異常

          static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
          {
          NVIC->ISER[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
          }

          2.禁止某個中斷或異常

          static __INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
          {
          NVIC->ICER[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
          }

          3.讀取某個中斷或異常的掛起狀態(tài)

          static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
          {
          return((uint32_t) ((NVIC->ISPR[0] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
          }

          4.把某個中斷或異常的掛起狀態(tài)設為1

          static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
          {
          NVIC->ISPR[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
          }

          5.把某個中斷或異常的掛起狀態(tài)清為0

          static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
          {
          NVIC->ICPR[0] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* Clear pending interrupt */
          }

          6.把某個中斷或異常的可配置優(yōu)先級設為1

          static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
          {
          if(IRQn < 0) {
          SCB->SHP[_SHP_IDX(IRQn)] = (SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |
          (((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }
          else {
          NVIC->IP[_IP_IDX(IRQn)] = (NVIC->IP[_IP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |
          (((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }
          }

          7.讀取某個中斷或異常的優(yōu)先級

          static __INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)
          {

          if(IRQn < 0) {
          return((uint32_t)((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for Cortex-M0 system interrupts */
          else {
          return((uint32_t)((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for device specific interrupts */
          }

          8.復位NVIC

          static __INLINE void NVIC_SystemReset(void)
          {
          __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */
          SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos)| SCB_AIRCR_SYSRESETREQ_Msk);
          __DSB(); /* Ensure completion of memory access */
          while(1); /* wait until reset */
          }

          在上述函數(shù)中有幾點要說明一下,一是數(shù)組的引用其取值只能是0(即第一個元素),這是因為在結構體定義中只定義了一個數(shù)組元素,且由于需要利用數(shù)組的地址連續(xù)性來對映CPU物理地址,所以也不能將其定義為一個普通變量;二是關鍵字“__INLINE”在頭文件core_cm0.h中已做了宏定義“#define __INLINE __inline”,__inline是通知編譯器其后面的函數(shù)為內(nèi)聯(lián)形式;三是中斷源IRQn要與0x1F與一下,是為了屏蔽高27位的值,因為中斷源的最大值只到31,所以只用了32位中的低5位(31的二進制是11111,十六進制是0x1F);四是在函數(shù)的參數(shù)中,由于引入了枚舉類型,所以可以在調(diào)用函數(shù)的時候,在參數(shù)部分可直接使用枚舉中的名稱,這樣就可以省去記憶32個中斷源在32位寄存器中的對應位置,便于書寫和閱讀。例如,要開啟端口0的外部中斷,執(zhí)行程序“NVIC_EnableIRQ(EINT0_IRQn)”即可。

          上述就是LPC1114中的整個中斷系統(tǒng),即“內(nèi)嵌套向量中斷控制器”。可以看出,它控制著整個處理器32路中斷源的使能與掛起等8個動作,功能非常強大。但做為外部中斷的端口中斷源卻只有4個,即EINT0_IRQn、EINT1_IRQn、EINT2_IRQn、EINT3_IRQn四個。而每一個端口又對應有12個引腳(端口3為6個)又都可以產(chǎn)生外部中斷,那怎么來判斷是那個引腳上申請的中斷呢?這就需要借助前面“通用輸入/輸出端口”部分介紹過的MIS寄存器了。在外部中斷響應的服務程序內(nèi),判別MIS寄存器的各個位,值為1的位所對應的就是觸發(fā)本次外部中斷的引腳。

          和所有的單片機一樣,在中斷響應后,程序指針會跳轉(zhuǎn)到相應的中斷向量入口處去執(zhí)行中斷服務程序,而在C語言中則是以特定形式的中斷入口函數(shù)來呈現(xiàn)。比如EINT0_IRQn、EINT1_IRQn、EINT2_IRQn、EINT3_IRQn四個端口的外部中斷入口函數(shù)分別如下:

          void PIOINT0_IRQHandler(void)
          {
          端口0的中斷服務程序部分
          }
          void PIOINT1_IRQHandler(void)
          {
          端口1的中斷服務程序部分
          }
          void PIOINT2_IRQHandler(void)
          {
          端口2的中斷服務程序部分
          }
          void PIOINT3_IRQHandler(void)
          {
          端口3的中斷服務程序部分
          }
          上述函數(shù)的名稱是不能改變的,它標志著特定的中斷入口,除了四個外部中斷以外的其它中斷源,也有各自的中斷入口函數(shù),它們都位于起動文件“startup_LPC11xx.s”中,在以后用到時再討論,這里就不給出了。

          下面來討論一個外部中斷的例子,要求使用外部中斷來實現(xiàn)按鍵控制LED的亮滅。程序代碼如下(假設KEY接在GPIO1.9,LED接在GPIO1.0):

          #include
          //=================端口1的外部中斷服務程序=====================
          void PIOINT1_IRQHandler(void)
          {
          if((LPC_GPIO1->MIS&0x200)==0x200)//檢測是否是GPIO1.9引腳上的中斷
          {
          LPC_GPIO1->MASKED_ACCESS[1] = 0; //開啟LED
          while(LPC_GPIO1->MASKED_ACCESS[512] != 0x200); //等待GPIO1.9引腳按鍵釋放
          LPC_GPIO1->MASKED_ACCESS[1] = 1; //關閉LED
          }
          LPC_GPIO1->IC |= 0x200; //清除GPIO1.9引腳上的中斷標志
          }
          //==========================主程序============================
          int main(void)
          {
          LPC_SYSCON->SYSAHBCLKCTRL |= (1<<16); //使能IOCON時鐘
          LPC_IOCON->R_PIO1_0 = 0XD1; //把芯片上的33腳設置為GPIO1.0功能
          LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<16); //禁能IOCON時鐘
          LPC_GPIO1->DIR &= ~(1<<9); //設置GPIO1.9為輸入方向
          LPC_GPIO1->DIR |= (1<<0); //設置GPIO1.0為輸出方向
          LPC_GPIO1->MASKED_ACCESS[1] = 1; //輸出高電平,關閉LED
          LPC_GPIO1->IS &= ~(1<<9); //選擇中斷為邊沿觸發(fā)
          LPC_GPIO1->IEV &= ~(1<<9); //選擇下降沿觸發(fā)
          LPC_GPIO1->IE |= (1<<9); //設置中斷P1.9不被屏蔽
          NVIC_EnableIRQ(EINT1_IRQn); //使能GPIO1中斷
          while(1)
          {
          ;
          }
          }

          把上述程序編譯后下載到LPC1114中,給系統(tǒng)上電,可以看出在按下KEY后LED亮,放開KEY后LED滅,達到了使用外部中斷控制的目的。

          最后說明一點,如果需要打開或關閉中斷“總中斷”,可調(diào)用“__enable_irq();和__disable_irq();”來實現(xiàn),它們是通過調(diào)用匯編語言來實現(xiàn)這一操作的,具體的原型在頭文件“core_cmFunc.h”中,可自行查看,這里就不詳述了。



          關鍵詞: LPC1114外部中

          評論


          技術專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();