IoT Nano 33使用CMSIS配置TCC定时器中断时串口断开求助
基于ARM Cortex M0+的CMSIS中断配置排查与实现指南
一、开发板断连问题排查
- 时钟配置检查:CMSIS代码中不要随意修改系统时钟(Arduino默认已完成可靠初始化),若手动配置时钟,必须保证USB/调试接口的时钟源正确(多数Cortex M0+开发板依赖48MHz USB时钟)。
- 中断配置错误排查:
- Cortex M0+仅支持2位优先级(分组固定为0,[7:6]为抢占优先级,[5:0]为子优先级),不要修改
SCB->AIRCR寄存器改变优先级分组。 - ISR函数必须强制清除对应中断标志位,否则会无限触发中断导致系统挂死。
- Cortex M0+仅支持2位优先级(分组固定为0,[7:6]为抢占优先级,[5:0]为子优先级),不要修改
- 调试接口保护:确认代码未将SWD/JTAG引脚(如SAMD21的PA14/SWDCLK、PA15/SWDIO)配置为普通GPIO,否则会直接导致调试连接失效。
- 开发板恢复:若无法重连,通过BOOT引脚进入ISP模式,重新烧录Arduino引导程序后再测试CMSIS代码。
二、CMSIS中断配置实现
1. Cortex M0+默认ISR说明
启动文件(如startup_<device>.s)中定义了默认中断服务函数表,未自定义的ISR会跳转到Default_Handler,该函数为死循环:
void Default_Handler(void) { while(1); }
若中断触发但未定义对应ISR,系统会直接挂死,导致开发板无响应。
2. GPIO中断配置(以SAMD21 PA0上升沿触发为例)
#include "samd21.h" // 根据你的开发板替换对应CMSIS头文件 // GPIO中断ISR void EIC_0_Handler(void) { // 清除PA0对应的EXTINT0中断标志 EIC->INTFLAG.reg = EIC_INTFLAG_EXTINT0; // 执行自定义逻辑:翻转PA13引脚状态 PORT->Group[0].OUTTGL.reg = PORT_PA13; } void GPIO_Interrupt_Init(void) { // 使能EIC时钟 MCLK->APBAMASK.reg |= MCLK_APBAMASK_EIC; GCLK->PCHCTRL[EIC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; // 配置PA0为输入上拉 PORT->Group[0].DIRCLR.reg = PORT_PA0; PORT->Group[0].PINCFG[0].reg |= PORT_PINCFG_PULLEN | PORT_PINCFG_INEN | PORT_PINCFG_PMUXEN; PORT->Group[0].OUTSET.reg = PORT_PA0; // 将PA0复用为EIC EXTINT0 PORT->Group[0].PMUX[0].reg = PORT_PMUX_PMUXE_E; // 配置EIC上升沿触发 EIC->CONFIG[0].reg = EIC_CONFIG_SENSE0_RISE; // 使能EXTINT0中断 EIC->INTENSET.reg = EIC_INTENSET_EXTINT0; // NVIC配置:设置优先级(0-3,0最高),使能中断 NVIC_SetPriority(EIC_IRQn, 2); NVIC_EnableIRQ(EIC_IRQn); // 使能EIC模块 EIC->CTRL.reg |= EIC_CTRL_ENABLE; }
3. TCCx定时器中断配置(以SAMD21 TCC0为例)
// TCC0溢出中断ISR void TCC0_Handler(void) { // 清除溢出中断标志 if(TCC0->INTFLAG.reg & TCC_INTFLAG_OVF) { TCC0->INTFLAG.reg = TCC_INTFLAG_OVF; // 自定义逻辑:翻转PA13引脚 PORT->Group[0].OUTTGL.reg = PORT_PA13; } } void TCC0_Interrupt_Init(void) { // 使能TCC0时钟 MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC0; GCLK->PCHCTRL[TCC0_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; // 配置TCC0为16位计数模式,预分频1024 TCC0->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV1024 | TCC_CTRLA_MODE_COUNT16; // 设置周期值:48MHz/1024/50=937,对应50Hz中断 TCC0->PER.reg = 937; // 使能溢出中断 TCC0->INTENSET.reg = TCC_INTENSET_OVF; // NVIC配置 NVIC_SetPriority(TCC0_IRQn, 1); NVIC_EnableIRQ(TCC0_IRQn); } // TCC0启停函数 void TCC0_Start(void) { TCC0->CTRLA.reg |= TCC_CTRLA_ENABLE; } void TCC0_Stop(void) { TCC0->CTRLA.reg &= ~TCC_CTRLA_ENABLE; // 等待模块禁用完成 while(TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_ENABLE); }
4. 主函数示例
int main(void) { // 初始化系统时钟(开发板提供的默认初始化函数) SystemInit(); // 配置PA13为输出(用于测试) PORT->Group[0].DIRSET.reg = PORT_PA13; PORT->Group[0].OUTCLR.reg = PORT_PA13; // 初始化GPIO与定时器中断 GPIO_Interrupt_Init(); TCC0_Interrupt_Init(); // 启动定时器 TCC0_Start(); while(1) { // 主循环逻辑 } }
三、核心注意事项
- 中断标志必须清除:所有ISR中必须手动清除对应中断标志,否则会持续触发中断导致系统崩溃。
- 优先级范围限制:Cortex M0+仅支持0-3共4级中断优先级,不要设置超出范围的值。
- 外设时钟必使能:所有外设(EIC、TCCx)必须先使能GCLK和APB总线时钟,否则外设无法工作。
内容的提问来源于stack exchange,提问作者Daiyan Khan
相关产品推荐
相关产品推荐

