1. 引言
在上一篇博客中,成功搭建了 MPLAB 开发环境,初次体验了图形化配置的简单便捷,并点亮了开发板上的 LED。本篇将详细配置嵌入式开发/MCU开发中极为重要的外部中断(EI)。学习如何使用板载按键触发中断来翻转 LED。这不仅是按键检测的最佳实践,更是理解 SAM D21 事件驱动机制的起点。
2. 核心架构深度解析:SAM D21 EIC vs STM32 EXTI
对于熟悉 STM32 的开发者来说,配置外部中断通常涉及 GPIO、AFIO(或SYSCFG)、EXTI和NVIC这几个模块。而在 SAM D21 上,这一套逻辑被封装在了一个名为 EIC (External Interrupt Controller) 的外设中。二者中断架构的详细区别如下表所示。
| 特性维度 | STM32 (以 F1/F4 为例) | Microchip SAM D21 | 深度差异解析 |
|---|---|---|---|
| 控制器名称 | EXTI (External Interrupt/Event Controller) | EIC (External Interrupt Controller) | 名称不同,但在系统总线上的位置类似。 |
| 引脚映射 | Line 映射制 PA0, PB0, PC0 共用 EXTI0 线。这意味着你不能同时开启 PA0 和 PB0 的中断。 | 通道映射制 (Channels) 拥有 16 个外部中断通道 (EXTINT[0..15])。任意引脚都可以映射到这 16 个通道之一。 | SAM D21 更灵活。虽然也存在共用通道的情况,但其复用矩阵(Multiplexing)更自由,且支持 NMI(不可屏蔽中断)。 |
| 去抖动 (Debounce) | 无硬件去抖 通常需要在软件中断服务函数中加延时或定时器来消抖。 | 硬件去抖支持 EIC 模块内部集成了数字滤波器,可直接配置是否开启滤波和去抖。 | SAM 的突出功能。硬件直接过滤毛刺,不仅简化代码,还能避免因按键抖动导致的频繁无效中断唤醒 CPU,极大降低功耗。 |
| 时钟依赖 | 挂载在 APB 总线上,随系统时钟开启。 | 独立 GCLK 时钟 EIC 需要独立配置时钟源 (GCLK)。 | 这意味着 EIC 可以在 CPU 睡眠(甚至深度睡眠)且主时钟关闭时,依靠 32kHz 低速时钟独立工作并唤醒系统。 |
| 代码实现 | HAL_GPIO_EXTI_Callback() 所有引脚共用一个或几个 Callback,需内部判断 Pin。 |
EIC_CallbackRegister() 针对每个引脚/通道独立注册回调函数。 |
Harmony 的 PLIB 提供了更现代的"注册机制",避免了在 ISR 里写一堆 if-else 判断是谁触发的中断。 |
3. 按键控制 LED(基于 Harmony v3)
3.1 硬件准备与原理
本次使用的是 SAM D21 Curiosity Nano 评估板。该板自带板载调试器(nEDBG),插上 USB 就能仿真和打印串口,不需要额外的调试器。MPLAB X IDE版本为v6.25,xc32版本为v5.00。
-
输入 :板载用户按键 SW0 。查阅原理图可知,它连接在 PA15 引脚上。
-
输出 :板载黄色 LED LED0 。连接在 PB10 引脚上。
-
逻辑:按下 SW0 -> 触发下降沿中断 -> CPU 响应 -> 翻转 LED0 电平。
3.2 MCC 图形化配置步骤
打开 MPLAB X IDE创建好对应工程后,启动 MCC,开始配置硬件。
第一步:激活 EIC 模块
在左侧的 Device Resources (设备资源)栏中,找到 Peripherals -> EIC,双击将其添加到中间的 Project Graph 中。此时,EIC 模块就挂载到了项目中。

