Funpack5-3 - 基于MAX32690EVKIT实现 LED 无极调光控制系统
该项目使用了MAX32690EVKIT,实现了简易灯光控制原型验证的设计,它的主要功能为:LED 无极调光控制系统。
标签
Funpack活动
ADI
MAX32690EVKIT
无极调光
CX反C
更新2026-08-20
13

一、项目介绍

本项目以MAX32690 EVKIT开发板为硬件平台,设计并实现了一套带Gamma非线性校正的软件PWM无极LED调光系统

项目摒弃传统LED固定闪烁、线性单调光的基础功能,结合按键长短按识别、非阻塞定时、边界延时换向、视觉算法优化,实现LED开关控制、平滑无极调光、双向循环变亮变暗的智能化功能。系统操作简单、调光手感流畅、视觉效果贴合人眼特性,解决了常规线性调光高亮度变化不明显、低亮度跳变突兀、边界调节卡死、档位调节速度不适配等问题,具备完整的嵌入式裸机开发逻辑与工程优化思路。

二、任务介绍

实现一个LED无极调光系统:

功能要求:

  • 短按功能:实现LED灯光开启/关闭切换,切换瞬间串口同步输出当前亮度数值,实时反馈设备状态
  • 长按功能:长按按键800ms后进入连续无极调光模式,可平滑调节LED亮度,无明显跳变、无卡顿
  • 亮度调节区间:摒弃0亮度黑屏状态,调节范围为5%~100%,5%最低亮度保留微光,精准区分「LED关闭」和「最低亮度」两种状态
  • 双向循环调节:亮度可从5%微光逐步递增至100%满亮,到达100%极值后,保持长按1秒可反向从100%递减至5%,循环往复
  • 平滑优化设计:引入Gamma2.2非线性校正算法,修正人眼视觉非线性缺陷,低亮度变化柔和、高亮度变化清晰,全程调光过渡平滑自然
  • 操作手感优化:设置5%固定调光步长、500ms调光刷新间隔,搭配1秒边界延时换向机制,避免档位滑变、误触发,调节手感舒适稳定

三、硬件介绍

image.png

器件

型号

功能说明

主控芯片

MAX32690(MAX32690EVKIT 开发板)

低功耗ARM内核单片机,提供GPIO端口、SysTick定时器、串口外设支持,为系统定时、IO控制、串口调试提供核心运算与硬件支撑。

板载 LED

GPIO14

灌电流驱动模式,低电平点亮、高电平熄灭,通过软件PWM波形输出不同占空比,实现亮度无级调节。

板载按键

GPIO4

默认上拉输入模式,通过轮询扫描方式检测按键电平变化,精准区分短按、长按动作,实现功能切换与调光控制。

开发板外设

UART 串口

输出亮度百分比调试信息,用于观测当前亮度数值

三、方案框图与项目设计思路

3.1 方案框图

系统整体采用「定时时基 + 按键状态检测 + 算法处理 + PWM输出 + 串口调试」的分层架构,分层清晰、模块化极强:

image.png

SysTick1ms定时时基 → 按键长短按扫描状态机 → Gamma非线性亮度算法处理 → 软件PWM波形生成 → LED亮度输出;亮度变化同步通过串口打印输出状态。

3.2 项目设计思路

  • 时基设计:采用SysTick定时器生成1ms精准系统节拍,全程无阻塞延时,保证系统实时响应,不占用CPU资源。
  • 按键逻辑设计:通过按键按下、松开时间戳差值判断,区分短按与长按;短按实现LED开关切换,长按800ms触发无极调光。
  • 调光逻辑设计:固定5%亮度步进,500ms刷新一次亮度;设置5%~100%有效亮度区间,区分LED关闭与最低微光状态。
  • 边界换向设计:亮度到达5%、100%边界后,持续长按1秒自动反向调光,避免档位快速滑过,提升操作手感。
  • 视觉优化设计:引入Gamma2.2非线性校正算法,修正人眼视觉非线性缺陷,实现低亮度柔和渐变、高亮度变化清晰的视觉效果。
  • 状态反馈设计:仅亮度数值变化时串口输出亮度信息,避免串口刷屏,实时反馈系统工作状态。


四、调试软件介绍

  • CodeFusion Studio™:工程编译、下载、在线调试,配置 MAX32690 工程,完成代码编译烧录。
  • 串口助手(XCOM):波特率 115200,接收串口输出的亮度百分比,观测调光状态。
  • 硬件调试工具MAX32625PICO板附带加载的DAPLink映像,提供USB海量存储设备(MSD)拖放式编程、USB通信设备类(CDC)虚拟串行端口和Mbed网站使用的人机接口设备(HID) CMSIS-DAP接口。


五、软件流程图及关键代码片段

5.1 软件流程图

系统上电复位 → 初始化GPIO、SysTick定时器 → LED默认熄灭,系统启动完成 → 大循环轮询执行所有逻辑,完整流程如下:

image.png

5.2 关键代码片段

1. SysTick定时模块(系统1ms时基,非阻塞核心)

为全系统提供统一毫秒计时,全程无 delay 阻塞,保证调光、按键计时精准。

// 全局系统计时
static volatile uint32_t sys_ms = 0U;

// SysTick中断服务函数
void SysTick_Handler(void)
{
sys_ms++;
}

// 初始化1ms系统滴答
void systick_tick_init(void)
{
uint32_t ticks = SystemCoreClock / 1000U;
SysTick_Config(ticks);
NVIC_SetPriority(SysTick_IRQn, 0);
}

2.GPIO初始化模块(LED/按键硬件初始化)

严格匹配硬件特性:LED低电平点亮、上电默认熄灭;按键上拉输入,防误触发。

