Funpack5-2 - 基于PIC32CM5164LS00048通过触摸输入实现LED亮度调节
该项目使用了Microchip PIC32CM5164LS00048 微控制器 的 触摸外设(PTC) 和 定时器(TC0)PWM 输出,结合 SYSTICK 系统定时器,实现了基于单触摸按键的 LED 智能调光控制的设计,它的主要功能为:短按触摸按键实现 LED 的开启与关闭;长按触摸按键(>400ms)进入连续调光模式,LED 亮度从当前值向最亮方向线性变化,到达极值后自动反向,形成亮度循环渐变;松手后退出调光模式并保持当前亮度。系统采用状态机设计,调光步长与时间间隔可配置,亮度变化平滑无闪烁。
标签
Funpack活动
MPLAB
PIC32
触摸按键
知足常乐
更新2026-06-15
8

一、项目介绍

本报告旨在完成 Funpack5-2 任务中的 LED 触摸控制与调光功能。项目基于 EV41C56A 开发板 及板载触摸按键,实现了从基础开关控制到高级连续调光的完整功能。其中,基础任务实现了触摸按键对 LED 的单次触发开关控制,逻辑清晰且无抖动误触;进阶任务进一步实现了 PWM 调光,支持长按连续调节亮度,亮度按照“灭 → 最亮 → 灭”的规律循环变化,松手后亮度保持,整个过程平滑过渡、无闪烁。项目充分验证了 PIC32CM5164LS00048 芯片在触摸交互与模拟输出控制方面的能力。

二、简短的所有使用到的硬件介绍

板卡简介EV41C56A 是 Microchip 推出的 PIC32CM LS00 Curiosity Nano+ Touch Evaluation Kit, 基于安全且超低功耗的 PIC32CM5164LS00048 微控制器(ARM Cortex-M23)。 该评估套件集成了板载调试器、触摸感应功能和完整的开发工具支持, 是学习安全嵌入式开发、触摸应用设计和低功耗优化的理想平台。

关键参数:

MCU

PIC32CM5164LS00048

内核

ARM Cortx-M23

Flash

512KB

SRAM

64KB

电压范围

1.7V-3.6V

调试器

板载PKOB nano

扩展接口

Curiosity Nano Edge

开发板外观:

正面-主控芯片与调试器

EV41C56A 正面

背面-触摸传感器区域

EV41C56A 背面

三大核心特性:

安全特性:

1、ARM TrustZone - 硬件级安全隔离,保护敏感代码和数据;

2、安全启动 - 验证固件完整性,防止恶意代码执行;

3、加密加速器 - 硬件AES、SHA、TRNG支持;

4、安全存储 - 密钥存储和防篡改机制

触摸控制:

1、PTC控制器 - 增强型外设触摸控制器;

2、多种触摸界面 - 支持按键、滑条、滚轮;

3、抗干扰设计 - 优秀的噪声抑制能力;

4、MCC Touch支持 - 图形化配置触摸功能;

低功耗设计

1、SleepWalking - 外设独立于CPU运行;

2、多种睡眠模式 - 灵活的功耗管理策略;

3、快速唤醒 - 微秒级唤醒响应;

4、电压范围宽 - 1.7V-3.6V工作电压;

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

方案框图:

image.png

设计目标:

本项目基于 EV41C56A 开发板和 PIC32CM5164LS00048 微控制器,利用板载触摸按键实现对 LED 的智能控制。基础功能要求单次触摸切换 LED 亮灭状态且无抖动误触;进阶功能要求在基础之上增加长按连续调光能力,亮度按照从灭到最亮、再从最亮到灭的规律循环变化,松手后亮度保持,整个调光过程必须平滑无闪烁。

硬件资源配置:

系统硬件以 PIC32CM5164LS00048 微控制器为核心,主要调用了三个外设模块。

1、 PTC 触摸控制器,负责检测板载触摸按键的触摸状态,配置为单通道轮询模式,通过周期性调用触摸处理函数来获取按键的按下与松开事件。

image.png

image.png

2、 TC0 定时器,用于产生 PWM 波形驱动 LED。该定时器工作在 16 位 Compare 模式的 Normal PWM 方式下,时钟分频设置为不分频,因此定时器直接以 48MHz 的系统时钟频率计数。由于是 16 位定时器,其周期寄存器默认值为 65535,用户无需额外配置周期值。占空比通过修改比较寄存器 Match1 进行控制,有效范围从 0 到 65534,对应亮度从完全熄灭到最高亮度,共计 65535 级亮度分辨率。PWM 输出频率约为 732 赫兹(48MHz 除以 65535),远高于人眼能够感知闪烁的频率范围,同时双缓存功能已使能,确保在连续修改占空比的过程中不会产生波形毛刺或异常跳变。

