1. 项目介绍
1.1 项目背景
随着物联网和智能家居设备的快速发展,人机交互界面正向着更加直观、自然的方向演进。触摸按键作为一种无需机械按压的交互方式,凭借其防水防尘、寿命长、外观美观等优点,已广泛应用于各类电子产品中。Microchip公司的32位低功耗MCU系列产品因其丰富的片上资源和灵活的触摸检测能力,成为实现电容式触摸按键应用的理想平台。
本项目来源于实际产品开发需求,旨在利用EV41C56A开发板(基于PIC32CM5164LS00048微控制器)实现一个具有短按和长按两种交互模式的LED控制系统。该系统需要能够准确识别用户的触摸意图——区分短时触碰与持续按压——并据此控制LED的状态,实现直观的视觉反馈。
1.2 项目目标
本项目的主要目标是设计并实现一个功能完整的触摸按键LED控制固件,具体要求如下:
基本功能需求:
- 单次触摸(触摸时间小于5秒):控制LED点亮或关闭,实现LED状态的切换
- 长时触摸(触摸时间大于等于5秒):使LED进入闪烁模式,以直观方式提示用户已进入特殊模式
扩展功能需求:
- 闪烁模式下,LED闪烁频率应随时间自动加快,每隔约5秒加速一次,以提供更具动感的视觉反馈
性能指标要求:
- 触摸检测周期:20毫秒(保证响应的实时性)
- 触摸响应延迟:小于100毫秒(从触摸发生到LED状态变化)
- 长按识别阈值:250个检测周期(约5秒)
- 闪烁频率范围:10Hz至1Hz可调
2. 硬件介绍
开发板
本项目使用的核心控制器是Microchip PIC32CM5164LS00048,这是一款基于ARM Cortex-M33内核的32位低功耗微控制器,属于PIC32CM LS系列家族。该系列芯片是Microchip为安全应用设计的MCU产品线,集成了TrustZone安全扩展,非常适合需要高可靠性和安全性的嵌入式应用场景。EV41C56A是Microchip官方推出的一款评估开发板,专门用于展示PIC32CM-LS系列微控制器的各项功能。该开发板板载多个实用外设,极大地方便了开发者进行原型验证和功能评估。
板载资源:
3. 方案框图与设计思路
我们本次主要使用MCC进行相关的使用到外设继续配置,主要用到的包括PIN配置,定时器配置,touch库配置,图形化选择:
电容式触摸检测的核心是PTC(Peripheral Touch Controller)模块。Microchip的QTouch库为开发者提供了完整的触摸检测解决方案,包括采集算法、滤波处理和状态机管理。
引脚配置
touch配置
定时器配置
状态机设计
为了正确区分短按和长按,并管理LED的多种状态,本项目设计了一个简单的状态机:
┌──────────────┐
│ IDLE │◀─────────────────────────┐
│ (等待触摸) │ │
└──────┬───────┘ │
│ 触摸按下 │
▼ │
┌──────────────┐ │
┌───────│ TOUCHED │ │
│ │ (触摸进行中) │ │
│ └──────┬───────┘ │
│ │ 计数 ≥ 250 │ 触摸释放
│ │ (约5秒) │ (计数 < 250)
│ ▼ │
│ ┌──────────────┐ │
│ │ BLINKING │──────────────────────────┤
│ │ (闪烁模式) │ │
│ └──────┬───────┘ │
│ │ 触摸释放 │
│ └───────────────────────────────────┘
│
│ 触摸释放 (短按)
▼
LED状态翻转
状态说明:
状态 | 说明 | 进入条件 | 退出条件 |
IDLE | 空闲等待 | 系统启动/触摸释放后 | 检测到触摸按下 |
TOUCHED | 触摸进行中 | 触摸按下 | 触摸释放(短按)或计数达标(长按) |
BLINKING | 闪烁模式 | 触摸持续5秒以上 | 触摸释放 |
状态转换详解:
- IDLE → TOUCHED:当检测到触摸按下时(touched && !last_touch),状态从IDLE转换为TOUCHED,同时将触摸计数清零。这个边沿检测逻辑确保每次触摸只被识别一次。
- TOUCHED → IDLE:如果触摸在5秒内释放(touch_cnt < LONG_TOUCH_CNT && !touched),则判定为短按,执行LED Toggle操作后返回IDLE状态。
- TOUCHED → BLINKING:如果触摸持续超过5秒(touch_cnt >= LONG_TOUCH_CNT),则判定为长按,进入BLINKING模式,LED开始闪烁。
- BLINKING → IDLE:在闪烁模式下,只有当触摸释放时才会退出,回到IDLE状态。这确保了用户在体验完闪烁效果后,可以通过释放触摸来结束该模式。
4. 软件设计与实现
软件流程图

