一、项目介绍和创意介绍
本项目基于 Microchip 的 EV41C56A 开发板,完成了 Funpack5-2 活动中任务1“触摸输入与 LED 控制”的基础题与进阶题。项目的核心目标,是使用开发板板载触摸按键实现对板载 LED 的稳定控制,并在此基础上增加长按亮度调节功能。
基础题的功能要求比较明确,即通过单次触摸实现 LED 点亮,再次触摸实现 LED 熄灭。进阶题则在基础触摸开关的基础上,增加了“长按调节亮度”的功能。实现要求包括:短按实现 LED 开关控制;长按时,LED 亮度按照“灭到最亮,再从最亮回到灭”的方式循环变化;整个亮度变化过程应平滑,不能出现明显闪烁和跳变。这个功能相当于把原本的二值控制,扩展成了带有连续调光特性的交互系统,因此不仅要处理触摸状态,还要引入 PWM 外设,并结合按压时间判断短按与长按。
可以看出这个任务并不是简单地在一个 `while(1)` 循环里读按键、翻转 GPIO,而是结合了 `QTouch` 触摸库、`RTC` 定时采样、`TC0` PWM 输出、`SERCOM3` 串口调试以及 `TrustZone` 安全/非安全工程协同等多个模块。所以我在基础题和进阶题都采用了安全域与非安全域分离的工程结构:触摸处理和关键外设控制主要在 `secure` 工程中完成,非安全工程负责系统任务调度和串口打印。这种结构一方面体现了 PIC32CM LS00 系列对安全隔离的支持,另一方面也让整个项目更接近实际产品开发的组织方式。
二、硬件介绍
本项目所使用的主硬件平台为EV41C56A。它是一块面向低功耗、触摸应用和安全应用场景的评估板,适合用于学习 Microchip 触摸方案、外设配置以及 TrustZone 安全架构。
本项目实际使用到了以下几个板载资源:
1.主控 MCU:`PIC32CM5164LS00048`
2.板载触摸按键通道
3.板载用户 LED
4.板载调试/下载接口
5.串口调试通道
硬件实物图如下:

三、方案框图和项目设计思路
系统框图:

设计思路:
1. 基础题设计思路
基础题的核心在于“单次触摸只触发一次状态翻转”。如果只是检测当前是否被触摸,然后立即切换 LED 状态,就会出现一个典型问题:手指按住的时间远大于程序循环时间,于是在一次按下过程中,程序会重复多次检测到“正在触摸”,从而造成 LED 连续翻转,最终表现为误触发或者闪烁。为了解决这个问题,我采用了边沿检测思路:首先保存上一次触摸状态 `last_touch_state`,然后本次采样得到当前触摸状态 `current_touch_state`,最后只有当状态从“未触摸”变为“已触摸”时,才认定为一次新的触摸事件。这样就把“持续按住”与“新的一次触发”区分开了。只有在上升沿出现时,程序才执行一次 `Usr_LED_Toggle()`,并同步更新逻辑状态 `logical_led_state`。这种方法结构简单、运行可靠。
2. 进阶题设计思路
进阶题相比基础题,新增了一个重要维度:按压时间。也就是说,不仅要判断“有没有按”,还要判断“按了多久”。因此,我在安全域中引入了 `touch_hold_count` 变量,用于统计触摸持续时间,并依据阈值实现以下逻辑划分为短按和长按。
具体亮度调节策略如下:
1.初始亮度保存于 `current_brightness`
2.使用 `direction` 表示调节方向,`1` 为变亮,`-1` 为变暗
3.长按时每隔固定计数步进一次亮度
4.当亮度到达最大值后,方向反转
5.当亮度降低到接近熄灭时,再次反转方向
这样就实现了题目要求的“灭 -> 最亮 -> 灭”的循环渐变效果。由于 PWM 比较值是逐步微调的,LED 亮度变化肉眼看起来较平滑,不会突然跳变。
四、软件流程图和关键代码介绍
软件流程图
基础题的软件流程如下:

进阶题的软件流程如下:

关键代码一:基础题中的边沿检测逻辑
bool current_touch_state = (get_sensor_state(0) & 0x80) ? true : false;
if (current_touch_state == true && last_touch_state == false)
{
Usr_LED_Toggle();
logical_led_state = !logical_led_state;
}
last_touch_state = current_touch_state;
这段逻辑的关键点在于,它并不直接根据“当前是否按下”来切换 LED,而是判断触摸状态是否从 0 变成 1,也就是上升沿触发。这样做可以有效避免一次长触摸导致多次翻转,是本项目基础题稳定运行的关键。
关键代码二:进阶题中的短按和长按判定
进阶题在安全域中增加了三个重要参数:
#define SHORT_PRESS_THRESHOLD 1000
#define LONG_PRESS_THRESHOLD 40000
#define SPEED 600
其中:
SHORT_PRESS_THRESHOLD`用于过滤极短的误触
LONG_PRESS_THRESHOLD 用于区分短按和长按
SPEED用于控制亮度变化的步进速度
当手指持续按住时,程序持续累加 touch_hold_count。如果计数值超过长按阈值,就进入调光逻辑;如果在短按区间内松手,则执行一次 LED 开关切换。
关键代码三:PWM 亮度调节代码
int16_t new_brightness = current_brightness + direction;
if (new_brightness >= 255) {
new_brightness = 255;
direction = -1;
} else if (new_brightness <= 10) {
new_brightness = 10;
direction = 1;
}
current_brightness = (uint8_t)new_brightness;
TC0_Compare8bitMatch1Set(current_brightness);
这段代码通过 `direction` 控制亮度增减方向,并在到达上下边界时自动反向。这里把最小亮度下限设为 `10` 而不是 `0`,其实际作用是避免长按调光过程中亮度完全熄灭后用户误以为系统失效。
五、功能展示图及说明
基础题功能展示:
手指触摸按键后,板载 LED 点亮
再次触摸后,板载 LED 熄灭
进阶题功能展示:
短按点亮 LED
长按过程中 LED 亮度逐渐增强
继续长按后亮度由最亮逐渐减弱
六、项目中遇到的难题及解决方法
1. 首先是MCC的安装,一开始一直无法安装成功。最后切换了一个系统用户名非中文的电脑才成功了
2. 还有就是没找到官方的触摸例程,最后还是通过观看直播,去参考其他开发板的触摸例程才学会应该怎么配置。
3. 触摸配置后无法使用,必须要修改初始化顺序。具体是在SYS_Initialize()中应该修改RIC_Initialize();和touch_init();的顺序。应该先初始化RIC_Initialize();
七、心得体会
以前做按键实验时,更多是基于 GPIO 读取电平,而这次项目让我真正接触到了触摸采样、阈值、滤波、状态判定和调试参数之间的关系。表面上看,触摸开关只是“按一下亮、再按一下灭”,但在实现层面,它比机械按键更考验系统设计细节。
其次,这次项目让我更深刻地体会到“状态机”在嵌入式开发中的重要性。无论是基础题中的单次触摸翻转,还是进阶题中的短按/长按判定,本质上都不是简单的条件判断,而是对“过去状态、当前状态、持续时间、输出结果”进行综合管理。如果没有清晰的状态切换思路,程序很容易出现重复触发、误判或者交互不连贯的问题。
本次项目中另一个让我印象比较深的点,是 `TrustZone` 双工程结构。虽然本次任务规模不算大,但通过把触摸处理和 LED/PWM 控制放在安全域中执行,我第一次更直观地理解了安全域与非安全域协作的开发方式。