基于Microchip EV41C56A实现触摸按键控制LED
一、活动介绍
本次参加的是电子森林Funpack第五季第二期活动,活动板卡为Microchip公司的EV41C56A开发板,型号为PIC32CM LS00 Curiosity Nano+ Touch Evaluation Kit。这是一款基于ARM Cortex-M23内核的微控制器开发板,特色功能就是集成了电容触摸检测功能。
活动要求参与者从三个任务中任选其一完成,我选择了**任务1:触摸输入与LED控制**的基础题目。
具体要求是:使用开发板板载触摸按键功能,实现单次触摸点亮LED,再次触摸关闭LED,循环往复。需要正确初始化触摸通道,控制逻辑清晰,无误触发。
二、开发环境搭建
2.1 软件安装
开发环境使用Microchip官方提供的MPLAB X IDE v6.x,搭配XC32编译器。安装过程比较简单:
1. 从Microchip官网下载MPLAB X IDE安装包
2. 运行安装程序,按照向导完成安装
3. 安装XC32编译器,MPLAB X会自动识别
4. 安装对应PIC32CM系列的器件包(DFP)
2.2 使用MHC配置Touch功能
MPLAB X提供了MPLAB Harmony Configurator(MHC)图形化配置工具,可以非常方便地配置触摸功能:
1. 在MHC中添加"Touch"组件
2. 选择使用PTC(Peripheral Touch Controller)触摸控制器
3. 根据硬件设计选择触摸通道,板载触摸按键连接到PA22
4. 配置触摸参数:采样周期、检测阈值等,使用默认参数即可工作
5. 生成代码,MHC会自动生成触摸库的初始化和驱动代码
三、硬件资源介绍

EV41C56A开发板是Microchip推出的PIC32CM LS00系列评估板,主要硬件资源如下:
- MCU:PIC32CM5164LS00048
- 内核:ARM Cortex-M23(支持TrustZone安全架构)
- Flash:516KB,RAM:64KB
- 板载一个电容触摸按键(连接到PA22)
- 板载一个用户LED(连接到PA15)
- 供电:USB直接供电
- 调试接口:板载EDBG调试器
根据硬件设计和MHC配置:
触摸按键:PA22 - PTC通道Y16,自容式检测
用户LED:PA15 - GPIO输出,低电平点亮/高电平熄灭(取决于硬件设计)
四、方案设计思路
4.1方案框图

4.2 TrustZone架构说明
PIC32CM支持ARM TrustZone安全架构,所以MPLAB X在生成项目时会自动生成两个项目:
- `project` - 非安全项目(Non-secure)
- `project_secure` - 安全项目(Secure)
触摸功能的初始化和PTC触摸控制器配置在安全项目中。由于我们这个项目功能简单,不需要复杂的安全隔离,所以我决定**直接在安全项目中实现整个应用逻辑**,省去跨安全域调用的复杂性,这样代码更简洁,调试更方便。
4.2 触摸检测原理
Microchip提供了QTouch触摸库,使用PTC外设进行电容触摸检测:
1. PTC周期性采样触摸电极的电容值
2. 当手指触摸时,电容值发生变化
3. QTouch库通过信号处理算法判断是否有触摸
4. 通过API可以读取触摸传感器的状态
本项目只有一个触摸按键,配置为自容式检测(NODE_SELFCAP)。
4.3 按键消抖设计
为了避免误触发和重复触发,使用**上升沿检测**方案:
- 保存上一次的触摸状态 `previous_touch_state`
- 每次测量完成后获取当前触摸状态 `current_touch_state`
- 只有当 `当前有触摸 && 上一次无触摸` 时才触发一次
- 这样保证每按一次只切换一次LED状态,长按不会重复触发
五、代码实现
5.1 项目结构
project_secure/
├── src/
│ ├── main.c # 主程序(我们实现的代码)
│ ├── config/default/
│ │ ├── touch/ # MHC生成的触摸配置代码
│ │ ├── peripheral/ # 外设驱动代码(PORT、RTC等)
│ │ └── definitions.h # 系统定义
│ └── trustZone/
│ └── nonsecure_entry.c # 非安全入口(我们不使用)
5.2 完整代码
// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************
#include <stddef.h> // Defines NULL
#include <stdbool.h> // Defines true
#include <stdlib.h> // Defines EXIT_FAILURE
#include "definitions.h" // SYS function prototypes
// Touch sensor number
#define TOUCH_SENSOR 0
// *****************************************************************************
// *****************************************************************************
// Section: Main Entry Point
// *****************************************************************************
// *****************************************************************************
int main(void)
{
/* Touch state variables */
// 定义3个变量:
// previous_touch_state - 保存上一次的触摸状态
// current_touch_state - 保存当前的触摸状态
// led_state - 保存LED的开关状态
uint8_t previous_touch_state = 0;
uint8_t current_touch_state = 0;
bool led_state = false;
/* Initialize all modules */
// 调用系统初始化函数,初始化所有硬件模块(时钟、端口、触摸等)
SYS_Initialize(NULL);
/* Initialize LED state - default off */
// 初始化LED为关闭状态(PA15输出低电平)
GPIO_PA15_Clear();
// 进入无限循环,程序永远在这里运行
while (true)
{
/* Call touch process function */
// 调用触摸处理函数,这是触摸库的核心函数
// 它会启动触摸测量、处理触摸数据、运行状态机
touch_process();
/* Check if touch measurement is done */
// 检查触摸测量是否完成标志
// measurement_done_touch 是触摸库设置的全局变量
if (measurement_done_touch == 1u)
{
/* Clear measurement done flag */
// 清除测量完成标志,准备下一次测量
measurement_done_touch = 0u;
/* Get current touch state - use KEY_TOUCHED_MASK */
// 获取触摸传感器0的状态,用KEY_TOUCHED_MASK(0x80)过滤
// 如果返回非0,表示触摸被按下;返回0表示未触摸
current_touch_state = get_sensor_state(TOUCH_SENSOR) & KEY_TOUCHED_MASK;
/* Detect touch press event (rising edge) */
// 检测上升沿:当前有触摸 && 上一次无触摸
// 这样只在刚按下时触发一次,避免长按一直触发
if (current_touch_state != 0 && previous_touch_state == 0)
{
/* Toggle LED state */
// 切换LED状态:true变false,false变true
led_state = !led_state;
if (led_state)
{
GPIO_PA15_Set(); // Turn LED on - 点亮LED
}
else
{
GPIO_PA15_Clear(); // Turn LED off - 熄灭LED
} }
/* Update previous touch state */
// 更新上一次的状态,为下一次循环做准备
previous_touch_state = current_touch_state;
}
}
/* Execution should not come here during normal operation */
// 正常运行不会到这里,因为上面是无限循环
return (EXIT_FAILURE);
}
/*******************************************************************************
End of File
*/
5.3 关键代码逐行解释
| 代码行 | 作用说明 |
|--------|----------|
| `#define TOUCH_SENSOR 0` | 定义使用第一个触摸传感器,项目只配置了一个触摸按键 |
| `uint8_t previous_touch_state = 0;` | 保存上一次循环的触摸状态,初始为无触摸 |
| `uint8_t current_touch_state = 0;` | 保存本次测量的触摸状态 |
| `bool led_state = false;` | 保存LED当前状态,初始为关闭 |
| `SYS_Initialize(NULL);` | 系统初始化,MHC生成,初始化所有外设和触摸库 |
| `GPIO_PA15_Clear();` | LED初始化为关闭状态 |
| `while (true)` | 无限主循环 |
| `touch_process();` | 调用触摸库处理函数,必须在主循环中持续调用 |
| `if (measurement_done_touch == 1u)` | 等待一次触摸测量完成 |
| `measurement_done_touch = 0u;` | 清除完成标志,准备下一次测量 |
| `current_touch_state = get_sensor_state(TOUCH_SENSOR) & KEY_TOUCHED_MASK;` | 获取触摸状态,KEY_TOUCHED_MASK是触摸检测位掩码 |
| `if (current_touch_state != 0 && previous_touch_state == 0)` | 上升沿检测:刚按下时才触发 |
| `led_state = !led_state;` | 翻转LED状态 |
| `GPIO_PA15_Set()` / `GPIO_PA15_Clear()` | 根据状态设置LED输出 |
| `previous_touch_state = current_touch_state;` | 更新状态,供下一次比较 |
六、功能测试
6.1 编译下载
代码编译成功,通过板载EDBG调试器下载到开发板中。

