一、项目介绍
1.1 活动背景
本项目是参加硬禾科技联合DigiKey发起的Funpack活动第五季第3期Funpack S5 #3。第五季第3期的板卡是来自 Analog Devices 的评估套件 MAX32690EVKIT。
MAX32690 评估套件提供了一个平台,用于评估 MAX32690 微控制器的功能,该微控制器是一款先进的片内系统 。它采用了 Arm Cortex-M4F CPU,可高效计算复杂的功能和算法,并采用了最新一代的 Bluetooth 5 低功耗(蓝牙 LE)射频,专为可穿戴和便携式健身设备、便携式和可穿戴式医疗设备、工业传感器/网络、物联网 和资产追踪而设计。

1.2 项目概述
本项目基于 MAX32690EVKIT 开发板,实现了 任务1:按键控制LED闪烁 的基础功能。
本项目实现功能:
- 单次按键 → LED 开始闪烁(频率约 1Hz)
- 再次按键 → LED 停止闪烁(保持熄灭状态)
- 功能要求:
- ✅ 正确初始化 GPIO 中断
- ✅ LED 控制逻辑清晰,不出现误触发
- ✅ 闪烁频率约 1Hz
1.3 项目成果
通过本项目的开发,成功完成了 Funpack S5 #3 活动任务1的基础题目要求:
- ✅ 了解 MAX32690EVKIT 开发板的硬件结构和特性
- ✅ 掌握 Maxim MSDK 的 GPIO 驱动开发
- ✅ 实现 GPIO 中断的正确初始化与配置
- ✅ 实现按键消抖机制,避免误触发
- ✅ 实现 1Hz 频率的 LED 闪烁控制
- ✅ 掌握程序烧录与独立运行验证方法
二、硬件介绍
2.1 微控制器:MAX32690
MAX32690 是基于 Arm® Cortex®-M4F 处理器的超低功耗微控制器,具备以下核心特性:
- 处理器:Arm® Cortex®-M4F,带 FPU,最高 100MHz
- 存储器:2MB 双 bank Flash,512KB SRAM
- 无线连接:Bluetooth 5 低功耗(蓝牙 LE)射频
- 超低功耗:多种低功耗模式,适合电池供电设备
- 丰富外设:SPI、UART、I2C、GPIO、定时器、PWM、ADC 等
- 调试接口:SWD 调试支持

2.2 MAX32690EVKIT 开发板概述
MAX32690EVKIT 是用于评估 MAX32690 MCU 的官方硬件平台,板载资源包括:
名称 | 特性 |
|---|---|
MAX32690 MCU | Arm® Cortex®-M4F 微控制器,带 BLE 5.0 |
User LED | 红色 LED(GPIO0_14,低电平点亮) |
User Switch | SW2 用户按键(GPIO4_0,按下为低电平) |
显示屏 | 128 x 128(1.45 英寸)TFT 彩色显示屏 |
音频 | MAX9867 立体声音频编解码器,3.5mm 插孔 |
存储器 | 板载 HyperRAM |
调试接口 | MAX32625PICO 调试器接口,支持 CMSIS-DAP |

2.3 引脚分配
本项目主要用到板载按键 SW2 和红色 LED0:
- 按键 SW2:连接至 GPIO4_0(P4.0),按下时为低电平
- 红色 LED0:连接至 GPIO0_14(P0.14),低电平点亮
额外用到绿色LED1:
- 绿色 LED1:连接至 GPIO2_12(P2.12),进入中断指示灯

2.4 原理图
MAX32690EVKIT 原理图主要包括电源原理图、MCU 原理图和调试器原理图。其中最应关注的是 MCU 原理图中的两个引脚 GPIO4_0(按键)和 GPIO0_14(LED)。
GPIO4_0引脚通过杜邦线连接至GPIO2_11,因此实际的按键输入为P2.11。
三、方案框图和项目设计思路
3.1 方案框图
根据项目要求,确定方案框图如下:

3.2 项目设计思路
硬件设计:
- 使用板载按键 SW2(连接至 GPIO4_0)作为输入,配置为下降沿触发中断,GPIO4_0引脚通过杜邦线连接至GPIO2_11,因此实际的按键输入为P2.11。
- 使用板载红色 LED0(连接至 GPIO0_14)作为输出,低电平点亮
- 使用板载绿色 LED1(连接至 GPIO2_12),进入中断指示灯
软件设计:
- GPIO 初始化:GPIO2_11 配置为输入模式,使能内部上拉,配置下降沿中断;GPIO0_14 配置为推挽输出模式
- 中断服务函数:
- 进入中断后立即禁用该引脚中断,防止抖动再次触发
- 清除中断标志
- 软件消抖延时(约 20ms)
- 再次读取引脚电平,确认是有效按键(低电平)
- 切换 LED 状态标志
led_blink_enable - 重新使能中断
- 主循环控制:
- 若
led_blink_enable == 1:LED 以 500ms 间隔翻转(1Hz 闪烁) - 若
led_blink_enable == 0:LED 保持熄灭
- 若
- 消抖机制:采用 中断内禁用 + 软件延时 + 电平二次确认 的消抖策略,有效滤除按键的机械抖动和噪声
3.3 调试引脚设计(可选)
为便于调试观察中断是否触发,可配置 GPIO2_12(P2.12)作为调试指示引脚:
- 每次有效按键处理后翻转 P2.12 电平
- 可用示波器或逻辑分析仪观察中断触发情况
四、开发环境介绍、软件流程图及关键代码
4.1 开发环境介绍
4.1.1 开发环境
本项目使用 Analog Devices 官方提供的 Maxim Micros SDK 作为软件开发框架。
软件 | 版本 | 用途 |
|---|---|---|
Eclipse | 2023-06 | 集成开发环境 |
Maxim MSDK | 最新版 | MAX32690 驱动库和示例代码 |
OpenOCD | 0.12.0 | 调试和烧录工具 |
GCC ARM | 10.3.1 | ARM Cortex-M 编译器 |
MAX32625PICO | CMSIS-DAP v2.1.0 | 调试器硬件 |
4.1.2 项目新建
1.将 MAX32690EVKIT 通过 USB 连接到电脑,确保 MAX32625PICO 调试器已连接

2.打开 Eclipse IDE,新建项目:File——New——Project...,选择工程类别
3.配置项目名称和路径
4.选择芯片型号、开发板型号、工程模板、调试器型号等

4.2 程序流程图
4.2.1 主程序流程图

4.2.2 GPIO 中断服务函数流程图

