这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 电子DIY+MAX32655FTHRGPIO控制

共2条 1/1 1 跳转至

电子DIY+MAX32655FTHRGPIO控制

高工
2026-03-18 07:49:35     打赏
MAX32655FTHR 板载 LED 控制任务设计一、任务背景

MAX32655FTHR 是一款基于 MAX32655 Arm Cortex-M4F 和 Bluetooth 5.2 LE 的超低功耗无线开发板,集成 MAX20303 PMIC 电源管理芯片,并配备丰富的外设资源,包括 RGB LED 指示灯、数字麦克风、音频编解码器、QSPI 闪存、micro SD 卡接口及按键等。本次任务聚焦于利用板载按键控制 RGB LED,实现多种灯效切换,包括普通亮灭和呼吸灯效果,并支持红、绿、蓝三色显示。


二、任务目标基础功能:通过按键切换 LED 的亮灭状态(开/关)。进阶功能:实现呼吸灯效果(亮度渐变),并支持颜色切换(红/绿/蓝)。

交互设计:使用按键中断触发状态切换,确保系统响应实时性。


三、设计思路硬件资源:RGB LED:通过 PWM 通道控制三色亮度,实现混色或独立颜色显示。按键:配置为外部中断输入,触发状态机切换。软件逻辑:状态定义:颜色状态:红(R)、绿(G)、蓝(B)。模式状态:普通亮灭(固定亮度)、呼吸灯(动态亮度)。按键中断处理:每次按键按下时,切换颜色或模式(如红→绿→蓝→呼吸灯循环)。PWM 控制:普通模式:直接设置 PWM 占空比(如 50% 亮度)。

呼吸模式:通过定时器动态调整 PWM 占空比(0%→100%→0% 循环)。

38f85729-317e-4a58-80e2-1836f4d60c65.png

四、实现步骤

开发工具使用MaximSDK,基本就是eclipse内核,加载了完整的编译工具的一个SDK。安装起来挺不容易的,好在之前有做MAX78000项目,电脑安装好了MaximSDK。

初始化 GPIO 和 PWM:配置 RGB LED 引脚为 PWM 输出模式。配置按键中断:启用外部中断,设置触发条件(如下降沿)。主循环:根据当前状态更新 PWM 占空比,实现灯效。

中断服务函数:按键按下时切换状态变量,触发灯效更新。

a700145d-76a5-4f5f-9c2d-86d7d70e3aff.png

使用kimi做协助,现在的人工智能很强大了,能很好滴帮忙生成代码。

首先是GPIO的驱动。将LED对应的管脚设置为输出;按键对应的管脚设置为输入。并添加按键的中断调用。


代码

/***** ISR Functions *****/
static void sw2_isr(void *cbdata) {
	sw2_event = 1;  // 设置事件标志
	MXC_GPIO_ClearFlags(SW2_PORT, SW2_PIN);
}

static void sw3_isr(void *cbdata) {
	sw3_event = 1;  // 设置事件标志
	MXC_GPIO_ClearFlags(SW3_PORT, SW3_PIN);
}