6.2 功能测试结果
刚上电:LED灭

触摸后:LED亮

再次触摸:LED灭

七、遇到的问题与解决方法
问题1:触摸状态检测不正确
现象:代码能编译运行,但触摸后LED没有反应。
原因分析:一开始我误以为触摸状态位在bit 0,直接用 `& 0x01` 判断,但实际上Microchip QTouch库定义的触摸检测位是 `KEY_TOUCHED_MASK = 0x80`,掩码不对导致一直检测不到触摸。
解决方法:查看官方示例代码 `touch_example.c`,发现正确的掩码是 `KEY_TOUCHED_MASK`,修改后问题解决。
问题2:中文注释乱码
现象:MPLAB X IDE中中文注释显示为乱码。
原因分析:源文件保存为UTF-8编码,但MPLAB X在Windows默认使用GBK编码显示。
解决方法:将注释改为英文,或者设置IDE的文件编码为UTF-8,避免编码问题。
问题3:项目结构理解不清楚
现象:一开始不清楚为什么有两个项目(project和project_secure),不知道该在哪里写代码。
原因分析:PIC32CM支持TrustZone,所以MPLAB X自动生成了安全和非安全两个项目。触摸初始化默认在安全项目。
解决方法:对于简单应用,直接在安全项目中实现完整功能,删除跳转到非安全端的代码,这样结构更简单,调试更方便。
八、总结与心得体会
8.1 项目完成情况
本次项目圆满完成了Funpack5-2活动任务1的基础题目要求:
- 正确初始化触摸通道
- 实现单次触摸切换LED状态
- 控制逻辑清晰,没有误触发
- 功能稳定可靠
8.2 学习收获
通过本次项目,我学到了:
- Microchip触摸技术:了解了QTouch触摸库的使用方法,PTC触摸控制器的工作原理
- TrustZone架构:理解了ARM TrustZone安全架构的基本概念,安全域和非安全域的划分
- MPLAB X开发流程:掌握了使用MHC图形化配置工具快速配置外设和功能
- 按键检测算法:上升沿检测方法可以有效避免按键抖动和重复触发
8.3 对产品的评价
Microchip EV41C56A开发板是一款非常不错的低功耗触摸开发平台:
- 触摸库配置简单,开箱即用
- 触摸检测稳定,抗干扰能力强
- Cortex-M23内核+TrustZone适合物联网安全应用
- 板载调试器,开发方便
感谢硬禾科技联合DigiKey举办的这次活动,让我有机会学习和体验Microchip的触摸技术!