第二步:时钟配置
在 STM32 中,使能 GPIO 时钟通常只有一行代码(__HAL_RCC_GPIOA_CLK_ENABLE)。但在 SAM D21 中,你需要显式地给 EIC "喂"时钟。
-
打开 Clock Configuration 视图,
Plugins->Clock Configuration。 -
找到 EIC 模块的时钟输入槽。
-
确保它连接到了一个有效的时钟发生器(GCLK Generator)。MPLAB Harmony v3 配置器的默认设置是让所有选定的外设以最大速度运行,连接的由DFLL产生的GCLK0 48MHz。建议选择内部超低功耗 32 kHz 振荡器作为 EIC 源时钟,以降低响应速度,从而避免按钮在长时间内产生误触发。

第三步:引脚配置
打开 Plugins -> Pin Configuration -> Pin Settings:
LED0 (PB10):
Function: GPIO、Direction: Out、Latch: High (初始熄灭)
SW0 (PA15):
Function 设置为 EIC_EXTINT11 (外部中断通道 11)。SAM D21 的引脚复用功能极其强大,PB11正是被复用为了EIC功能才能响应中断。Direction: In、Pull: Up (因为按键按下接地,平时需要上拉)

第四步:配置 EIC 模块
回到 Project Graph,点击 EIC 模块,在右侧的 Configuration Options 中进行精细化设置。启用EIC 11中断。边沿触发选择 Falling-edge detection,意味着仅在信号从高电平跳变到低电平(下降沿)的瞬间触发。启用硬件滤波,为引脚信号增加一个数字防抖滤波,滤除由于机械振动(如按键抖动)或噪声引起的短暂毛刺脉冲,确保只有稳定有效的边沿才会被识别。

此时点击system模块,在右侧 Configuration Options 中可以看到外部中断控制器已使能、中断优先级和回调函数,回调函数名称可以自定义。

3.3 生成代码与回调函数编写
点击 Generate ,MCC 会自动生成底层的 PLIB 代码(如 plib_eic.c, plib_eic.h)。
只需在 main.c 中编写外部中断逻辑。编写并注册一个中断回调处理函数。
main 函数
cs
int main ( void ) {
SYS_Initialize ( NULL );
while ( true ) {
SYS_Tasks ( );
}
return ( EXIT_FAILURE );
}
-
SYS_Initialize ( NULL );:一次性硬件初始化 。它会根据在图形化配置工具(MCC)中的所有设置,初始化MCU的时钟、引脚、外设(包括EIC中断)等。它内部已经将配置的BUTTON_Handler函数,注册为EIC通道11中断的服务程序。 -
while ( true )循环中的SYS_Tasks ( );:驱动系统任务 。它轮询处理所有模块的后台状态机。对于中断而言,它的关键作用是:当中断标志在后台被硬件置位后,框架会在合适的时机(通常是在SYS_Tasks中)调用你注册的BUTTON_Handler。
中断服务程序 (BUTTON_Handler 函数)
cs
void BUTTON_Handler() {
LED_Toggle();
EIC_REGS->EIC_INTFLAG = (1 << 11);
}
-
响应操作 :执行中断发生时要做的动作,这里是
LED_Toggle()。 -
清除标志 :手动清除EIC的中断标志位。如果不清除,硬件会认为中断请求持续存在,导致中断函数被无限重复调用。
4. 调试与总结
编译并下载程序到 SAM D21 Curiosity Nano。
-
现象:当你按下板子上的 SW0 按键时,LED0 会翻转亮灭状态。
-
验证去抖:如果手头有示波器,可以观察 PA15 引脚的波形。即使按键因为机械结构产生了几毫秒的抖动, LED 翻转也是干脆利落的,不会出现"按一下闪好几下"的现象,这归功于 EIC 强大的硬件去抖功能。
本篇详述了 SAM D21 在外部中断设计上的巧思:
-
更强的硬件支持:内置硬件滤波和去抖,释放 CPU 算力。
-
更灵活的时钟:EIC 独立时钟域设计,为低功耗唤醒铺平道路。
-
更现代的 API:基于回调函数的开发模式,让应用层代码更加整洁。