在Windows模擬器中使用LVGL8.3

2022-11-28 06:02:24

引言

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教學|極客筆記 (deepinout.com)

歡迎閱讀百問網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,也可能是我開啟的姿勢不對,如有解決此問題的朋友,請不吝告知,十分感謝。