// LED初始化:默认高电平,LED熄灭
led_cfg.port = LED_PORT;
led_cfg.mask = LED_PIN;
led_cfg.func = MXC_GPIO_FUNC_OUT;
led_cfg.pad = MXC_GPIO_PAD_NONE;
led_cfg.vssel = MXC_GPIO_VSSEL_VDDIO;
MXC_GPIO_Config(&led_cfg);
MXC_GPIO_OutSet(LED_PORT, LED_PIN);

// 按键初始化:上拉输入
key_cfg.port = KEY_PORT;
key_cfg.mask = KEY_PIN;
key_cfg.func = MXC_GPIO_FUNC_IN;
key_cfg.pad = MXC_GPIO_PAD_PULL_UP;
key_cfg.vssel = MXC_GPIO_VSSEL_VDDIO;
MXC_GPIO_Config(&key_cfg);

3.Gamma非线性校正模块(项目核心优化算法)

解决人眼非线性问题,低亮度变化柔和、高亮度变化明显;强制最小PWM输出,保证5%档位微光不熄灭。

static uint32_t gamma_map(uint8_t input_bright)
{
float norm = (float)input_bright / 100.0f;
float gamma_out = powf(norm, 2.2f);
uint32_t pwm_val = (uint32_t)(gamma_out * 20.0f + 0.5f);

if(pwm_val > 20U)
pwm_val = 20U;
if(pwm_val < 1U) // 最低档位保留微光,不黑屏
pwm_val = 1U;

return pwm_val;
}

4. 长短按按键状态机模块

通过时间戳差值区分短按/长按,短按开关LED、长按进入调光,逻辑稳定无抖动误触发。

bool key_low = (0 == MXC_GPIO_InGet(KEY_PORT, KEY_PIN));

// 按键按下
if(key_low && !key_pressed)
{
key_pressed = true;
key_press_tick = now_ms;
}
// 按键松开,判定长短按
else if(!key_low && key_pressed)
{
uint32_t press_time = now_ms - key_press_tick;
if(press_time < 800U) // 短按:开关LED
{
led_enable = !led_enable;
printf("%d %%\r\n", brightness);
}
key_pressed = false;
at_boundary = false;
}

5. 边界延时换向 + 限幅保护模块(解决100%卡死bug)

到达5/100边界长按1秒自动换向,同时限幅保护,杜绝亮度越界、卡死锁死。

// 亮度下限5边界处理
if(brightness <= BRIGHTNESS_MIN)
{
if(!at_boundary)
{
at_boundary = true;
boundary_hold_tick = now_ms;
}
if(now_ms - boundary_hold_tick >= BOUNDARY_HOLD_MS)
{
dir = 1;
at_boundary = false;
brightness = brightness + dir * BRIGHTNESS_STEP;
}
}
// 亮度上限100边界处理
else if(brightness >= BRIGHTNESS_MAX)
{
if(!at_boundary)
{
at_boundary = true;
boundary_hold_tick = now_ms;
}
if(now_ms - boundary_hold_tick >= BOUNDARY_HOLD_MS)
{
dir = -1;
at_boundary = false;
brightness = brightness + dir * BRIGHTNESS_STEP;
}
}
else
{
brightness = brightness + dir * BRIGHTNESS_STEP;
}

// 限幅保护
if(brightness > BRIGHTNESS_MAX) brightness = BRIGHTNESS_MAX;
if(brightness < BRIGHTNESS_MIN) brightness = BRIGHTNESS_MIN;

6. 软件PWM波形输出核心代码

非阻塞软件PWM,根据Gamma映射值动态调节占空比,实现无闪烁无极调光。

if(led_enable == true)
{
pwm_tick += delta;
if(pwm_tick >= PWM_TICK_CNT)
{
pwm_tick = 0;
}
uint32_t high_tick = gamma_map(brightness);
// 硬件低电平点亮LED
if(pwm_tick < high_tick)
{
MXC_GPIO_OutClr(LED_PORT, LED_PIN);
}
else
{
MXC_GPIO_OutSet(LED_PORT, LED_PIN);
}
}
else
{
MXC_GPIO_OutSet(LED_PORT, LED_PIN);
pwm_tick = 0;
}

六、功能展示及说明

1.上电初始状态

设备复位后LED保持熄灭,串口输出中文系统启动提示,初始状态稳定无异常亮灭

image.png

串口输出系统启动

2.短按按键功能

单次短按点亮LED,保留上次调光亮度;再次短按关闭LED,每次切换均通过串口打印当前亮度值。

6C8713CB-1959-4a67-AC74-9E7401A11D8F.gif

image.png

串口输出默认亮度

3.长按调光功能

长按超过800ms进入调光状态,每500ms亮度变化5%,可从5%微光平滑递增至100%满亮,也可反向递减。

反.gif

image.png

串口输出实时亮度

4.边界换向功能

亮度到达100%最亮或5%最暗时,持续长按1秒自动反向调光,实现双向循环调节。

反1.gif

image.png

串口输出亮度

七、心得体会

通过本次MAX32690单片机PWM无极调光项目开发,我系统掌握了嵌入式裸机非阻塞编程的核心思路,理解了SysTick定时器时基搭建、软件PWM波形生成、按键长短按状态机设计的工作原理。相较于基础的LED闪烁实验,本次项目增加了算法优化、状态机逻辑、边界防抖、人机交互优化等工程化设计,让我认识到嵌入式开发不仅是实现基础功能,更需要兼顾稳定性、实用性与用户体验。

附件下载
key_led_blink.zip
团队介绍
一个热爱嵌入式的爱好者
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号