在上一讲LP-MSPM0G3507学习--04GPIO控制中实现了通过按键控制led灯的亮灭,可以看出程序效率不高,下面采用中断的方式实现,其中的配置大部分相同,除了将管脚buttoninterrupts设置为中断:
需要注意的是触发极性(triggler polarity),有4种:
- diabled--可能是电平触发(此时应该是低电平触发,因为有上拉电阻了)
- trigger on rising edge--上升沿触发
- trigger on falling edge--下降沿触发
- trigger on both Edg--双边沿触发
此处选择下降沿触发
#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;