-
lv_timer_handler()
是 LVGL 的“心脏”:这个函数会依次做以下事情:-
处理定时器(如动画、延迟回调)。
-
读取输入设备(如触摸屏、按键的状态)。
-
刷新脏区域(仅重绘屏幕上发生变化的区域)。
-
执行用户注册的回调函数(如按钮点击事件)。
-
-
开发者需要手动调用它:通常在一个
while(1)
循环或 FreeRTOS 任务中定期调用,例如每 5~50ms 调用一次。例如:c
复制
while (1) {lv_timer_handler(); // 驱动 LVGL 的核心逻辑vTaskDelay(5); // FreeRTOS 中延时 5ms }
-
如果没有调用
lv_timer_handler()
:LVGL 的定时器不会触发,输入设备状态不会被读取,UI 也不会更新,导致“死机”。
2. 为什么 LVGL 不依赖硬件中断?
-
跨平台兼容性:LVGL 需要支持从低端单片机到 Linux 的各种平台,硬件中断机制差异较大,轮询更通用。
-
可控性:轮询允许开发者自由控制 LVGL 的调用频率,避免中断抢占导致实时系统的不确定性(尤其是在 FreeRTOS 中)。
-
资源效率:中断处理需要上下文切换,频繁的中断可能占用过多 CPU 资源,而轮询可以通过调整调用间隔平衡性能与功耗。
3. LVGL 如何与 FreeRTOS 协同工作?
-
典型场景:在 FreeRTOS 中创建一个专用任务(如
lvgl_task
),负责定期调用lv_timer_handler()
。例如:c
复制
void lvgl_task(void *pvParameters) {while (1) {lv_timer_handler(); // 驱动 LVGLvTaskDelay(pdMS_TO_TICKS(5)); // 5ms 周期} }
-
输入设备的读取:触摸屏或按键的状态通常也需要通过轮询或中断获取,但 LVGL 不强制要求使用中断。例如:
-
轮询方式:在
lv_timer_handler()
中调用lv_indev_read()
。 -
中断方式:在触摸屏中断中标记事件,然后在
lv_timer_handler()
中处理。
-
因为需要用到systicks作为lvgl时基函数的基本盘,所以你freertos配置systicks时最好为1ms也就是时间片长短哪里的配置综合结果要为每1ms systicks触发一次
4. LVGL 的优化:减少轮询开销
-
脏区域机制(Dirty Area):LVGL 只会重绘屏幕上发生变化的区域,而不是全屏刷新,大幅降低 CPU 负载。
-
事件驱动回调:用户可以为 UI 元素(如按钮)注册回调函数,仅在事件发生时触发逻辑,避免不必要的轮询计算。
-
定时器精度控制:通过调整
lv_timer_handler()
的调用频率,平衡响应速度和 CPU 占用率。
5. 对比 FreeRTOS 的任务调度
-
FreeRTOS 的任务:基于优先级抢占,依赖调度器(如 PendSV 中断)切换任务。
-
LVGL 的轮询:依赖开发者主动调用
lv_timer_handler()
,本质上是一个“协作式”任务。 -
关键区别:LVGL 不直接依赖硬件中断,而是通过任务调度间接实现“伪实时性”。
6. 你的推测是否正确?
-
正确部分:
-
LVGL 确实依赖轮询(
lv_timer_handler()
),而非硬件中断。 -
不调用
lv_timer_handler()
会导致 LVGL 无法工作。
-
-
需要补充的细节:
-
LVGL 的轮询是协作式的,需要开发者将
lv_timer_handler()
嵌入到主循环或任务中。 -
FreeRTOS 的任务调度和 LVGL 的轮询是互补的,前者管理多任务,后者管理 UI 逻辑。
-
7. 实际项目中的建议
-
调用频率:根据 UI 复杂度调整
lv_timer_handler()
的调用间隔(通常 5~50ms)。 -
任务优先级:在 FreeRTOS 中,为 LVGL 任务分配中低优先级,避免阻塞关键任务。
-
输入设备优化:如果使用触摸屏,可以在硬件中断中标记触摸事件,然后在
lv_timer_handler()
中批量处理,减少响应延迟。
1. LVGL 的定时器机制
-
LVGL 内部有一个定时器系统,
lv_timer_handler()
是这个系统的核心函数。它负责处理所有与时间相关的任务,比如动画、屏幕刷新、输入设备的状态检测等。 -
lv_timer_handler()
函数必须定期调用,否则 LVGL 的定时器系统将无法正常工作,导致动画停止、输入设备无响应等问题。这是因为 LVGL 的定时器系统是基于轮询的,而不是基于中断的。 -
在 FreeRTOS 中,你可以在一个任务中定期调用
lv_timer_handler()
,比如每隔几毫秒调用一次。这个任务可以是一个低优先级的任务,确保它不会影响其他高优先级任务的执行。
2. LVGL 的输入设备处理
-
LVGL 通过
lv_indev_read()
函数来读取输入设备(如触摸屏、按键等)的状态。这个函数通常会在lv_timer_handler()
中被调用。 -
“持续监测触摸屏有没有被按下”实际上是通过定期调用
lv_indev_read()
来实现的。LVGL 并不会像 FreeRTOS 的任务调度那样实时监测输入设备,而是通过轮询的方式来获取输入设备的状态。 -
当
lv_timer_handler()
被调用时,它会检查输入设备的状态,并根据这些状态更新 UI。例如,如果检测到触摸屏被按下,LVGL 会更新相应的 UI 元素(如按钮的状态)。
3. LVGL 与 FreeRTOS 的协同工作
-
FreeRTOS 的任务调度是基于优先级的,高优先级的任务会抢占低优先级的任务。LVGL 的
lv_timer_handler()
通常在一个低优先级的任务中运行,确保它不会影响其他高优先级任务的执行。 -
你提到的“类似 PendSV 的机制”在 LVGL 中并不存在。LVGL 的定时器系统和输入设备处理是基于轮询的,而不是基于中断的。PendSV 是 FreeRTOS 用于任务切换的中断,而 LVGL 的定时器系统是通过定期调用
lv_timer_handler()
来实现的。
4. LVGL 的 UI 更新机制
-
当你添加 UI 部件(如按钮、标签等)时,LVGL 会将这些部件添加到显示列表中。
lv_timer_handler()
会定期检查这些部件的状态,并根据需要更新显示。 -
如果触摸屏被按下,LVGL 会检测到这个事件,并更新相应的 UI 部件(如改变按钮的颜色、触发回调函数等)。这些更新操作通常是在
lv_timer_handler()
中完成的。
5. 总结
-
LVGL 的运行机制是基于轮询的,而不是基于中断的。它通过定期调用
lv_timer_handler()
来处理定时器、输入设备和 UI 更新。 -
FreeRTOS 的任务调度机制与 LVGL 的定时器系统可以协同工作。你可以在 FreeRTOS 的一个任务中定期调用
lv_timer_handler()
,确保 LVGL 的正常运行。 -
LVGL 并不会像 FreeRTOS 的任务调度那样实时监测输入设备,而是通过轮询的方式来获取输入设备的状态,并在
lv_timer_handler()
中处理这些状态。