image.png

image.png

3、 SYSTICK 系统定时器,提供毫秒级的时间基准,用于长短按识别的计时以及调光过程中的亮度更新周期控制。

image.png

image.png

4、LED 驱动引脚已复用为 TC0 的 PWM 输出通道,直接接收 PWM 波形并控制 LED 亮度。

image.png

整体工作流程:

系统启动后首先完成所有外设的初始化工作,包括 PTC 触摸通道、TC0 的 PWM 参数以及 SYSTICK 定时器,LED 初始设置为关闭状态。随后主循环持续轮询读取触摸按键状态。

当检测到按键从松开变为按下时,系统记录当前时间戳并进入等待状态。若在 400 毫秒内检测到按键松开,则判定为短按,系统执行 LED 的开关切换操作,关闭时会保存当前亮度值,开启时会恢复上一次的亮度值。若按键持续按住超过 400 毫秒,则判定为长按,系统进入调光模式。

在调光模式下,系统以 15 毫秒为间隔不断调整亮度值,每次步进 500 级,到达亮度边界即 0 或 65534 时自动改变方向。这一过程持续到用户松手为止。松手后系统退出调光模式,将当前亮度锁定并将调光方向重置为递增,等待下一次触摸操作。

四、调试软件介绍、软件流程图及关键代码介绍

MPLAB简介:

MPLAB X IDE 是 Microchip 公司推出的旗舰级嵌入式开发环境,基于 NetBeans 平台构建,支持 Windows、macOS 和 Linux 三大操作系统。它专为 Microchip 全系列单片机(包括 PIC 系列、AVR 系列和 SAM 系列)提供统一的开发平台。

MPLAB X IDE 的核心功能包括:源代码编辑与项目管理、编译与调试、仿真与在线编程。它集成了 GCC 和 XC 系列编译器(XC8、XC16、XC32),支持硬件调试器(如 PICkit、ICD、Real ICE)进行断点调试、变量监视和寄存器查看。此外,MPLAB X IDE 还具备强大的项目管理能力,支持多工程协同开发,特别是针对支持 TrustZone 安全架构的芯片,可以同时管理安全工程和非安全工程。

对于初学者而言,MPLAB X IDE 的图形化界面降低了开发门槛,而其丰富的插件生态则满足了专业开发者的深度需求。

MCC简介:

MCC(MPLAB Code Configurator)是 MPLAB X IDE 中一款革命性的图形化代码配置插件工具。它的设计目标是让开发者通过图形界面配置外设参数,自动生成底层驱动代码,从而将开发者从繁琐的寄存器操作中解放出来,专注于应用层逻辑的实现。

MCC 的工作流程非常简单直观。开发者首先在图形界面中选择需要使用的芯片型号,然后在项目图中添加所需的外设模块,如 GPIO、定时器、UART、SPI、I2C、PWM 等。接着,通过下拉菜单和数值输入框配置各个外设的具体参数,例如定时器的分频系数、工作模式、周期值以及 PWM 的频率和占空比等。配置完成后,点击生成按钮,MCC 会自动产生完整的初始化代码和底层驱动 API,开发者可以直接在主函数中调用这些 API 来实现所需功能。

对于本项目而言,MCC 发挥了至关重要的作用。TC0 定时器的 PWM 模式配置,包括选择 Compare 模式下的 Normal PWM 波形、设置时钟不分频以及使能双缓存功能,全部通过 MCC 的图形化界面完成。触摸外设 PTC 的通道配置和初始化代码同样由 MCC 自动生成。SYSTICK 系统定时器的配置也借助了 MCC 的辅助。可以说,如果没有 MCC 的帮助,开发者需要查阅数千页的数据手册并手动编写大量寄存器操作代码,而有了 MCC,整个配置过程仅需几分钟即可完成。

MPLAB X IDE 与 MCC 的协同优势:

MPLAB X IDE 与 MCC 的组合形成了完整的开发流水线。IDE 提供了编译、调试、下载的运行环境,MCC 则负责硬件配置和驱动生成的起始环节。两者无缝集成,使得开发者从芯片选型到代码运行的全流程都能够在一个统一的平台内完成,大大缩短了开发周期,降低了出错概率。