4.3 关键代码介绍
以下为主程序完整代码,并对代码进行详细解析。
/**
* @file main.c
* @brief Funpack S5 #3 - 任务1:按键控制LED闪烁
* 单次按键 → LED开始闪烁 (1Hz)
* 再次按键 → LED停止闪烁
* 调试: P2.12 翻转指示中断触发
*/
#include <stdio.h>
#include <string.h>
#include "mxc_device.h"
#include "nvic_table.h"
#include "board.h"
#include "gpio.h"
#include "mxc_delay.h"
/***** 硬件引脚定义 *****/
#define MXC_GPIO_PORT_IN MXC_GPIO4 // 按键输入端口 (SW2)
#define MXC_GPIO_PIN_IN MXC_GPIO_PIN_0 // 按键引脚
#define MXC_GPIO_PORT_OUT MXC_GPIO0 // LED输出端口
#define MXC_GPIO_PIN_OUT MXC_GPIO_PIN_14 // LED引脚 (红色LED0)
#define MXC_GPIO_PORT_DBG MXC_GPIO2 // 调试端口
#define MXC_GPIO_PIN_DBG MXC_GPIO_PIN_12 // 调试引脚 (可选)
/***** 全局状态变量 *****/
volatile uint8_t led_blink_enable = 0; // 0: 停止, 1: 闪烁
/***** 函数声明 *****/
void GPIO4_IRQHandler(void); // GPIO4 中断服务函数
/***** 主函数 *****/
int main(void)
{
mxc_gpio_cfg_t gpio_in;
mxc_gpio_cfg_t gpio_out;
mxc_gpio_cfg_t gpio_dbg;
// ---------- 1. 配置输出引脚 (LED) ----------
gpio_out.port = MXC_GPIO_PORT_OUT;
gpio_out.mask = MXC_GPIO_PIN_OUT;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
gpio_out.vssel = MXC_GPIO_VSSEL_VDDIO;
gpio_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_out);
MXC_GPIO_OutSet(gpio_out.port, gpio_out.mask); // 初始熄灭 (高电平)
// ---------- 2. 配置调试引脚 (P2.12, 可选) ----------
gpio_dbg.port = MXC_GPIO_PORT_DBG;
gpio_dbg.mask = MXC_GPIO_PIN_DBG;
gpio_dbg.pad = MXC_GPIO_PAD_NONE;
gpio_dbg.func = MXC_GPIO_FUNC_OUT;
gpio_dbg.vssel = MXC_GPIO_VSSEL_VDDIO;
gpio_dbg.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_dbg);
MXC_GPIO_OutSet(gpio_dbg.port, gpio_dbg.mask);
// ---------- 3. 配置输入引脚 (按键) ----------
gpio_in.port = MXC_GPIO_PORT_IN;
gpio_in.mask = MXC_GPIO_PIN_IN;
gpio_in.pad = MXC_GPIO_PAD_PULL_UP; // 内部上拉
gpio_in.func = MXC_GPIO_FUNC_IN;
gpio_in.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_in.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_in);
// 清除中断标志,配置下降沿触发
MXC_GPIO_ClearFlags(gpio_in.port, gpio_in.mask);
MXC_GPIO_IntConfig(&gpio_in, MXC_GPIO_INT_FALLING);
MXC_GPIO_EnableInt(gpio_in.port, gpio_in.mask);
// 使能 GPIO4 中断
NVIC_EnableIRQ(GPIO4_IRQn);
// ---------- 4. 主循环 (使用延时实现1Hz闪烁) ----------
while (1) {
if (led_blink_enable) {
MXC_GPIO_OutClr(MXC_GPIO_PORT_OUT, MXC_GPIO_PIN_OUT); // LED 亮
MXC_Delay(MXC_DELAY_MSEC(500)); // 延时 500ms
MXC_GPIO_OutSet(MXC_GPIO_PORT_OUT, MXC_GPIO_PIN_OUT); // LED 灭
MXC_Delay(MXC_DELAY_MSEC(500)); // 延时 500ms
} else {
MXC_GPIO_OutSet(MXC_GPIO_PORT_OUT, MXC_GPIO_PIN_OUT); // 保持熄灭
MXC_Delay(MXC_DELAY_MSEC(10)); // 短暂延时,避免忙等待
}
}
}
/***** GPIO4 中断服务函数 *****/
void GPIO4_IRQHandler(void)
{
// 1. 立即禁用按键引脚中断,防止后续抖动再次触发
MXC_GPIO_DisableInt(MXC_GPIO_PORT_IN, MXC_GPIO_PIN_IN);
// 2. 清除中断标志
uint32_t flags = MXC_GPIO_GetFlags(MXC_GPIO_PORT_IN);
if (flags & MXC_GPIO_PIN_IN) {
MXC_GPIO_ClearFlags(MXC_GPIO_PORT_IN, MXC_GPIO_PIN_IN);
}
// 3. 软件消抖延时 (约20ms)
MXC_Delay(MXC_DELAY_MSEC(20));
// 4. 再次读取引脚电平,确认是有效按下 (低电平)
if (MXC_GPIO_InGet(MXC_GPIO_PORT_IN, MXC_GPIO_PIN_IN) == 0) {
// ---- 有效按键处理 ----
// 翻转调试指示引脚 (用于观察中断触发)
MXC_GPIO_OutToggle(MXC_GPIO_PORT_DBG, MXC_GPIO_PIN_DBG);
// 切换 LED 状态
led_blink_enable = !led_blink_enable;
// 若停止闪烁,立即熄灭 LED
if (!led_blink_enable) {
MXC_GPIO_OutSet(MXC_GPIO_PORT_OUT, MXC_GPIO_PIN_OUT);
}
}
// 5. 清除可能因消抖期间产生的额外中断标志
MXC_GPIO_ClearFlags(MXC_GPIO_PORT_IN, MXC_GPIO_PIN_IN);
// 6. 重新使能按键引脚中断
MXC_GPIO_EnableInt(MXC_GPIO_PORT_IN, MXC_GPIO_PIN_IN);
}
4.3.1 硬件引脚定义
#define MXC_GPIO_PORT_IN MXC_GPIO4 // 按键输入端口 (SW2)
#define MXC_GPIO_PIN_IN MXC_GPIO_PIN_0 // 按键引脚
#define MXC_GPIO_PORT_OUT MXC_GPIO0 // LED输出端口
#define MXC_GPIO_PIN_OUT MXC_GPIO_PIN_14 // LED引脚 (红色LED0)
定义项目使用的硬件引脚,便于代码移植和维护。
4.3.2 全局状态变量
volatile uint8_t led_blink_enable = 0; // 0: 停止, 1: 闪烁
使用 volatile 关键字修饰,确保编译器不会优化掉该变量,保证中断和主循环之间的数据一致性。
4.3.3 GPIO 初始化
// LED 配置为推挽输出
gpio_out.port = MXC_GPIO_PORT_OUT;
gpio_out.mask = MXC_GPIO_PIN_OUT;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
gpio_out.vssel = MXC_GPIO_VSSEL_VDDIO;
gpio_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_out);
MXC_GPIO_OutSet(gpio_out.port, gpio_out.mask); // 初始熄灭
// 按键配置为输入,内部上拉
gpio_in.port = MXC_GPIO_PORT_IN;
gpio_in.mask = MXC_GPIO_PIN_IN;
gpio_in.pad = MXC_GPIO_PAD_PULL_UP; // 内部上拉
gpio_in.func = MXC_GPIO_FUNC_IN;
MXC_GPIO_Config(&gpio_in);
// 配置下降沿中断
MXC_GPIO_ClearFlags(gpio_in.port, gpio_in.mask);
MXC_GPIO_IntConfig(&gpio_in, MXC_GPIO_INT_FALLING);
MXC_GPIO_EnableInt(gpio_in.port, gpio_in.mask);
NVIC_EnableIRQ(GPIO4_IRQn);
关键点:
- LED 配置为推挽输出,初始高电平(LED 熄灭,因为低电平点亮)
- 按键配置为输入模式,使能内部上拉电阻
- 配置下降沿触发中断(按键按下时电平从高变低)
- 使能 GPIO4 中断向量
4.3.4 GPIO 中断服务函数
void GPIO4_IRQHandler(void)
{
// 1. 立即禁用按键引脚中断,防止后续抖动再次触发
MXC_GPIO_DisableInt(MXC_GPIO_PORT_IN, MXC_GPIO_PIN_IN);
// 2. 清除中断标志
uint32_t flags = MXC_GPIO_GetFlags(MXC_GPIO_PORT_IN);
if (flags & MXC_GPIO_PIN_IN) {
MXC_GPIO_ClearFlags(MXC_GPIO_PORT_IN, MXC_GPIO_PIN_IN);
}
// 3. 软件消抖延时 (约20ms)
MXC_Delay(MXC_DELAY_MSEC(20));
// 4. 再次读取引脚电平,确认是有效按下 (低电平)
if (MXC_GPIO_InGet(MXC_GPIO_PORT_IN, MXC_GPIO_PIN_IN) == 0) {
// 翻转调试指示引脚
MXC_GPIO_OutToggle(MXC_GPIO_PORT_DBG, MXC_GPIO_PIN_DBG);
// 切换 LED 状态
led_blink_enable = !led_blink_enable;
if (!led_blink_enable) {
MXC_GPIO_OutSet(MXC_GPIO_PORT_OUT, MXC_GPIO_PIN_OUT);
}
}
// 5. 清除可能因消抖期间产生的额外中断标志
MXC_GPIO_ClearFlags(MXC_GPIO_PORT_IN, MXC_GPIO_PIN_IN);
// 6. 重新使能按键引脚中断
MXC_GPIO_EnableInt(MXC_GPIO_PORT_IN, MXC_GPIO_PIN_IN);
}
关键点:
- 进入中断立即禁用该引脚中断:防止在消抖和处理期间再次触发中断,彻底杜绝误触发
- 双重清除中断标志:在开始和结束都清除标志,确保挂起标志被清除干净
- 软件消抖延时:延时 20ms 后再次读取电平,确认是真实按键
- 电平二次确认:只有读取到低电平才执行有效按键处理
- 重新使能中断:处理完成后重新打开中断,准备下一次按键
五、功能展示与说明

