新聞中心

        LPC1114外部中斷

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

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

        本文引用地址:http://www.104case.com/article/201611/316324.htm

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

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

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

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

        從表中可以看出,每個(gè)寄存器都是32位的結(jié)構(gòu),都具有可讀可寫(xiě)的屬性,復(fù)位值都為全0。其中ISER寄存器是設(shè)置中斷的使能,32位對(duì)應(yīng)32路中斷,值為1使能中斷,值為0不使能中斷。ICER寄存器是設(shè)置中斷的禁能,32位對(duì)應(yīng)32路中斷,值為1禁能中斷,值為0不禁能。ISPR寄存器是設(shè)置中斷的掛起,32位對(duì)應(yīng)32路中斷,值為1掛起,值為0不掛起。ICPR寄存器是清除中斷的掛起,32位對(duì)應(yīng)32路中斷,值為1清除掛起,值為0不清除掛起。IPR0~7寄存器是設(shè)置中斷優(yōu)先級(jí)。

        下面是NVIC寄存器組所對(duì)應(yīng)的結(jié)構(gòu)體形式(位于頭文件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,所以要將基址指針強(qiáng)制轉(zhuǎn)換為上述結(jié)構(gòu)體,還必須要加上下面的定義。

        #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 */

        接下來(lái)給出的是上面NVIC32位寄存器所對(duì)應(yīng)的32路中斷向量的中斷源。

        為了能描述上面的32路中斷源,在C語(yǔ)言中運(yùn)用了枚舉類(lèi)型,代碼如下所示(位于頭文件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)先級(jí)更高5個(gè)中斷源。這里先不進(jìn)行說(shuō)明,在后面用到時(shí)再來(lái)討論。定義好上述代碼后,就可以來(lái)寫(xiě)中斷所需要的函數(shù)了。下面就是依據(jù)CMSIS規(guī)范所定義的8個(gè)中斷操作函數(shù)(位于頭文件core_cm0.h中)。

        1.允許某個(gè)中斷或異常

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

        2.禁止某個(gè)中斷或異常

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

        3.讀取某個(gè)中斷或異常的掛起狀態(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.把某個(gè)中斷或異常的掛起狀態(tài)設(shè)為1

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

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

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

        6.把某個(gè)中斷或異常的可配置優(yōu)先級(jí)設(shè)為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.讀取某個(gè)中斷或異常的優(yōu)先級(jí)

        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.復(fù)位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ù)中有幾點(diǎn)要說(shuō)明一下,一是數(shù)組的引用其取值只能是0(即第一個(gè)元素),這是因?yàn)樵诮Y(jié)構(gòu)體定義中只定義了一個(gè)數(shù)組元素,且由于需要利用數(shù)組的地址連續(xù)性來(lái)對(duì)映CPU物理地址,所以也不能將其定義為一個(gè)普通變量;二是關(guān)鍵字“__INLINE”在頭文件core_cm0.h中已做了宏定義“#define __INLINE __inline”,__inline是通知編譯器其后面的函數(shù)為內(nèi)聯(lián)形式;三是中斷源IRQn要與0x1F與一下,是為了屏蔽高27位的值,因?yàn)橹袛嘣吹淖畲笾抵坏?1,所以只用了32位中的低5位(31的二進(jìn)制是11111,十六進(jìn)制是0x1F);四是在函數(shù)的參數(shù)中,由于引入了枚舉類(lèi)型,所以可以在調(diào)用函數(shù)的時(shí)候,在參數(shù)部分可直接使用枚舉中的名稱,這樣就可以省去記憶32個(gè)中斷源在32位寄存器中的對(duì)應(yīng)位置,便于書(shū)寫(xiě)和閱讀。例如,要開(kāi)啟端口0的外部中斷,執(zhí)行程序“NVIC_EnableIRQ(EINT0_IRQn)”即可。

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

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

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

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

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

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

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



        關(guān)鍵詞: LPC1114外部中

        評(píng)論


        技術(shù)專(zhuān)區(qū)

        關(guān)閉
        主站蜘蛛池模板: 台北县| 东丰县| 巴南区| 博乐市| 岚皋县| 黎平县| 潜山县| 怀来县| 上杭县| 景东| 华容县| 潞西市| 乌审旗| 铁力市| 英德市| 上高县| 德令哈市| 宽甸| 昌黎县| 延川县| 德阳市| 新宁县| 公主岭市| 黄龙县| 罗定市| 大石桥市| 玛纳斯县| 贡嘎县| 惠州市| 逊克县| 晋城| 扎囊县| 和平县| 庄河市| 安塞县| 调兵山市| 宝鸡市| 吉林市| 吉安县| 新和县| 方山县|