软件流程图:

上图共分为以下几个部分:

第一部分:系统初始化。系统上电后,依次完成 PTC 触摸模块、TC0 的 PWM 模块以及 SYSTICK 定时器的初始化。其中 TC0 配置为 Normal PWM 模式,时钟不分频,双缓存功能使能,LED 初始状态为关闭,亮度值为 0。

第二部分:主循环与触摸检测。主循环持续调用 touch_process() 更新触摸状态,并读取当前按键值。通过边沿检测判断按键是刚刚按下、刚刚松开还是状态无变化。

第三部分:按下处理。当检测到按键刚刚按下时,系统记录当前时间戳,并清除长按触发标记。

第四部分:松开处理。当检测到按键刚刚松开时,判断是否已经触发过长按。若长按已触发,则退出调光模式,锁定当前亮度并将调光方向重置为递增。若长按未触发且按压时长小于 400 毫秒,则执行短按操作,切换 LED 的开关状态并在关闭时保存亮度值。

第五部分:长按检测与调光。在按键持续按住的期间,若按压时间达到 400 毫秒且尚未触发长按,则触发长按并进入调光模式。在调光模式下,每 15 毫秒执行一次亮度调整,每次增减 500 级亮度值。亮度到达上限 65534 或下限 0 时自动改变调光方向,实现循环渐变。每次调整后调用 TC0_Compare16bitMatch1Set() 更新 PWM 占空比。

第六部分:循环结束。更新上一次按键状态后,主循环继续下一次迭代。

关键代码介绍:

1、PWM亮度控制函数

static void set_led_brightness(uint16_t brightness)
{
if (brightness > PWM_PERIOD_MAX) {
brightness = PWM_PERIOD_MAX;
}
if (brightness < BRIGHTNESS_MIN) {
brightness = BRIGHTNESS_MIN;
}
TC0_Compare16bitMatch1Set(brightness);
current_brightness = brightness;
}

set_led_brightness 函数是硬件操作的核心。它首先对输入的亮度值进行限幅处理,确保不超过 0 到 65534 的有效范围,然后调用 MCC 生成的 TC0_Compare16bitMatch1Set 函数修改 TC0 定时器的比较寄存器值。该寄存器直接决定 PWM 波形的占空比,从而控制 LED 的亮度。写入后更新全局变量 current_brightness 以保持状态同步。由于 TC0 已使能双缓存功能,每次占空比更新都会在当前 PWM 周期结束后才生效,避免了波形毛刺。

2、短按开关与亮度记忆

static void led_off(void)
{
set_led_brightness(0);
led_state = LED_OFF;
}
static void led_on(void)
{
uint16_t start_brightness = last_brightness;
if (start_brightness == 0) {
start_brightness = 32767;
}
set_led_brightness(start_brightness);
led_state = LED_ON;
}

led_off 和 led_on 函数实现了短按开关的基本逻辑。关闭 LED 时,调用 set_led_brightness(0) 将亮度归零,并将状态切换为 LED_OFF。开启 LED 时,读取 last_brightness 变量恢复上次关闭前的亮度值。若该值为 0(表示芯片从未被开启过),则默认设置为 32767,对应 50% 亮度。这种亮度记忆机制让用户在反复开关时无需重新调整亮度,提升了操作体验的连贯性。

3、调光模式进入与推出

tatic void enter_dimming_mode(void)
{
if (current_brightness == 0) {
set_led_brightness(32767);
last_brightness = 32767;
}
led_state = LED_DIMMING;
last_dim_update_time = SYSTICK_GetTickCounter();
}
static void exit_dimming_mode(void)
{
if (led_state == LED_DIMMING) {
last_brightness = current_brightness;
led_state = LED_ON;
dim_direction = DIR_INCREASE;
}
}

enter_dimming_mode 函数在长按触发时被调用。进入调光模式前会检查当前亮度,如果 LED 处于关闭状态(亮度为 0),则先将亮度设置为 50%,确保用户开始调光时能够看到亮度变化。随后将状态切换为 LED_DIMMING,并记录当前时间戳作为调光更新的起始时刻。

exit_dimming_mode 函数在长按松手时被调用。它将当前亮度保存到 last_brightness 中,将状态切回 LED_ON,同时重置调光方向为递增,为下一次长按调光做好准备。

