文章目錄
- 🧠 一句話總結 LVGL 的運行核心:
- 🔁 1. `while(1)` 主循環中的 `lv_task_handler()`
- ?? 2. `lv_timer_handler()` 定時器調度核心
- ? 并發控制
- ? 關鍵行為流程:
- 🌀 任務執行邏輯:
- 🧮 計算下一次調用間隔
- 📊 3. 額外性能監控與優化
- 🎯 總結一張圖(邏輯關系)
- 🧩 你需要做的最關鍵一件事
- ? 總結重點
LVGL 的運行核心機制其實就圍繞兩個關鍵詞展開:定時器輪詢(Timer Loop)+ 任務處理器(Task Handler)。你貼的這段代碼正是 LVGL 運行機制的心臟,下面我會從宏觀和細節兩個層面幫你理解這套機制的運行流程。
🧠 一句話總結 LVGL 的運行核心:
LVGL 通過定時器輪詢機制(
lv_timer_handler
)周期性檢查并執行任務(動畫、事件、刷新等),由主循環中持續調用lv_task_handler()
驅動系統更新。
🔁 1. while(1)
主循環中的 lv_task_handler()
while(1) {lv_task_handler();usleep(5000); // 每 5ms 調用一次
}
- 這是你在主線程、RTOS 任務或定時器中 周期性調用 的函數;
- 實際內部會調用
lv_timer_handler()
,這是 LVGL 所有內部“定時行為”的核心; - 例:刷新控件、執行動畫、檢測事件、處理輸入設備等,都是靠這里觸發。
?? 2. lv_timer_handler()
定時器調度核心
這是 LVGL 的任務調度中心,其關鍵職責如下:
? 并發控制
if(state_p->already_running) return 1;
防止多線程或中斷中重復進入,保護調度流程。
? 關鍵行為流程:
lv_timer_t * timer_active = lv_ll_get_head(timer_head);
- LVGL 內部的“任務”是以
lv_timer_t
為單位組織的; - 每一個
lv_timer_t
都有周期(例如 30ms 執行一次); - 所有
timer
被鏈接在一個鏈表中,調度器依次遍歷并執行;
🌀 任務執行邏輯:
if(lv_timer_exec(timer_active)) {if(state_p->timer_created || state_p->timer_deleted) {break;}
}
- 每次調度,調用
lv_timer_exec()
試圖執行任務; - 如果任務內部創建或刪除了其他
timer
,則會中斷本次遍歷,從頭再來(保證鏈表安全);
🧮 計算下一次調用間隔
uint32_t delay = lv_timer_time_remaining(next);
- 執行完任務后,計算距離下一次要執行的任務的最小延遲;
- 這個值可用于指導下一輪
lv_task_handler()
的調用周期優化(例如設置精確定時器)。
📊 3. 額外性能監控與優化
state_p->idle_last = (state_p->busy_time * 100) / idle_period_time;
- LVGL 會統計任務執行耗時,判斷 CPU 占用率;
- 可用于分析系統是否卡頓,或優化任務調度頻率;
🎯 總結一張圖(邏輯關系)
主循環/RTOS任務↓
lv_task_handler()↓
lv_timer_handler()↓
遍歷 lv_timer 鏈表↓
執行注冊任務(動畫、屏幕刷新、事件分發等)↓
計算下次執行時間 & 性能分析
🧩 你需要做的最關鍵一件事
在你的系統中,確保 lv_task_handler()
每隔 5~10ms 被調用一次,即可激活 LVGL 的整個圖形與事件系統。
當然可以,以下是為 lv_timer_handler()
添加的詳細中文注釋版,注釋盡量保留原有邏輯結構,方便你后續閱讀和調試:
// LVGL 的定時器調度主函數,每次被調用會遍歷所有注冊的定時器并執行到期的任務
LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void)
{LV_TRACE_TIMER("begin");lv_timer_state_t * state_p = &state;// 避免定時器調度函數被重復進入(多線程或中斷中可能會并發調用)if(state_p->already_running) {LV_TRACE_TIMER("already running, concurrent calls are not allow, returning");return 1;}state_p->already_running = true;// 如果定時器已被暫停,直接返回if(state_p->lv_timer_run == false) {state_p->already_running = false; // 釋放“互斥鎖”return 1;}LV_PROFILER_BEGIN;lv_lock(); // 進入臨界區,保護鏈表等資源不被同時訪問// 獲取當前時間(單位 ms)uint32_t handler_start = lv_tick_get();// 檢查是否調用了 lv_tick_inc()(用于更新系統 tick)if(handler_start == 0) {state.run_cnt++;if(state.run_cnt > 100) {state.run_cnt = 0;LV_LOG_WARN("It seems lv_tick_inc() is not called.");}}/*************** 開始遍歷并執行定時器任務 ***************/lv_timer_t * next;lv_timer_t * timer_active;lv_ll_t * timer_head = timer_ll_p; // 定時器鏈表頭指針do {// 每輪遍歷前先清空“狀態標志”state_p->timer_deleted = false;state_p->timer_created = false;// 獲取第一個定時器timer_active = lv_ll_get_head(timer_head);while(timer_active) {// 提前獲取下一個指針(因為本 timer 執行后可能會被刪除)next = lv_ll_get_next(timer_head, timer_active);// 如果當前定時器已經到期,則執行回調函數if(lv_timer_exec(timer_active)) {// 如果執行期間創建/刪除了定時器,鏈表結構可能被破壞,必須重新從頭遍歷if(state_p->timer_created || state_p->timer_deleted) {LV_TRACE_TIMER("Start from the first timer again because a timer was created or deleted");break;}}// 進入下一個定時器timer_active = next;}} while(timer_active); // 如果因鏈表被修改跳出,則重新遍歷/*************** 計算下次定時器觸發時間 ***************/uint32_t time_until_next = LV_NO_TIMER_READY; // 默認無任務準備next = lv_ll_get_head(timer_head);while(next) {if(!next->paused) {// 獲取該定時器距離下一次觸發還需等待的時間uint32_t delay = lv_timer_time_remaining(next);if(delay < time_until_next)time_until_next = delay; // 保留最短時間}next = lv_ll_get_next(timer_head, next);}/*************** 統計“空閑率”用于性能分析 ***************/state_p->busy_time += lv_tick_elaps(handler_start); // 本輪花費時間uint32_t idle_period_time = lv_tick_elaps(state_p->idle_period_start);if(idle_period_time >= IDLE_MEAS_PERIOD) {// 計算過去一段時間內的 CPU 空閑率(100% - 忙碌率)state_p->idle_last = (state_p->busy_time * 100) / idle_period_time;state_p->idle_last = state_p->idle_last > 100 ? 0 : 100 - state_p->idle_last;// 重置統計值state_p->busy_time = 0;state_p->idle_period_start = lv_tick_get();}// 保存本次計算的“下次觸發間隔”state_p->timer_time_until_next = time_until_next;state_p->already_running = false; // 解鎖,允許下次進入LV_TRACE_TIMER("finished (%" LV_PRIu32 " ms until the next timer call)", time_until_next);lv_unlock(); // 退出臨界區LV_PROFILER_END;return time_until_next; // 返回最短等待時間,供外部調度參考
}
? 總結重點
-
每次調用
lv_timer_handler()
:- 會遍歷所有活躍的定時器;
- 執行到期的任務;
- 動態應對中途創建/刪除定時器的情況;
- 返回下次最早觸發的延時時間。
-
所有動畫、控件刷新、事件分發等操作,最終都是通過定時器機制驅動。