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 中断与轮询的选择决策图

为了让你更直观地理解怎么选,我画了一张决策流程图。每次做新项目,我都会拿出来看一眼:

触摸模式选择决策流程 开始选择触摸模式 触摸芯片支持中断引脚? (查看数据手册 GPIO 功能) 是 MCU 中断资源充足? (EXTI 引脚未被占用) 是 有低功耗要求? (电池供电 / 待机功耗 < 1mA) 是 推荐:中断模式 响应快 · 功耗低 · 配置稍复杂 否 否 否 推荐:轮询模式 简单可靠 · 调试方便 决策要点 • 中断模式:适合量产、低功耗 • 轮询模式:适合原型、调试 • 混合模式:中断唤醒 + 轮询读取 注:如果中断资源紧张但有低功耗要求,可考虑“中断唤醒 + 轮询读取”的混合方案

这张图我建议你截图保存。每次选型的时候拿出来对照一下,基本不会选错。

4.5 混合模式:取长补短

其实还有一种玩法——中断唤醒 + 轮询读取。什么意思呢?就是平时 CPU 睡大觉,触摸来了中断唤醒,然后主循环里轮询读取坐标。这样既省电,又避免了中断里做复杂操作。

我在一个智能手表项目里用过这种方案。触摸中断唤醒 MCU,然后在一个 5ms 的定时器里轮询读取坐标,持续 50ms 后如果没有新触摸,再让 CPU 睡回去。效果很好,待机电流从 2mA 降到了 0.3mA。

小技巧:混合模式下,中断里只设一个标志位,主循环检测到标志后启动轮询定时器。定时器超时后自动关闭,CPU 重新进入睡眠。这样既保证了响应速度,又控制了功耗。