4、平滑调光更新算法

static void update_dimming(void)
{
uint32_t now = SYSTICK_GetTickCounter();;
if ((now - last_dim_update_time) < DIM_STEP_INTERVAL_MS) {
return;
}
last_dim_update_time = now;
if (dim_direction == DIR_INCREASE) {
if (current_brightness + DIM_STEP_VALUE <= PWM_PERIOD_MAX) {
set_led_brightness(current_brightness + DIM_STEP_VALUE);
} else {
dim_direction = DIR_DECREASE;
set_led_brightness(PWM_PERIOD_MAX - DIM_STEP_VALUE);
}
} else {
if (current_brightness >= DIM_STEP_VALUE) {
set_led_brightness(current_brightness - DIM_STEP_VALUE);
} else {
dim_direction = DIR_INCREASE;
set_led_brightness(DIM_STEP_VALUE);
}
}
}

update_dimming 函数是调光模式的核心逻辑,每 15 毫秒执行一次。它首先通过 SYSTICK_GetTickCounter 获取当前系统时间,判断是否已达到更新间隔,确保调光速度的稳定性。

亮度调整采用方向控制机制。在递增模式下,若当前亮度加上步长不超过最大值 65534,则直接增加 500 级;若超过最大值,则切换方向为递减,并将亮度设置为最大值减步长,实现到达最亮后自动反向。递减模式的逻辑对称,亮度减到小于步长时切换方向为递增。这种边界自动反向的设计实现了亮度在灭到最亮再到灭之间的无级循环渐变,调光过程流畅自然。

5、外设初始化

		TC0_CompareInitialize(); 
TC0_CompareStart();
RTC_Initialize();
SYSTICK_TimerInitialize();
SYSTICK_TimerStart();
touch_init();

必须将这些外设初始化写出来,不然对应的功能不能使用!!!

MCC初始化对应外设后,头文件中会产生对应外设的.h文件,其中会包含各种调用函数,方便在主函数中使用。

6、主循环触摸检测与长短按识别

        touch_process();
uint8_t current_key = get_sensor_state(0) & KEY_TOUCHED_MASK;
if (current_key && !last_key_state) {
press_start_time = SYSTICK_GetTickCounter();//SYSTICK_GetTick();
long_press_triggered = false;
short_press_pending = true;
}
if (!current_key && last_key_state) {
if (short_press_pending && !long_press_triggered) {
if (led_state == LED_OFF) {
led_on();
} else if (led_state == LED_ON) {
led_off();
}
} else if (long_press_triggered) {
exit_dimming_mode();
}
short_press_pending = false;
long_press_triggered = false;
}
if (current_key && short_press_pending && !long_press_triggered) {
uint32_t press_duration = SYSTICK_GetTickCounter() - press_start_time;
if (press_duration >= LONG_PRESS_MS) {
long_press_triggered = true;
short_press_pending = false;
enter_dimming_mode();
}
}
if (led_state == LED_DIMMING && current_key) {
update_dimming();
}
last_key_state = current_key;
}

主循环中首先调用 touch_process 更新触摸状态,然后读取当前按键值。通过将当前值与上一次值进行比较,实现边沿检测。

按键按下时(上升沿),记录当前时间戳到 press_start_time,并清除长按标记,同时设置短按待处理标记。按键松开时(下降沿),判断若短按待处理且长按未触发,则执行短按操作切换 LED 开关状态;若长按已触发,则调用 exit_dimming_mode 退出调光模式。

在按键持续按住的期间,若短按待处理且长按未触发,则不断计算按压时长,当达到 400 毫秒时触发长按,调用 enter_dimming_mode 进入调光模式。最后,若当前处于调光模式且按键仍按住,则调用 update_dimming 持续更新亮度。每次循环结束时更新上一次按键状态,为下一轮检测做准备。整个逻辑基于状态机和时间戳,长短按功能独立互不干扰,响应准确可靠。

五、功能展示图及说明

具体展示效果可以看视频中的演示部分。

短按实现LED的开关。长按通过PWM调节LED亮度。短按默认50%亮度开关,长按是从50%亮度变亮到100%再转向变灭到0%,然后再变亮到100%,往复循环,松手后亮度保持,再次短按可以实现在这个亮度进行开关控制。整个调光过程必须平滑无闪烁。

六、项目中遇到的难题及解决方法

1、开发环境与软件工具不熟悉

