引言
LVGL是一個跨平臺、輕量級、易於移植的圖形庫。也因其支援大量特性和其易於裁剪,配置開關眾多,且版本升級較快,不同版本之間存在一定的差異性,相關的使用教程有一定的滯後性,由於缺少最新版本的中文教程,加上大量的教程中未註明對應的版本,初始接觸的開發者往往容易中招,花費大量時間爬坑,本文特對自己的使用經驗進行記錄和總結,以期對初始接觸LVGL的開發者有所幫助。
簡介
什麼是Lvgl?LVGL(輕巧而多功能的圖形庫)是一個免費的開放原始碼圖形庫,它提供建立具有易於使用的圖形元素,精美的視覺效果和低記憶體佔用的嵌入式GUI所需的一切。
主要特性
l 功能強大的構建塊,例如按鈕,圖表,列表,滑塊,影像等。
l 帶有動畫,抗鋸齒,不透明,平滑滾動的高階圖形
l 各種輸入裝置,例如觸控板,滑鼠,鍵盤,編碼器等
l 支援UTF-8編碼的多語言
l 多顯示器支援,如TFT,單色顯示器
l 完全可定製的圖形元素
l 獨立於任何微控制器或顯示器使用的硬體
l 可擴充套件以使用很少的記憶體(64 kB快閃記憶體,16 kB RAM)進行操作
l 作業系統,支援外部儲存器和GPU,但不是必需的
l 單幀緩衝區操作,即使具有高階圖形效果
l 用C語言編寫,以實現最大的相容性(與C ++相容)
l 模擬器可在沒有嵌入式硬體的PC上進行嵌入式GUI設計
l 可移植到MicroPython
l 可快速上手的教程、示例、主題
l 豐富的文件教程
l 在MIT許可下免費和開源
LVGL硬體要求
- 16、32或64位微控制器或處理器
- 最低 16 MHz 時脈頻率
- Flash/ROM::對於非常重要的元件要求 >64 kB(建議 > 180 kB)
- RAM
- 靜態 RAM 使用量:~2 kB,取決於所使用的功能和物件型別
- 堆疊: > 2kB(建議 > 8 kB)
- 動態資料(堆):> 2 KB(如果使用多個物件,則建議 > 16 kB)。由 lv_conf.h 中的 LV_MEM_SIZE 宏進行設定。
- 顯示緩衝區:> “水平解析度”畫素(建議 > 10× “水平解析度” )
- MCU 或外部顯示控制器中的一幀緩衝區
- C99或更高版本的編譯器
- 具備基本的C(或C ++)知識:指標,結構,回撥...
請注意,記憶體使用情況可能會因具體的體系結構、編譯器和構建選項而異。
官方網址
LVGL - Light and Versatile Embedded Graphics Library
原始碼地址 https://github.com/lvgl/lvgl
- lvgl官方文件網站(https://docs.lvgl.io)
- lvgl官方部落格部落格站點(https://blog.lvgl.io)
- sim線上模擬器網站(https://sim.lvgl.io)
部分中文資料網址
歡迎閱讀百問網LVGL中文開發手冊! — 百問網LVGL中文教程文件 文件 (100ask.net)
環境搭建
本文主要針對在windows10下,使用visual stdio開發環境編譯執行模組器對LVGL8.3開發測試的一些配置使用進行介紹。
VS2019或VS022均可,Visual Stdio和Git工具的安裝使用,在此不做介紹。
Visual Studio simulator模擬器為開源專案,原始碼地址如下:
https://github.com/lvgl/lv_port_win_visual_studio
模擬器原始碼專案下載
模擬器專案原始碼內部包含了引用特定版本程式碼庫模組,透過檔案下載方式下載,會存在引用模組為空的問題。
Github站點的英文說明文件中介紹了推薦的下載方式,採用git下載,但與我們通常下載單個原始碼庫有所不同。
此儲存庫包含其他必要的 LVGL 軟體儲存庫作為 git 子模組。這些子模組不會使用正常的 git clone 命令拉入,它們將被需要。有幾種技術可以拉入子模組。
此命令將在單個步驟中克隆lv_sim_visual_studio儲存庫和所有子模組。
git clone --recurse-submodules https://github.com/lvgl/
lv_sim_visual_studio.git
眾所周知,國內的網路環境,訪問github比較抽風,這種方式,通常會失敗。
因此,推薦使用下面的方式下載
git clone https://github.com/lvgl/lv_sim_visual_studio.git
cd lv_sim_visual_studio
git submodule update --init –recursive
先單獨下載模擬器主專案,再切換到模擬器專案目錄,使用模組拉取命令下載,這樣,即使用失敗了,可以透過反覆嘗試,可以將模組程式碼拉取回來。
模擬器使用
模組器專案程式碼成功拉取後,使用VS2019或VS2022成功開啟即可執行。
模擬器專案中,lvgl的配置檔案中,大部分可用宏已預設開啟,這個與MCU專案下配置模板中的有所不同,畢竟電腦上模擬器可以有充足的硬體資源可供分配。
lv_conf.h 中的LV_MEM_SIZE宏應為 128KB 或更大,因為在使用 64 位模擬器時可能會遇到記憶體不足問題。 注意:在此專案中,大小設定為 1024KB。 使用者需要檢查在Visual Studio中選擇的目標,因為模擬器專案支援ARM64,Visual Studio會因為字母順序在第一時間選擇ARM64。
自帶例程使用
LVGL.Simulator.cpp檔案中,main函式內,預設使用的lv_demo_widgets()演示例程,其後有各類其他演示例程,只需註釋掉lv_demo_widgets()演示例程呼叫,分別啟用其他例程即可。
檔案系統使用
LVGL8.3版本的fsdrv目錄中,已自帶lv_fs_win32的檔案系統呼叫介面,在模擬器中使用無需另外移植lv_fs_port檔案,但需要在相關的配置檔案中進行相關宏定義開啟和相關配置。
Lv_conf.h配置檔案中,檔案系統宏預設已開啟
#define LV_USE_FS_WIN32 '/'
//#define LV_FS_WIN32_PATH "C:\\Users\\john\\"
檔案系統的訪問路徑配置為註釋狀態,可啟用該宏定義並指向所需訪問的磁碟檔案目錄,否則,檔案系統預設訪問專案的當前路徑。
修改配置如下
#define LV_USE_FS_WIN32 '/'
#define LV_FS_WIN32_PATH "D:\\SD"//此處可使用你自己的目錄
然後,開啟main函式中的如下程式碼
lv_fs_dir_t d; if (lv_fs_dir_open(&d, "/") == LV_FS_RES_OK) { char b[MAX_PATH]; memset(b, 0, MAX_PATH); while (lv_fs_dir_read(&d, b) == LV_FS_RES_OK) { printf("%s\n", b); } lv_fs_dir_close(&d); }
執行程式,檢視控制檯視窗,是不是應該出現指定目錄下的所有目錄和檔案呢?
然而,並沒有。
這一步也是LVGL預設模擬器專案比較坑的地方,沒有預設給出需要的配置項,這一處也折騰我跟蹤程式碼,分析了好久,說起來都是淚啊。
到底應該怎麼辦呢?
執行並跟蹤程式碼,在lv_init()中會呼叫lv_fs_win32_init(),在這個函式中,對檔案驅動器進行了初始化
static lv_fs_drv_t fs_drv; /*A driver descriptor*/ lv_fs_drv_init(&fs_drv); /*Set up fields...*/ fs_drv.letter = LV_FS_WIN32_LETTER; fs_drv.cache_size = LV_FS_WIN32_CACHE_SIZE;
定位檢視LV_FS_WIN32_LETTER宏,發現在lv_conf_internal.h中,
如果外部未定義,會被定義為'\0',其後註釋說明,需設定為設定驅動器可訪問的大寫字母。
如此處不進行定義,當lv_fs_dir_open函式中呼叫lv_fs_get_drv(letter)方法時,其內部的判斷 (*drv)->letter == letter會無法匹配而導致無法返回可用的驅動器物件。
我們可以修改lv_conf_internal.h檔案中(2035行)處的LV_FS_WIN32_LETTER宏定義,或者在lv_conf.h檔案中,在宏 LV_USE_FS_WIN32 的下面,增加一行如下定義即可
#define LV_FS_WIN32_LETTER '/'
再次執行模擬器,bingo,指定目標下的目錄和檔案,在控制檯中被列印輸出出來了
使用向量字型
模擬器專案中,預設已提供了向量字型示例,開啟註釋開關啟用,同時註釋掉後面的演示Demo呼叫即可。
// ---------------------------------- // my freetype application // ---------------------------------- ///*Init freetype library // *Cache max 64 faces and 1 size*/ lv_freetype_init(64, 1, 0); ///*Create a font*/ static lv_ft_info_t info; info.name = "./lvgl/src/extra/libs/freetype/arial.ttf"; info.weight = 36; info.style = FT_FONT_STYLE_NORMAL; lv_ft_font_init(&info); /*Create style with the new font*/ static lv_style_t style; lv_style_init(&style); lv_style_set_text_font(&style, info.font); /*Create a label with the new style*/ lv_obj_t* label = lv_label_create(lv_scr_act()); lv_obj_add_style(label, &style, 0); lv_label_set_text(label, "FreeType Arial Test");
預設向量字型例程是英文字型,我們要使用中文向量字型怎麼處理呢?
在我們之前建立的檔案系統目錄中,放置對應的中文字型
//info.name = "./lvgl/src/extra/libs/freetype/arial.ttf"; info.name = "D:/SD/TTF/simhei.ttf";
此處須使用完整路徑或相對路徑
lv_label_set_text(label, "This is 思源黑體!");
測試,中文顯示成功。
使用點陣字型
向量字型使用方便,但在資源緊張的MCU中使用,需要消耗一定的記憶體開銷和儲存開銷,至少需要增加200KB左右的Flash和16KB左右的記憶體開銷。
為了節約記憶體資源 ,在無需多種字號的情況下,我們通常選擇點陣字型。點陣字型可以透過專門的轉換工具軟體從向量字型檔提取。
我們使用裡飛網阿里兄提供的免費轉換軟體實現點陣字型庫的轉換。
字型轉換工具和用法,大家在裡飛網論壇自行查閱即可,如不需發貼,無需註冊。
生成點陣字型檔檔案的同時,會生成一個C檔案,將檔案新增到專案,將修改以下方法,增加在Windows系統下的文字字陣資料獲取方法實現。
static uint8_t __g_font_buf[512];//如bin檔案存在SPI FLASH可使用此buff static uint8_t* __user_font_getdata(int offset, int size) { //如字模儲存在SPI FLASH, SPIFLASH_Read(__g_font_buf,offset,size); //如字模已載入到SDRAM,直接返回偏移地址即可如:return (uint8_t*)(sdram_fontddr+offset); lv_fs_file_t file; lv_fs_res_t result; static uint32_t icount = 0; result = lv_fs_open(&file, "/Font/Bin/SourceHanSans_16.bin", LV_FS_MODE_RD); printf("lv_fs_open res:%d,count:%d\r\n", result, ++icount); if (result != LV_FS_RES_OK) return NULL; lv_fs_seek(&file, offset, LV_FS_SEEK_CUR); uint32_t len; lv_fs_read(&file, __g_font_buf, size, &len); lv_fs_close(&file); return __g_font_buf; }
注:此方法僅適用於windows系統中測試使用,如果MCU中使用,速度一定會十分感人^_^,因為lvgl獲取點陣字型的每一個位元組,都會呼叫一次這個函式。
大家可對此方法進行最佳化,如增加讀取快取處理,減少檔案訪問。如有好的實現,也請告訴我呵。
增加點陣字型測試程式碼:
void lv_showFont(void) { LV_FONT_DECLARE(SourceHanSans_16);//引入字型檔 lv_obj_t* zh_label = lv_label_create(lv_scr_act());//獲取預設螢幕 lv_obj_set_style_text_font(zh_label, &SourceHanSans_16, LV_STATE_DEFAULT);// 設定風格的字型 lv_label_set_text(zh_label, "你好,這是思源黑體!");//顯示文字 lv_obj_align(zh_label, LV_ALIGN_TOP_MID, 0, 0); lv_obj_t* label = lv_label_create(lv_scr_act());//獲取預設螢幕 lv_obj_set_style_text_font(label, &SourceHanSans_16, LV_STATE_DEFAULT);// 設定風格的字型 lv_label_set_text(label, "山不在高,有仙則名,水不在深,有龍則靈。");//顯示文字 lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); //lv_obj_t* style_txt = lv_label_create(lv_scr_act());//獲取預設螢幕 //lv_obj_set_style_text_font(style_txt, &SourceHanSans_16, LV_STATE_DEFAULT);// 設定風格的字型 //lv_label_set_text(style_txt, "\uF00C確定");//顯示文字 //lv_obj_align(style_txt, LV_ALIGN_BOTTOM_MID, 0, 0); }
執行測試程式碼,效果如下。
使用圖片檔案
我們通常希望能夠直接使用儲存在檔案系統中的圖片,最好是圖片無需預先經過專門的處理,這樣的話,圖片比較通用,也無需專門的軟體工具處理。
LVGL8.3已經準備好了常用的BMP、PNG、JPG格式影像解碼器。
考慮解碼的效能和速度,我們直接使用BMP點陣圖。
為了降低記憶體開銷和儲存開銷,我打算使用256色點陣圖,這樣的話,一張普通圖片,使用windows自帶的畫圖程式,可以直接轉存為256色點陣圖。
新增載入圖形物件程式碼,如下
void lv_showBmp(void) { lv_obj_t* bmp = lv_img_create(lv_scr_act()); if (bmp == NULL) { printf("[%s:%d] create bmp failed\n", __FUNCTION__, __LINE__); return; } char* bmp_path; #if LV_USE_FS_WIN32 bmp_path = "/Images/Lena_320_256.bmp"; #else bmp_path = "C:/Images/Lena_320_256.bmp"; #endif lv_img_set_src(bmp, bmp_path); // 設定圖片 //lv_img_set_zoom(bmp, 128); lv_obj_align(bmp, LV_ALIGN_CENTER, 0, 0); lv_obj_set_size(bmp, 160, 160); // 設定大小 }
此處載入圖片的路徑應設定成相對路徑,且需以’/’開頭,檔案系統處理函式中,會定位到配置的檔案目錄裡面,否則,會出現找不到檔案的情況。
為了節省資源 ,使用256色點陣圖,lv_conf.h中,顏色深度宏引數如下定義
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 8
實際測試,發現存在如上圖中的顏色顯示不正常問題。
如將色深改為32,#define LV_COLOR_DEPTH 32
使用24位真彩或32位真彩點陣圖,則一切正常,除了lvgl需要的記憶體大幅飆升(相對於資源緊缺的MCU來說)。
如果想使用16位色深的圖片,windows自帶的畫圖工具並不支援,需要專門的工具進行轉換,並且需將色深宏引數定義為16。
256色(8位)點陣圖為什麼不能正常顯示,本人目前也還未找到原因,可能是lvgl的bug,也可能是我開啟的姿勢不對,如有解決此問題的朋友,請不吝告知,十分感謝。