/***** Functions *****/
static void gpio_interrupt_init(void) {
	mxc_gpio_cfg_t gpio_cfg;

	// 使能GPIO时钟(必须!)
	MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_GPIO0);

	// LED配置(初始熄灭)
	gpio_cfg.port = LED_RED_PORT;
	gpio_cfg.mask = LED_RED_PIN;
	gpio_cfg.pad = MXC_GPIO_PAD_NONE;
	gpio_cfg.func = MXC_GPIO_FUNC_OUT;
	gpio_cfg.vssel = MXC_GPIO_VSSEL_VDDIO;
	MXC_GPIO_Config(&gpio_cfg);
	MXC_GPIO_OutSet(LED_RED_PORT, LED_RED_PIN);

	gpio_cfg.port = LED_GREEN_PORT;
	gpio_cfg.mask = LED_GREEN_PIN;
	MXC_GPIO_Config(&gpio_cfg);
	MXC_GPIO_OutSet(LED_GREEN_PORT, LED_GREEN_PIN);

	gpio_cfg.port = LED_BLUE_PORT;
	gpio_cfg.mask = LED_BLUE_PIN;
	MXC_GPIO_Config(&gpio_cfg);
	MXC_GPIO_OutSet(LED_BLUE_PORT, LED_BLUE_PIN);

	// SW2中断配置
	gpio_cfg.port = SW2_PORT;
	gpio_cfg.mask = SW2_PIN;
	gpio_cfg.pad = MXC_GPIO_PAD_PULL_UP;
	gpio_cfg.func = MXC_GPIO_FUNC_IN;
	gpio_cfg.vssel = MXC_GPIO_VSSEL_VDDIO;
	MXC_GPIO_Config(&gpio_cfg);
	MXC_GPIO_RegisterCallback(&gpio_cfg, sw2_isr, NULL);
	MXC_GPIO_IntConfig(&gpio_cfg, MXC_GPIO_INT_FALLING);  // 下降沿触发
	MXC_GPIO_EnableInt(SW2_PORT, SW2_PIN);

	// SW3中断配置
	gpio_cfg.port = SW3_PORT;
	gpio_cfg.mask = SW3_PIN;
	MXC_GPIO_Config(&gpio_cfg);
	MXC_GPIO_RegisterCallback(&gpio_cfg, sw3_isr, NULL);
	MXC_GPIO_IntConfig(&gpio_cfg, MXC_GPIO_INT_FALLING);
	MXC_GPIO_EnableInt(SW3_PORT, SW3_PIN);

	// 使能GPIO中断向量
	NVIC_EnableIRQ(MXC_GPIO_GET_IRQ(MXC_GPIO_GET_IDX(SW2_PORT)));
}
在 MAX32655FTHR 开发板中,RGB LED 由三个独立通道(红、绿、蓝)控制,每个通道对应一个 GPIO 引脚。普通亮灭驱动模式通过直接设置这些引脚的高、低电平,实现 LED 的开关及颜色切换,操作简单且资源占用低。实现原理:引脚初始化:将 R、G、B 通道对应的 GPIO 配置为输出模式,并默认输出低电平(LED 熄灭)。颜色控制:根据预设的颜色状态值(如 RED、GREEN、BLUE),仅点亮对应通道的引脚(输出高电平),其余通道保持低电平。例如,选择红色时,仅 R 通道置高,G、B 通道置低。开关管理:通过全局变量(如 led_state)统一控制 LED 的开关状态,避免重复操作引脚,提升效率。
static void update_led_color(void) {
	// 关闭所有LED
	MXC_GPIO_OutSet(LED_RED_PORT, LED_RED_PIN);
	MXC_GPIO_OutSet(LED_GREEN_PORT, LED_GREEN_PIN);
	MXC_GPIO_OutSet(LED_BLUE_PORT, LED_BLUE_PIN);

	// 点亮当前颜色
	switch (current_color) {
	case COLOR_RED:
		MXC_GPIO_OutClr(LED_RED_PORT, LED_RED_PIN);
		break;
	case COLOR_GREEN:
		MXC_GPIO_OutClr(LED_GREEN_PORT, LED_GREEN_PIN);
		break;
	case COLOR_BLUE:
		MXC_GPIO_OutClr(LED_BLUE_PORT, LED_BLUE_PIN);
		break;
	case COLOR_OFF:
		printf("LED: OFF\n");
		break;
	}
}


