1. 动画基础概念:帧率、刷新率、屏幕撕裂与垂直同步

做嵌入式GUI开发,说白了就是在跟「时间」打交道。你写的每一帧画面,最终都要在屏幕上呈现给用户。如果时间没卡好,画面就会卡顿、撕裂,用户一眼就能看出来。这一章,我们先把这些基础概念掰扯清楚。

1.1 帧率(FPS)—— 你的程序能跑多快

FPS,全称 Frames Per Second,每秒能渲染多少帧。我习惯把它叫做「程序的心跳」。你写了一个动画,每秒钟能画出 30 张图,那 FPS 就是 30;能画出 60 张,就是 60。

但这里有个坑:FPS 高不代表画面就流畅。为什么?因为屏幕还有个刷新率在等着你。

我的经验: 在低端 MCU 上做 GUI,我经常把 FPS 锁在 30。不是跑不到 60,而是跑 60 时 CPU 占用率飙到 90%,其他任务全被饿死了。你得在流畅度和系统负载之间找平衡。

1.2 刷新率(Hz)—— 屏幕的固定节奏

刷新率是屏幕硬件决定的。常见的 60Hz 意味着屏幕每秒刷新 60 次,每次刷新间隔约 16.67ms。这个时间是固定的,你改不了。

你想想看,如果你的程序 FPS 是 60,屏幕刷新率也是 60,那理论上每一帧都能完美对齐。但现实没这么理想——FPS 经常波动,而刷新率纹丝不动。这就引出了下一个问题。

参数 帧率 (FPS) 刷新率 (Hz)
决定者 软件(你的代码 + GPU/CPU) 硬件(屏幕面板 + 驱动 IC)
是否固定 波动,随场景复杂度变化 固定,除非你主动切换
典型值 30、60、120 60、90、120、144
影响 决定动画的「流畅感」 决定画面的「闪烁感」

1.3 屏幕撕裂(Tearing)—— 不同步的后果

屏幕撕裂长什么样?就是画面中间出现一条错位的「断层」,上半张图和下半张图对不上。我在做智能手表项目时第一次遇到这问题,当时还以为是屏坏了。

原因很简单:屏幕正在刷新第 N 行像素时,你的程序把显存里的内容换成了下一帧。结果屏幕上半截是旧帧,下半截是新帧,中间就裂开了。

核心矛盾: 帧率与刷新率不同步。程序随时可以写显存,但屏幕只在固定时间点读显存。两者抢同一个缓冲区,必然打架。

1.4 垂直同步(V-Sync)—— 让两队对齐

V-Sync 就是解决这个打架问题的。它的做法很简单:让程序等屏幕把当前帧显示完,再开始画下一帧。具体来说,屏幕每扫完一帧,会发一个「垂直消隐」信号(VBlank)。程序收到这个信号,才允许更新显存。

这样做的好处是:永远不会撕裂。坏处是:如果程序画一帧的时间超过了 16.67ms(60Hz 下),那下一帧就得等两个 VBlank,FPS 直接掉到 30。这就是为什么有些游戏开了 V-Sync 反而卡。

// 伪代码:V-Sync 的典型实现
while (1) {
    wait_for_vblank();      // 等待垂直消隐信号
    swap_buffers();         // 交换前后缓冲区
    render_next_frame();    // 开始渲染下一帧
}
我曾经踩过的坑: 在 STM32 上做 GUI,我直接用轮询方式等 VBlank,结果 CPU 空转浪费了大量功耗。后来改成中断触发,功耗降了 30%。嵌入式系统里,能等中断就别轮询。

1.5 四者的关系——一张图说清楚

下面这张图展示了帧率、刷新率、屏幕撕裂和 V-Sync 之间的逻辑关系。你可以把它当作本章的知识地图。

动画基础概念关系图 动画基础概念关系图 帧率 (FPS) 刷新率 (Hz) 屏幕撕裂 (Tearing) 垂直同步 (V-Sync) 不同步导致 解决方案 限制写入时机 等待 VBlank 关键理解: 1. FPS 和 Hz 是两套独立时钟,一个由软件决定,一个由硬件决定。 2. 两者不同步 → 屏幕撕裂。 3. V-Sync 通过等待 VBlank 强制同步,消除撕裂,但可能降低 FPS。

1.6 嵌入式环境下的特殊考量

在 PC 上,V-Sync 通常由显卡驱动和操作系统管理。但在嵌入式系统里,这些全得你自己写。我做过几个项目,总结出三条经验:

  • 双缓冲是标配: 一个缓冲区给屏幕读,一个给程序写。VBlank 到来时交换。没有双缓冲,V-Sync 基本没法用。
  • 小心 LTDC 控制器: 很多 MCU 内置的 LTDC(LCD-TFT 显示控制器)支持硬件 VBlank 中断。记得使能它,别自己用定时器模拟。
  • 帧率不要硬追刷新率: 如果屏幕是 60Hz,你的 FPS 稳定在 30 也比在 40~60 之间剧烈波动体验好。人眼对「卡顿」比「低帧率」更敏感。
一个小技巧: 调试时我习惯在屏幕角落显示实时 FPS 和 VBlank 计数。如果两个数字长期不成整数倍关系,说明同步有问题,该查代码了。

1.7 本章小结

帧率是你的程序能跑多快,刷新率是屏幕能刷多快。两者步调不一致,就会撕裂。V-Sync 通过等 VBlank 信号来对齐它们,代价是可能掉帧。在嵌入式环境里,你得自己实现这套机制,而且要考虑功耗和 CPU 占用。