關鍵函數:
- NVIC_EnableIRQ(IRQn_Type IRQn):使能中斷
例5-1:單按鍵中斷方式實現led燈的亮滅
在上一講LP-MSPM0G3507學習--04GPIO控制中實現了通過按鍵控制led燈的亮滅,可以看出程序效率不高,下面采用中斷的方式實現,其中的配置大部分相同,除了將管腳buttoninterrupts設置為中斷:
?需要注意的是觸發極性(triggler polarity),有4種:
- ?diabled--可能是電平觸發(此時應該是低電平觸發,因為有上拉電阻了)
- trigger on rising edge--上升沿觸發
- trigger on falling edge--下降沿觸發
- trigger on both Edg--雙邊沿觸發
從電路中可以看出,PB21應該上拉電阻,且采用邊沿觸發時,中斷觸發方式應該設為下降沿觸發
#include "ti_msp_dl_config.h"int main(void)
{SYSCFG_DL_init();NVIC_EnableIRQ(GPIOB_INT_IRQn);//開啟按鍵引腳的GPIOB端口中斷while (1) {}
}
void GROUP1_IRQHandler(void){//GPIO中斷服務函數DL_GPIO_togglePins(LED_PORT,LED_LED1_PIN);
}
分析:
這里涉及到兩個函數NVIC_EnableIRQ(),GROUP_IRQ_IRQHandler()
首先了解,NVIC,即嵌套矢量中斷控制器,用來管理外設中斷。有關的函數在ti\mspm0_sdk_2_05_01_00\source\third_party\CMSIS\Core\include\core_cm0plus.h中
另外,中斷號定義在i\mspm0_sdk_2_05_01_00\source\ti\devicws\msp\mspmog350x.h中
查閱數據手冊的時候,發現3507中只有兩個外設中斷組:INT_GROUP0、INT_GROUP1.本實驗要用到的只有按鍵和LED,所以只有GPIO這一部分的中斷,根據數據手冊,可以知道GPIO的中斷觸發后,都是通過GRP1線將中斷發布到總線,總線識別到之后就進入中斷服務函數中執行內容。
GPIO引腳的中斷服務函數(ISR)需在代碼中直接定義,其位置和聲明方式遵循以下核心規則:
1.?中斷服務函數的定義位置
-
直接在C文件中實現:GPIO中斷屬于
INT_GROUP1
組,因此中斷服務函數必須命名為?GROUP1_IRQHandler
,并在工程內的C文件(如main.c
或自定義的ISR文件)中實現。
示例代碼:?void GROUP1_IRQHandler(void) { // 中斷處理邏輯 }
-?無需頭文件聲明:此函數是ARM Cortex-M預定義的中斷向量之一,由鏈接腳本自動關聯到中斷向量表,無需在頭文件中顯式聲明9。
2.?函數內部處理邏輯
在GROUP1_IRQHandler
內,需通過以下步驟區分具體的中斷源(如不同GPIO引腳):
-
查詢中斷索引(IIDX):
使用DL_Interrupt_getPendingGroup(DL_INTERRUPT_GROUP_1)
獲取觸發中斷的外設索引。 -
判斷GPIO端口:
通過switch-case
匹配GPIO端口的IIDX宏(如GPIOA_INT_IIDX
或GPIOB_INT_IIDX
)。 -
檢查具體引腳狀態:
若同一端口有多個引腳使能中斷,需調用DL_GPIO_getEnabledInterruptStatus()
并檢查引腳位掩碼
完整示例:
void GROUP1_IRQHandler(void) {switch (DL_Interrupt_getPendingGroup(DL_INTERRUPT_GROUP_1)) {case DL_INTERRUPT_GROUP1_IIDX_GPIOA: // GPIOA中斷uint32_t status = DL_GPIO_getEnabledInterruptStatus(GPIOA);if (status & GPIO_PIN_12) { // 檢查PA12引腳DL_GPIO_togglePins(GPIO_LED_PORT, GPIO_LED_PIN);DL_GPIO_clearInterruptStatus(GPIOA, GPIO_PIN_12); // 清除標志}break;// 其他GPIO端口處理...}
}
3.?配置與使能中斷
-
SysConfig圖形化配置:
在CCS的SysConfig工具中需啟用GPIO中斷,設置觸發邊沿(如下降沿),并指定引腳。 -
代碼使能中斷:
主函數中調用NVIC_EnableIRQ(GPIOx_INT_IRQN)
(如GPIOA_INT_IRQn
)激活NVIC中斷。
4.?關鍵注意事項
-
中斷標志清除:
在ISR內必須清除中斷標志,否則會重復觸發。使用DL_GPIO_clearInterruptStatus()
或DL_Interrupt_clearFlag()
。 -
變量聲明:
跨中斷共享的變量(如delay_time
)需加volatile
關鍵字防止優化錯誤。 -
調試陷阱:
若未正確定義GROUP1_IRQHandler
,程序可能跳轉至默認錯誤處理(如死循環)。建議添加調試斷點(__BKPT(0)
)輔助排查。
附:GPIO中斷相關宏定義示例
宏名稱 | 作用 | 示例值 |
---|---|---|
GPIO_SWITCHES_GPIOA_INT_IRQN | GPIOA中斷號 | GPIOA_INT_IRQn |
DL_INTERRUPT_GROUP1_IIDX_GPIOA | GPIOA在GROUP1中的索引 | 由SDK頭文件定義 |
GPIO_SWITCHES_USER_SWITCH_1_PIN | 具體引腳宏 | DL_GPIO_PIN_12 |
附:其他的中斷名:?
其他的一些中斷名為(定義在C:\ti\mspm0_sdk_2_05_01_00\source\ti\devices\msp\m0p\startup_system_files\ticlang\startup_mspm0g350x_ticlang.c)中:
extern void GROUP0_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void GROUP1_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void TIMG8_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void UART3_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void ADC0_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void ADC1_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void CANFD0_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void DAC0_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void SPI0_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void SPI1_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void UART1_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void UART2_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void UART0_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void TIMG0_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void TIMG6_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void TIMA0_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void TIMA1_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void TIMG7_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void TIMG12_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void I2C0_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void I2C1_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void AES_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void RTC_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
extern void DMA_IRQHandler(void)__attribute__((weak, alias("Default_Handler")));
中斷號定義在ti\mspm0_sdk_2_05_01_00\source\ti\devices\msp\m0p\mspm0g350x.h
typedef enum IRQn
{NonMaskableInt_IRQn = -14, /* 2 Non Maskable Interrupt */HardFault_IRQn = -13, /* 3 Hard Fault Interrupt */SVCall_IRQn = -5, /* 11 SV Call Interrupt */PendSV_IRQn = -2, /* 14 Pend SV Interrupt */SysTick_IRQn = -1, /* 15 System Tick Interrupt */SYSCTL_INT_IRQn = 0, /* 16 SYSCTL_INT Interrupt */WWDT1_INT_IRQn = 0, /* 16 WWDT1_INT Interrupt */WWDT0_INT_IRQn = 0, /* 16 WWDT0_INT Interrupt */FLASHCTL_INT_IRQn = 0, /* 16 FLASHCTL_INT Interrupt */DEBUGSS_INT_IRQn = 0, /* 16 DEBUGSS_INT Interrupt */GPIOB_INT_IRQn = 1, /* 17 GPIOB_INT Interrupt */GPIOA_INT_IRQn = 1, /* 17 GPIOA_INT Interrupt */TRNG_INT_IRQn = 1, /* 17 TRNG_INT Interrupt */COMP0_INT_IRQn = 1, /* 17 COMP0_INT Interrupt */COMP1_INT_IRQn = 1, /* 17 COMP1_INT Interrupt */COMP2_INT_IRQn = 1, /* 17 COMP2_INT Interrupt */TIMG8_INT_IRQn = 2, /* 18 TIMG8_INT Interrupt */UART3_INT_IRQn = 3, /* 19 UART3_INT Interrupt */ADC0_INT_IRQn = 4, /* 20 ADC0_INT Interrupt */ADC1_INT_IRQn = 5, /* 21 ADC1_INT Interrupt */CANFD0_INT_IRQn = 6, /* 22 CANFD0_INT Interrupt */DAC0_INT_IRQn = 7, /* 23 DAC0_INT Interrupt */SPI0_INT_IRQn = 9, /* 25 SPI0_INT Interrupt */SPI1_INT_IRQn = 10, /* 26 SPI1_INT Interrupt */UART1_INT_IRQn = 13, /* 29 UART1_INT Interrupt */UART2_INT_IRQn = 14, /* 30 UART2_INT Interrupt */UART0_INT_IRQn = 15, /* 31 UART0_INT Interrupt */TIMG0_INT_IRQn = 16, /* 32 TIMG0_INT Interrupt */TIMG6_INT_IRQn = 17, /* 33 TIMG6_INT Interrupt */TIMA0_INT_IRQn = 18, /* 34 TIMA0_INT Interrupt */TIMA1_INT_IRQn = 19, /* 35 TIMA1_INT Interrupt */TIMG7_INT_IRQn = 20, /* 36 TIMG7_INT Interrupt */TIMG12_INT_IRQn = 21, /* 37 TIMG12_INT Interrupt */I2C0_INT_IRQn = 24, /* 40 I2C0_INT Interrupt */I2C1_INT_IRQn = 25, /* 41 I2C1_INT Interrupt */AES_INT_IRQn = 28, /* 44 AES_INT Interrupt */RTC_INT_IRQn = 30, /* 46 RTC_INT Interrupt */DMA_INT_IRQn = 31, /* 47 DMA_INT Interrupt */
} IRQn_Type;
例5-2:雙按鍵中斷方式實現led燈的亮滅
![]() | ![]() |
實現按鍵S1按鍵點亮LED1,按鍵S2熄滅LED1
首先還是配置管腳,從電路原理圖中可以看出S1按下為高電平,釋放為低電平,所以S1即PA18設定為輸入,內部連接下拉電阻,中斷觸發方式為上升沿;S2按下為低電平,釋放為高電平,即PB21設定為輸入,內部連接上拉電阻,中斷觸發方式為下降沿;led1設定為輸出,初始值為高,即led初始為熄滅。
#include "ti_msp_dl_config.h"int main(void)
{SYSCFG_DL_init();NVIC_EnableIRQ(GPIOA_INT_IRQn);//開啟按鍵引腳的GPIOA端口中斷NVIC_EnableIRQ(GPIOB_INT_IRQn);//開啟按鍵引腳的GPIOB端口中斷while (1) {}
}
void GROUP1_IRQHandler(void) {uint32_t status=0; switch (DL_Interrupt_getPendingGroup(DL_INTERRUPT_GROUP_1)) {case DL_INTERRUPT_GROUP1_IIDX_GPIOA: // 處理GPIOA中斷status= DL_GPIO_getEnabledInterruptStatus(Buttons_S1_PORT,Buttons_S1_PIN);if (status & Buttons_S1_PIN) { // 檢查PA18引腳DL_GPIO_clearPins(LED_PORT, LED_LED1_PIN);//亮燈DL_GPIO_clearInterruptStatus(Buttons_S1_PORT, Buttons_S1_PIN); // 清除標志}break;case DL_INTERRUPT_GROUP1_IIDX_GPIOB: // 處理GPIOB中斷status= DL_GPIO_getEnabledInterruptStatus(Buttons_S2_PORT,Buttons_S2_PIN);if (status & Buttons_S2_PIN) { // 檢查PB21引腳DL_GPIO_setPins(LED_PORT, LED_LED1_PIN);//熄燈DL_GPIO_clearInterruptStatus(Buttons_S2_PORT, Buttons_S2_PIN); // 清除標志}break; default: // 處理其他中斷// 完成處理break;}
}