4. 中断与轮询模式:触摸响应的两种路径
触摸层的响应方式,说白了就两条路:中断和轮询。很多刚接触 TouchGFX 的朋友会纠结选哪个,其实没那么玄乎。我做了这么多年嵌入式,两种模式都踩过坑,今天就把我的经验摊开来聊聊。
核心观点:中断模式适合“等事件”,轮询模式适合“定时查”。选哪个,取决于你的系统负载和实时性要求。
4.1 中断模式下的触摸响应
中断模式,就是让触摸芯片在检测到触摸动作时,主动拉一个引脚通知 MCU。MCU 暂停当前任务,跳去处理触摸事件。这种方式响应快,CPU 利用率高——没事的时候 CPU 可以睡大觉。
我在一个智能家居面板项目里用过中断模式。当时用的是 FT5x06 触摸芯片,中断引脚接到 MCU 的 EXTI 上。代码结构大概是这样的:
// 中断服务函数
void EXTI0_IRQHandler(void)
{
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET)
{
// 清除中断标志
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
// 通知 TouchGFX 有触摸事件
touchgfx::HAL::getInstance()->touchController()->sampleTouch(touchX, touchY);
// 设置触摸标志,让主循环处理
touch_flag = 1;
}
}
这里有个细节:不要在中断里做太多事。我见过有人直接在 ISR 里跑完整的触摸处理流程,结果系统响应变慢,还偶尔死机。正确的做法是:中断里只做标记,主循环里再处理。
我的习惯:中断服务函数里只做三件事——清标志、读坐标、设通知位。剩下的交给 TouchGFX 的 sampleTouch() 去调度。
中断模式的好处很明显:
- 响应快:触摸到响应,延迟通常在微秒级
- 省电:没事的时候 CPU 可以进低功耗模式
- 资源占用低:不需要定时器一直跑
但也不是没缺点。我记得有个项目,触摸中断和 SPI 通信中断冲突了,导致触摸数据读出来全是错的。排查了两天才发现是中断优先级没配好。
避坑指南:我曾经在一个多中断系统里,把触摸中断优先级设得太高,结果 DMA 传输一直被抢占,屏幕刷新率掉了一半。中断优先级一定要合理分配,别让触摸“一手遮天”。
4.2 轮询模式的适用场景
轮询模式就简单了——主循环里定时去读触摸芯片的寄存器,看看有没有触摸事件。不需要中断引脚,也不需要配置 EXTI。代码写起来更直接:
// 主循环中的轮询
while (1)
{
// 每 10ms 轮询一次触摸状态
if (HAL_GetTick() - last_touch_poll >= 10)
{
last_touch_poll = HAL_GetTick();
// 读取触摸坐标
touchController.sampleTouch(touchX, touchY);
// 如果有触摸,处理事件
if (touchX >= 0 && touchY >= 0)
{
// 处理触摸事件
touchgfx::HAL::getInstance()->touchController()->flush();
}
}
// 其他任务...
}
轮询模式适合什么场景?我总结了几种:
- 触摸芯片不支持中断:有些便宜的电阻屏芯片,压根没有中断引脚
- 系统负载低:CPU 闲着也是闲着,轮询不增加负担
- 中断资源紧张:MCU 的 EXTI 引脚不够用,或者被其他外设占满了
- 调试阶段:我习惯先用轮询把功能调通,再切中断优化性能
你想想看,如果一个系统里已经有 5 个中断源在跑,再加一个触摸中断,优先级怎么排都是个头疼事。这时候轮询反而是更稳的选择。
我的建议:轮询周期别太短,也别太长。10ms 是个不错的起点——太快浪费 CPU,太慢用户能感觉到延迟。我一般用 5~15ms,具体看触摸芯片的采样速率。
4.3 两种模式的性能对比
光说理论不够,咱们直接上数据。我在同一个硬件平台上(STM32F429 + FT5x06,主频 180MHz)做了对比测试:
| 对比项 | 中断模式 | 轮询模式 |
|---|---|---|
| 触摸响应延迟 | 8~15 μs | 5~10 ms(取决于轮询周期) |
| CPU 占用率 | 几乎为 0(无触摸时) | 2%~5%(持续占用) |
| 功耗(无触摸) | 低(可进睡眠模式) | 中(需定时唤醒) |
| 代码复杂度 | 中(需配置中断优先级) | 低(简单循环) |
| 调试难度 | 高(中断冲突难排查) | 低(逻辑清晰) |
| 适用场景 | 高实时性、低功耗需求 | 资源紧张、调试阶段 |
从数据能看出来,中断模式在响应速度和功耗上完胜。但轮询模式在代码可维护性和调试便利性上更胜一筹。说白了,没有绝对的好坏,只有合不合适的场景。
我个人习惯是:量产项目用中断,原型验证用轮询。等产品稳定了,再花时间优化中断优先级和响应逻辑。
性能关键点:中断模式下,从触摸发生到 TouchGFX 收到事件,延迟主要来自三部分——硬件中断响应时间(~1μs)、I2C/SPI 读取时间(~5μs)、TouchGFX 内部处理时间(~2μs)。总延迟控制在 15μs 以内,人眼完全感觉不到。
4.4 中断与轮询的选择决策图
为了让你更直观地理解怎么选,我画了一张决策流程图。每次做新项目,我都会拿出来看一眼:
这张图我建议你截图保存。每次选型的时候拿出来对照一下,基本不会选错。
4.5 混合模式:取长补短
其实还有一种玩法——中断唤醒 + 轮询读取。什么意思呢?就是平时 CPU 睡大觉,触摸来了中断唤醒,然后主循环里轮询读取坐标。这样既省电,又避免了中断里做复杂操作。
我在一个智能手表项目里用过这种方案。触摸中断唤醒 MCU,然后在一个 5ms 的定时器里轮询读取坐标,持续 50ms 后如果没有新触摸,再让 CPU 睡回去。效果很好,待机电流从 2mA 降到了 0.3mA。
小技巧:混合模式下,中断里只设一个标志位,主循环检测到标志后启动轮询定时器。定时器超时后自动关闭,CPU 重新进入睡眠。这样既保证了响应速度,又控制了功耗。