本项目是首次接触 Microchip 平台的开发,对 MPLAB X IDE 和 MCC 代码配置器的使用完全陌生。不知道如何新建工程、如何添加外设模块、如何通过图形界面配置定时器参数,更不清楚如何将配置结果生成为可用的底层驱动代码。此外,对于 PIC32CM5164LS00048 芯片的 SYSTICK 定时器 API 也不熟悉,最初尝试调用 SYSTICK_GetTick() 函数获取系统时间,但编译时发现该函数并不存在,导致时间基准无法获取,长短按识别和调光周期控制都无法进行。

解决方法:

首先通过 Microchip 官网和官方文档系统学习了 MPLAB X IDE 的基本操作流程,包括创建工程、选择芯片型号、配置编译器路径等。然后针对 MCC 的使用,参考了官方的快速入门指南和视频教程,逐步掌握了在图形界面中添加 TC0 定时器、PTC 触摸外设和 SYSTICK 系统定时器的方法,学会了设置时钟分频、PWM 工作模式和双缓存等参数,并通过点击 Generate 按钮自动生成初始化代码。对于 SYSTICK 的 API 问题,仔细阅读了 MCC 生成的头文件,发现实际可用的函数是 SYSTICK_GetTickCounter() 而非 SYSTICK_GetTick(),将代码中的调用全部替换后编译通过,系统时间基准成功建立,长短按计时功能正常运行。通过这次实践,后续配置其他外设和调试代码的效率大幅提升。

2、触摸按键长短按识别与调光逻辑设计

在实现触摸控制逻辑时遇到了两个核心难点。第一个难点是长按和短按的区分。最初采用直接检测电平的方式,只要检测到触摸就执行操作,结果导致一次短按被识别为多次触发,LED 会连续翻转多次。同时无法准确区分用户是想要短按开关还是长按调光,导致两种功能相互干扰。第二个难点是调光平滑性的实现。初始版本中亮度变化采用固定步长,但步长设置过大时亮度跳变明显,步长设置过小时调光速度太慢用户体验差。此外,在连续修改 PWM 占空比时,由于没有考虑更新时机,偶尔会出现亮度抖动或毛刺现象。调光的循环逻辑(到达最亮后自动反向变暗)也需要额外的状态管理。

解决方法:

对于长短按区分问题,设计了基于时间戳的状态机方案。在按键按下时记录起始时间,松手时计算按压时长,小于 400 毫秒判定为短按,大于等于 400 毫秒且松手前已触发调光模式则判定为长按结束。同时采用边沿检测法,仅在按键状态发生变化的瞬间响应,彻底消除了抖动导致的误触发。对于调光平滑性问题,充分利用了 TC0 的 16 位 PWM 分辨率(65535 级),通过反复测试确定了步长 500 级配合 15 毫秒更新间隔的组合,既保证了约 2 秒完成全量程变化的舒适速度,又实现了肉眼完全无感知的平滑过渡。同时启用了 TC0 的双缓存功能,确保占空比更新在当前周期结束后才生效,避免了波形毛刺。对于循环调光逻辑,增加了方向变量 dim_direction,亮度到达边界时自动切换方向,实现了灭到亮再到灭的循环渐变效果。最终的状态机代码结构清晰,四种状态(LED_OFF、LED_ON、LED_DIMMING)转换逻辑明确,长短按功能完全独立互不干扰。

七、心得体会

通过本次活动,我从零开始完成了基于PIC32CM5164LS00048的触摸调光系统开发,收获颇丰。

我首次使用MPLAB X IDE和MCC代码配置器,从最初对图形化配置外设感到陌生,到最终能够熟练配置TC0的PWM模式、PTC触摸通道和SYSTICK定时器,深刻体会到善用开发工具可以大幅提升工作效率。同时,我对PWM调光原理有了深入理解,掌握了占空比与亮度的关系、双缓存防毛刺机制以及频率选择对视觉体验的影响。我学会了系统化的调试方法。当遇到编译错误或功能异常时,不再盲目修改代码,而是通过查阅头文件、分析数据流程来定位根源。长短按识别的时间戳方案、边沿检测防抖方法、调光步长与间隔的参数调优,都是在反复试验中逐步完善的。

在工程思维上,将可调参数定义为宏、使用状态机管理逻辑、分离硬件操作与业务代码等良好习惯,让程序结构清晰且易于维护。

这次项目让我建立了对Microchip平台开发的信心,也培养了我解决实际工程问题的能力。

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