在 MAX32655FTHR 开发板中,为实现 RGB LED 的呼吸灯效果(亮度渐变),原计划采用硬件 PWM 驱动。然而,实际测试发现,使用人工智能生成的硬件 PWM 配置代码存在兼容性问题,导致 LED 亮度调节不稳定,甚至出现闪烁异常。经过多次调试无果后,最终放弃硬件 PWM 方案,转而采用软件模拟 PWM的方式实现呼吸效果。软件模拟 PWM 原理软件模拟 PWM 通过定时器中断或主循环延时,动态调整 GPIO 引脚的输出电平占空比,从而模拟 PWM 的亮度调节效果。定时控制:利用系统定时器周期性触发中断,在中断服务函数中更新 LED 引脚的电平状态。占空比调节:定义一个全局变量表示当前占空比,范围为 0%~100%。每次中断时,根据 pwm_duty 的值决定引脚输出高电平或低电平。渐变效果:通过逐步增加或减少 pwm_duty 的值(如每次中断增加 1%),实现 LED 亮度的平滑变化,形成呼吸效果。
//呼吸灯
static void set_led_bread() {
	mxc_gpio_regs_t *port;
	uint32_t currmask=0;
	// 先关闭所有LED(设置为高电平)
	MXC_GPIO_OutSet(LED_RED_PORT, LED_RED_PIN);
	MXC_GPIO_OutSet(LED_GREEN_PORT, LED_GREEN_PIN);
	MXC_GPIO_OutSet(LED_BLUE_PORT, LED_BLUE_PIN);

	switch (current_color) {
	case COLOR_RED:
		port = LED_RED_PORT;
		currmask = LED_RED_PIN;
		break;
	case COLOR_GREEN:
		port = LED_GREEN_PORT;
		currmask = LED_GREEN_PIN;
		break;
	case COLOR_BLUE:
		port = LED_BLUE_PORT;
		currmask = LED_BLUE_PIN;
		break;
	case COLOR_OFF:
		// 保持全灭
		return;
		break;
	}

	for (int duty = 0; duty <= 100; duty += 1) {
		for (int i = 0; i < 100; i++) {
			if (i < duty) {
				MXC_GPIO_OutClr(port, currmask); // 点亮
			} else {
				MXC_GPIO_OutSet(port, currmask); // 熄灭
			}
			MXC_Delay(MXC_DELAY_USEC(50)); // 10us周期 = 100kHz
		}
	}
	for (int duty = 100; duty >= 0; duty -= 1) {
		for (int i = 0; i < 100; i++) {
			if (i < duty) {
				MXC_GPIO_OutClr(port, currmask);
			} else {
				MXC_GPIO_OutSet(port, currmask);
			}
			MXC_Delay(MXC_DELAY_USEC(50));
		}
	}
}

最后在主函数中通过按键状态的判断,来修改颜色、显示模式两个状态量。

/***** Main *****/
int main(void) {
	gpio_interrupt_init();
	update_led_color();

	while (1) {
		// 检查是否有按键事件且未锁定
		if ((sw2_event) && !button_lock) {
			button_lock = 1;  // 锁定,防止重复触发
			current_color = (current_color + 1) % 4;
			// 等待按键释放
			while (MXC_GPIO_InGet(SW2_PORT, SW2_PIN) == 0) {
				MXC_Delay(MXC_DELAY_MSEC(10));
			}
			// 清除事件标志
			sw2_event = 0;
			button_lock = 0;  // 解锁,准备下次按键
		}
		if ((sw3_event) && !button_lock) {
			button_lock = 1;  // 锁定,防止重复触发
			led_stat = (led_stat + 1) % 2;
			// 等待按键释放
			while (MXC_GPIO_InGet(SW3_PORT, SW3_PIN) == 0) {
				MXC_Delay(MXC_DELAY_MSEC(10));
			}
			// 清除事件标志
			sw3_event = 0;
			button_lock = 0;  // 解锁,准备下次按键
		}
		if (led_stat == 0)
			update_led_color();
		if (led_stat == 1)
			set_led_bread();
	}
	return 0;
}

实现效果

绿色

be4e669a-6bfb-45dd-9f38-896b22d84cd5.png

蓝色

e67c2404-27bf-4cc0-9473-2b4234406119.png

红色

019f1538-8796-4f12-a345-0779b76d6fd9.png



专家
2026-03-18 08:33:05     打赏
2楼

谢谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]