触摸状态机流程图:
关键代码分析
头文件包含与常量定义:
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include "definitions.h" // 系统级定义(GPIO、PORT_PIN等)
#include "config/default/touch/touch.h" // QTouch库主头文件
#include "config/default/touch/touch_example.h" // 触摸示例(包含measurement_done等)
// 定义LED控制宏(使用port.h中的预定义宏)
#define LED_OFF() GPIO_PA15_Clear() // 低电平点亮
#define LED_ON() GPIO_PA15_Set() // 高电平熄灭
#define LED_TOGGLE() GPIO_PA15_Toggle() // 状态翻转
// 长按阈值:250个20ms周期 = 5秒
#define LONG_TOUCH_CNT 250
// 闪烁参数
#define BLINK_START_MS 1000 // 初始闪烁间隔1秒
#define BLINK_MIN_MS 100 // 最快100ms
全局变量与回调函数声明:
// TC0溢出标志(volatile保证在中断中写入,主循环中读取)
volatile bool tc0_flag = false;
// TC0中断回调函数声明
void tc0_callback(TC_TIMER_STATUS status, uintptr_t context);
触摸状态检测函数:
// 获取触摸状态的函数
bool is_touched(void) {
// get_sensor_state(0)返回传感器0的状态
// KEY_TOUCHED_MASK = 0x80,bit7表示"In Detect"状态
return (get_sensor_state(0) & KEY_TOUCHED_MASK) != 0;
}
关于KEY_TOUCHED_MASK的定义,QTouch库中定义如下:
// qtm_common_components_api.h
#define KEY_TOUCHED_MASK 0x80u
这个宏表示当bit7为1时,表示传感器处于"检测中"状态(包括Detect和Filter Out两种子状态)。在自电容模式下,当手指触摸传感器时,传感器状态值的高位会被置位,从而触发KEY_TOUCHED_MASK条件。
TC0回调函数:
void tc0_callback(TC_TIMER_STATUS status, uintptr_t context)
{
(void)status; // 未使用的参数
(void)context; // 未使用的参数
tc0_flag = true; // 设置标志,在主循环中处理
}
这个简单的回调函数将TC0溢出事件转换为一个标志位,主循环通过轮询这个标志来执行闪烁逻辑。这种设计避免了复杂的嵌套中断处理。
主循环核心逻辑:
while (true)
{
touch_process(); // 调用QTouch库的处理函数
if (measurement_done_touch == 1u) // 检查测量完成标志
{
measurement_done_touch = 0u; // 清除标志
bool touched = is_touched(); // 获取当前触摸状态
if (blink_active) {
// 闪烁模式下:只有触摸释放才退出
if (!touched) {
blink_active = false;
LED_OFF();
}
} else {
// 正常模式:使用状态机处理
if (touched && !last_touch) {
// 触摸开始(边沿检测)
touch_cnt = 0;
}
if (touched) {
touch_cnt++; // 计数增加
if (touch_cnt >= LONG_TOUCH_CNT) {
// 进入闪烁模式
blink_active = true;
blink_ms = BLINK_START_MS;
blink_cnt = 0;
blink_stage = 0;
blink_speed_cnt = 0;
blink_led = true;
LED_ON();
touch_cnt = 0;
}
} else {
// 触摸释放
if (touch_cnt > 0 && touch_cnt < LONG_TOUCH_CNT) {
LED_TOGGLE(); // 短按:翻转LED
}
touch_cnt = 0;
}
}
last_touch = touched;
}
// 闪烁模式LED控制
if (blink_active && tc0_flag) {
tc0_flag = false;
blink_cnt++;
uint32_t threshold = blink_ms / 20;
if (blink_cnt >= threshold) {
blink_cnt = 0;
blink_led = !blink_led;
if (blink_led) LED_ON(); else LED_OFF();
}
// 每5秒加速一次
blink_speed_cnt++;
if (blink_speed_cnt >= 250) {
blink_speed_cnt = 0;
if (blink_stage < 10) {
blink_ms = BLINK_START_MS - (blink_stage * 100);
if (blink_ms < BLINK_MIN_MS) blink_ms = BLINK_MIN_MS;
blink_stage++;
}
}
}
for (volatile uint32_t d = 0; d < 100; d++); // 简单延时
}
5. 功能测试与验证
实物操作效果如下,包括长按和短按效果展示:

6. 心得体会
本次项目让我对Microchip PIC32系列微控制器嵌入式开发有了更深理解与实践。理解电容式触摸检测原理,掌握PTC模块配置及硬件调试方法;熟悉QTouch库架构,理解中断驱动编程模式,学会设计状态机。本次项目虽然功能相对简单,但完整地经历了嵌入式项目开发的各个阶段,这种实践经验是单纯学习理论知识无法替代的。希望这份报告能够为后续的开发者提供有价值的参考,也作为自己成长道路上的一个重要里程碑。