项目介绍
本项目用Microchip的EV41C56A开发板,实现了软件模拟PWM来控制LED亮度控制功能。支持短按按键控制LED 开或者关、长按按键实现亮度双向线性平滑调节(灭→最亮→灭循环),且调光过程无闪烁、无跳变,满足人机交互的流畅性与视觉舒适性要求。
硬件介绍
本项目仅使用 EV41C56A 开发板板载硬件资源,核心硬件如下:
- PIC32CMLS00 32 位单片机:项目主控核心,内核:Cortex-M23,主频:48HMz,Flash / SRAM:512 / 64 KB。
- 板载LED:默认连接单片机指定的GPIO引脚,作为PWM调光执行器件,通过不同占空比的电平信号实现亮度调节;
- 板载触摸按键:用于输入短按 / 长按控制指令,连接单片机GPIO引脚;
- 电源电路:板载USB供电电路,为单片机及外设提供稳定的工作电压。

方案框图和项目设计思路介绍

主循环软件模拟 PWM 核心原理
无定时器中断,通过主循环 for 循环遍历 255 个周期计数实现 PWM 波形:定义 PWM 周期为 255 级,亮度值 0~255 对应占空比 0%~100%;循环中判断计数值与亮度值,控制 LED GPIO 电平输出,纯软件实现调光。
触摸按键状态识别逻辑
软件计数消抖 + 长按阈值判断:
- 消抖:连续 50 次检测到触摸,判定为按键稳定按下;
- 短按:触摸按下时长<1000 次计数并释放,切换 LED 开关;
- 长按:触摸按下时长 ≥ 1000 次计数,触发连续亮度调节。
亮度双向循环调节逻辑
亮度范围:0(灭)~255(最亮),通过方向标志位dir控制:
- 递增:亮度从 0→255,到达最大值自动切换为递减;
- 递减:亮度从 255→0,到达最小值自动切换为递增;
- 长按每 10 次计数刷新一次亮度,保证调光平滑。
短按开关逻辑
短按触摸按键:LED 开启则直接熄灭(亮度 0);LED 关闭则直接点亮为最亮(255),并重置调光方向为递增。
软件流程图及关键代码介绍
开发工具链:
- MPLAB X IDE:代码编辑、编译、下载与在线调试;
- XC32 C 编译器:PIC32 系列单片机专用编译器;
- MPLAB Code Configurator (MCC):图形化初始化 GPIO、触摸驱动;
软件流程图:

#define LONG_PRESS_TRIGGER 1000
#define BRIGHT_MAX 255
#define BRIGHT_MIN 0
#define PWM_FULL_CYCLE 255
#define CHANGE_DELAY 10
int main ( void )
{
uint32_t msp_ns = *((uint32_t *)(TZ_START_NS));
volatile funcptr_void NonSecure_ResetHandler;
/* Initialize all modules */
SYS_Initialize ( NULL );
if (msp_ns != 0xFFFFFFFF)
{
__TZ_set_MSP_NS(msp_ns);
NonSecure_ResetHandler = (funcptr_void)(*((uint32_t *)((TZ_START_NS) + 4U)));
NonSecure_ResetHandler();
}
uint8_t key_state = 0;
uint8_t prev_key_state = 0;
uint32_t press_cnt = 0;
uint8_t led_enable = 0;
uint8_t brightness = 0;
uint8_t dir = 1;
uint32_t slow_cnt = 0;
uint8_t short_press_flag = 0;
uint8_t debounce_cnt = 0;
while ( 1 )
{
touch_process();
prev_key_state = key_state;
key_state = get_sensor_state(0) & 0x80;
if(key_state)
{
if(debounce_cnt < 255) debounce_cnt++;
}
else
{
debounce_cnt = 0;
}
uint8_t key_stable = (debounce_cnt > 50) ? 0x80 : 0x00;
static uint8_t prev_key_stable = 0;
if(key_stable && !prev_key_stable)
{
press_cnt = 0;
short_press_flag = 0;
}
if(key_stable)
{
press_cnt++;
if(press_cnt >= LONG_PRESS_TRIGGER)
{
short_press_flag = 1;
slow_cnt++;
if(slow_cnt >= CHANGE_DELAY)
{
slow_cnt = 0;
if(dir == 1)
{
brightness++;
if(brightness >= BRIGHT_MAX)
{
brightness = BRIGHT_MAX;
dir = 0;
}
}
else
{
brightness--;
if(brightness <= BRIGHT_MIN)
{
brightness = BRIGHT_MIN;
dir = 1;
}
}
led_enable = (brightness > 0) ? 1 : 0;
}
}
}
else if(prev_key_stable)
{
if(short_press_flag == 0 && press_cnt > 0 && press_cnt < LONG_PRESS_TRIGGER)
{
led_enable = !led_enable;
if(led_enable)
{
brightness = BRIGHT_MAX;
}
else
{
brightness = BRIGHT_MIN;
dir = 1;
}
}
press_cnt = 0;
slow_cnt = 0;
short_press_flag = 0;
}
prev_key_stable = key_stable;
if(led_enable)
{
for(uint32_t i=0; i<PWM_FULL_CYCLE; i++)
{
if(i < brightness)
{
LED1_Set();
}
else
{
LED1_Clear();
}
}
}
else
{
LED1_Clear();
}
}
return EXIT_FAILURE;
}
功能展示图及说明
初始状态:开发板上电,LED1 熄灭,亮度值为 0;
短按触摸:LED1 立即点亮为最亮状态;再次短按,LED1 熄灭,开关响应灵敏;
长按递增调光:长按触摸保持,LED 亮度从 0 平滑递增至 255(最亮);
长按递减调光:亮度到达最亮后继续长按,自动从 255 平滑递减至 0;
循环调光:持续长按,LED 重复「灭→最亮→灭」平滑循环,无闪烁、无跳变。


项目中遇到的难题及解决方法
难题 1:LED所接的如何输出PWM
配置TTC0中只有Channel0~3,但是在配置Pin这里是TCC0的通道5,不知道是啥原因

难题 2:GPIO 模拟 PWM 出现 LED 闪烁
- 原因:PWM 频率过低(<50Hz),人眼感知到电平闪烁;亮度步长过大,调节跳变明显。
- 解决方法:将 PWM 频率设为 100Hz,亮度调节步长设为 1%,缩短长按刷新间隔至 10ms,彻底消除闪烁。
难题 3:短按 / 长按误触发
- 原因:无按键消抖,按键机械抖动导致检测错误;长按阈值设置不合理。
- 解决方法:增加 10ms 软件消抖,长按阈值设为 500ms,通过静态变量记录按键状态,精准区分指令。
心得体会
通过本次基于 EV41C56A 开发板的 LED 调光项目,我对Microchip这个芯片的使用了有了比较基础的认知和开发经验