按下按键 ,红色LED 开始闪烁(频率约 1Hz);再次按下按键,红色LED 停止闪烁(保持熄灭状态)。LED 控制逻辑清晰,不出现误触发。同时,每次按下按键,进入一次中断,中断指示灯绿色LED状态翻转。
六、项目总结
6.1 遇到的问题与解决方案
问题 | 解决方案 |
|---|---|
编译错误: | 使用 |
中断服务函数命名不匹配 | 使用启动文件中定义的 |
按键误触发(多次进入中断) | 中断内禁用引脚中断 + 软件消抖 + 电平二次确认 |
断电后程序无法独立运行 | 检查安全启动签名,使用正确烧录方式 |
6.2 项目收获
通过本项目的开发,深入了解了:
- MAX32690EVKIT 的硬件架构和引脚功能
- MSDK 的 GPIO 驱动库使用方法
- GPIO 中断的正确配置与消抖处理
- 嵌入式程序从开发到烧录的完整流程
- 中断服务函数与主循环的数据同步机制
6.3 可扩展方向(Funpack 进阶题目)
根据 Funpack S5 #3 活动的进阶题目要求,本项目可进一步扩展:
- 长按调节频率:在基础题之上,实现长按按键调节 LED 闪烁频率
- 频率线性变化:短按控制开关,长按实现 1Hz → 5Hz 线性变化
- 反向调节:到达最快后,保持长按可实现 5Hz → 1Hz 反向变化
- 平滑过渡:频率变化过程应平滑,无明显跳变
七、参考资料
- Funpack S5 #3 活动页面 - 硬禾科技
- MAX32690EVKIT 用户指南 - Analog Devices
- Maxim Micros SDK 用户手册
- ARM Cortex-M4 技术参考手册
- OpenOCD 用户手册
- Eclipse CDT 开发指南