1. LVGL簡(jiǎn)單介紹
關(guān)于LVGL的介紹,大家可以去它的官方文檔查看。下面關(guān)于LVGL的介紹均是引用自對(duì)官方文檔的翻譯。
LVGL,全稱是 Light and Versatile Graphics Library ,是一款免費(fèi)開(kāi)源的輕量多功能圖形庫(kù)。LVGL 提供創(chuàng)建嵌入式 GUI 所需的一切,該 GUI 具有易于使用的圖形元素、美觀的視覺(jué)效果和低內(nèi)存占用。
主要特性:
· 強(qiáng)大的構(gòu)建塊,如按鈕、圖表、列表、滑塊、圖像等。
· 具有動(dòng)畫、抗鋸齒、不透明度、平滑滾動(dòng)的高級(jí)圖形
· 各種輸入設(shè)備,如觸摸板、鼠標(biāo)、鍵盤、編碼器等
· UTF-8 編碼的多語(yǔ)言支持
· 多顯示器支持,即同時(shí)使用多個(gè)TFT、單色顯示器
· 具有類似 CSS 樣式的完全可定制的圖形元素
· 可擴(kuò)展:能夠使用很少的內(nèi)存(64 kB 閃存、16 kB RAM)進(jìn)行操作
· 支持操作系統(tǒng)、外部存儲(chǔ)器和 GPU,但不是必需的
· 即使具有高級(jí)圖形效果,也可進(jìn)行單幀緩沖區(qū)操作
· 用 C 編寫以實(shí)現(xiàn)最大兼容性(C++ 兼容)
· 無(wú)需嵌入式硬件即可在 PC 上啟動(dòng)嵌入式 GUI 設(shè)計(jì)的模擬器
· 綁定到 MicroPython
· 快速 GUI 設(shè)計(jì)的教程、示例、主題
· 文檔可在線獲取并以 PDF 形式提供
· 根據(jù) MIT 許可免費(fèi)且開(kāi)源
運(yùn)行的設(shè)備要求:
基本上,每個(gè)能夠驅(qū)動(dòng)顯示器的現(xiàn)代控制器都適合運(yùn)行 LVGL。最低要求是:
· 16、32 或 64 位微控制器或處理器
· 建議使用 > 16 MHz 時(shí)鐘速度
· 閃存/ROM:> 64 kB 用于非常重要的組件(建議> 180 kB)
· 內(nèi)存:
靜態(tài) RAM 使用量:~2 kB,具體取決于所使用的功能和對(duì)象類型堆棧:> 2kB(建議> 8 kB)動(dòng)態(tài)數(shù)據(jù)(堆):> 2 KB(如果使用多個(gè)對(duì)象,建議> 48 kB)。LV_MEM_SIZE通過(guò)在 中設(shè)置lv_conf.h。顯示緩沖區(qū):> “水平分辨率”像素(建議> 10 “水平分辨率” )MCU 或外部顯示控制器中的一個(gè)幀緩沖區(qū)
· C99 或更新版本的編譯器
2. LVGL學(xué)習(xí)資源
下面搜集了一些LVGL的學(xué)習(xí)資源。
1、LVGL官網(wǎng):
https://lvgl.io/
2、LVGL官網(wǎng)文檔教程:
https://docs.lvgl.io/master/
3、百問(wèn)網(wǎng)對(duì)LVGL官方文檔的翻譯:
https://lvgl.100ask.net/master/
4、LVGL Github倉(cāng)庫(kù):
https://github.com/lvgl/lvgl
5、lvgl基于Visual sudio 的PC模擬器
https://github.com/lvgl/lv_sim_visual_studio
6、百問(wèn)網(wǎng)基于LVGL的一個(gè)項(xiàng)目:
https://forums.100ask.net/t/topic/602
3. 移植前準(zhǔn)備
移植的硬件平臺(tái):
MCU:APM32F411
LCD驅(qū)動(dòng)芯片:ST7789V
觸摸IC:CST816T
本次移植是基于 RT-Thread 系統(tǒng)上運(yùn)行 LVGL 的,所以在移植前,我們需要準(zhǔn)備好可以正常運(yùn)行 RT-Thread 的Demo工程(可以到極海官網(wǎng)下載APM32F411的SDK)。
另外,還需準(zhǔn)備好可以正常運(yùn)行LCD的驅(qū)動(dòng)和觸摸IC的驅(qū)動(dòng)的代碼。
1、準(zhǔn)備一份可以運(yùn)行RT-Thread的Demo工程
2、下載LVGL_8.3源碼
到官方 Github 倉(cāng)庫(kù),然后選擇 LVGL_8.3 版本。
下載到的LVGL源碼,然后存放到工程目錄下的 middlewares 文件夾。
4. LVGL移植
4.1 移動(dòng)和修改移植的接口文件
(1)移植接口文件修改
下載了LVGL的源碼之后,我們把移植要使用到的接口文件,修改文件名后,放到工程目錄的另一個(gè)文件夾。
(2)移植配置文件修改
在LVGL源碼的根目錄下有一個(gè) lv_conf_template.h 頭文件,這個(gè)文件是 LVGL 庫(kù)的配置文件,可以修改該文件來(lái)設(shè)置庫(kù)的基本行為,禁用未使用的模塊和功能,調(diào)整編譯時(shí)緩沖區(qū)的大小等。
上面把LVGL移植接口和配置文件都復(fù)制到了工程的下面這個(gè)目錄:
4.2 Keil工程配置
(1)Keil工程添加文件
把LVGL的源碼導(dǎo)入到Keil工程下,其中 LVGL 源碼目錄下的 src 目錄的C文件可以全部導(dǎo)入Keil工程,然后再導(dǎo)入LVGL的移植接口文件。如下圖:
導(dǎo)入完成之后如下:
(2)修改工程頭文件路徑包含
(3)勾選C99模式
LVGL源碼的編譯需要C99模式的支持,不然會(huì)出現(xiàn)大量的報(bào)錯(cuò)。
4.3 LVGL修改源碼
(1)修改 startup_apm32f411.s 文件的棧大小
官方提供的啟動(dòng)文件的棧設(shè)置的比較小,我們需要改大一些。
(2)修改LVGL的配置文件 lvgl_conf.c
然后,下面是LVGL各個(gè)模塊的配置,可以根據(jù)自己的需要是否打開(kāi)還是關(guān)閉。
該文件還有色彩深度的配置,顯示屏寬高的配置等,需要根據(jù)自己的硬件進(jìn)行配置,不一一列舉了。
(3)修改LVGL顯示接口文件lv_port_disp.c
該文件就是LVGL的顯示接口文件,需要我們先準(zhǔn)備好LCD顯示的描點(diǎn)函數(shù)。該文件主要要修改的點(diǎn)有:
1、打開(kāi)顯示接口文件宏定義
2、修改lv_port_disp_init函數(shù)
對(duì)于lv_port_disp_init函數(shù),官方提供了3種寫緩存的方式及設(shè)置顯示分辨。我們可以選擇其中一種方式即可,修改后的函數(shù)如:
void lv_port_disp_init(void)
{
/*-------------------------
* Initialize your display
* -----------------------*/
disp_init();
/*-----------------------------
* Create a buffer for drawing
*----------------------------*/
/**
* LVGL requires a buffer where it internally draws the widgets.
* Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
* The buffer has to be greater than 1 display row
*
* There are 3 buffering configurations:
* 1. Create ONE buffer:
* LVGL will draw the display's content here and writes it to your display
*
* 2. Create TWO buffer:
* LVGL will draw the display's content to a buffer and writes it your display.
* You should use DMA to write the buffer's content to the display.
* It will enable LVGL to draw the next part of the screen to the other buffer while
* the data is being sent form the first buffer. It makes rendering and flushing parallel.
*
* 3. Double buffering
* Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
* This way LVGL will always provide the whole rendered screen in `flush_cb`
* and you only need to change the frame buffer's address.
*/
/* Example for 1) */
static lv_disp_draw_buf_t draw_buf_dsc_1;
static lv_color_t buf_1[MY_DISP_HOR_RES * DISP_BUFFER_LINES]; /*A buffer for 10 rows*/
lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * DISP_BUFFER_LINES); /*Initialize the display buffer*/
// /* Example for 2) */
// static lv_disp_draw_buf_t draw_buf_dsc_2;
// static lv_color_t buf_2_1[MY_DISP_HOR_RES * DISP_BUFFER_LINES]; /*A buffer for 10 rows*/
// static lv_color_t buf_2_2[MY_DISP_HOR_RES * DISP_BUFFER_LINES]; /*An other buffer for 10 rows*/
// lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * DISP_BUFFER_LINES); /*Initialize the display buffer*/
// /* Example for 3) also set disp_drv.full_refresh = 1 below*/
// static lv_disp_draw_buf_t draw_buf_dsc_3;
// static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*A screen sized buffer*/
// static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*Another screen sized buffer*/
// lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2,
// MY_DISP_VER_RES * MY_DISP_VER_RES); /*Initialize the display buffer*/
/*-----------------------------------
* Register the display in LVGL
*----------------------------------*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Set up the functions to access to your display*/
/*Set the resolution of the display*/
disp_drv.hor_res = MY_DISP_HOR_RES;
disp_drv.ver_res = MY_DISP_VER_RES;
/*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = disp_flush;
/*Set a display buffer*/
disp_drv.draw_buf = &draw_buf_dsc_1;
/*Required for Example 3)*/
//disp_drv.full_refresh = 1;
/* Fill a memory array with a color if you have GPU.
* Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
* But if you have a different GPU you can use with this callback.*/
//disp_drv.gpu_fill_cb = gpu_fill;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}
3、修改disp_flush函數(shù)
該函數(shù)就是調(diào)用底層LCD描點(diǎn)函數(shù)進(jìn)行繪制UI界面的。
// LCD描點(diǎn)函數(shù)
void LCD_Color_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u16 *color)
{
u16 i, j;
u16 height, width;
width = ex - sx + 1;
height = ey - sy + 1;
LCD_Address_Set(sx,sy+OFFSET_Y,ex,ey+OFFSET_Y);
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
LCD_WR_DATA(color[i * width + j]);
}
}
}
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
// 調(diào)用底層LCD描點(diǎn)函數(shù)
LCD_Color_Fill(area->x1, area->y1, area->x2, area->y2, (uint16_t *)color_p);
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
4.4 添加和修改RT-Thread環(huán)境的LVGL文件支持
我們需要把LVGL運(yùn)行在RT-Thread系統(tǒng),所以我們需要添加LVGL的RT-Thread接口文件。官方其實(shí)已經(jīng)做好了對(duì)應(yīng)的文件,我們復(fù)制到工程目錄下修改即可。
(1)添加LVGL的RT-Thread接口文件到Keil工程
然后把這兩個(gè)文件加入到Keil工程目錄下:
(2)修改lv_rt_thread_conf.h頭文件
因?yàn)楣俜揭呀?jīng)做好了RT-Thread接口文件了,我們只需要簡(jiǎn)單修改即可。修改如下:
4.5 添加LVGL Demo例程
前面的移植和修改代碼已經(jīng)完成了LVGL的移植工程,下面我們添加一個(gè)簡(jiǎn)單的 LVGLDemo 例程進(jìn)行測(cè)試。
我們可以在官方的源碼目錄 .demos 目錄下選一個(gè)示例程序,或者也可以自己找一個(gè)其他的簡(jiǎn)單的LVGL示例代碼。我下面選一個(gè)日歷demo例程進(jìn)行演示。
最后編譯工程源碼和下載到APM32F411中。
編譯會(huì)有一些警告,這是LVGL源碼引入的,有些語(yǔ)**有警告,可以暫時(shí)忽略。
在APM32F411運(yùn)行結(jié)果如下:
5. 給LVGL添加觸摸接口
前面的移植已經(jīng)把顯示接口給完成了,而且上面也可以正常顯示了。但是LVGL的輸入接口還沒(méi)移植進(jìn)來(lái),不過(guò)有了前面的移植過(guò)程,添加觸摸輸入接口就很簡(jiǎn)單了。主要就是修改 lv_port_indev.c 文件。
(1)把 lv_port_indev.c 文件的宏定義改為1
(2)修改 touchpad_is_pressed 和 touchpad_get_xy 函數(shù)
/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
/*Your code comes here*/
uint8_t num = cst816t_get_touch_points_num(); // 是否有觸摸點(diǎn)
if ((num != 0) && (num != 0xFF))
{
return true;
}
else
{
return false;
}
}
/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
/*Your code comes here*/
// uint16_t tp_x = 0, tp_y = 0;
cst816t_read_pos((uint16_t *)x, (uint16_t *)y); // 底層獲取觸摸坐標(biāo)函數(shù)
// (*x) = tp_x;
// (*y) = tp_y;
}
cst816t_read_pos 函數(shù)是要我們先寫好的獲取觸摸坐標(biāo)的函數(shù)。另外還有一些沒(méi)用到的代碼我給注釋掉了。
增加完上述代碼就可以發(fā)現(xiàn)在屏幕可以點(diǎn)擊進(jìn)行修改日期了,說(shuō)明觸摸接口移植完成。
最后,APM32F411在RT-Thread系統(tǒng)下移植LVGL工程就全部完成了。整個(gè)過(guò)程還是比較簡(jiǎn)單的,而且網(wǎng)上也有很多相關(guān)的教程。不過(guò)移植過(guò)程中還是碰到不是小問(wèn)題的,有些細(xì)節(jié)并沒(méi)有在文章中一一寫出來(lái),在移植過(guò)程中遇到一些問(wèn)題就需要我們根據(jù)報(bào)錯(cuò)提示對(duì)應(yīng)解決就好。另外,在移植前最重要的就是要保證LCD驅(qū)動(dòng)和觸摸驅(qū)動(dòng)代碼正確,然后再進(jìn)行移植,這樣出現(xiàn)問(wèn)題我們比較好分析和定位問(wèn)題。
-
微控制器
+關(guān)注
關(guān)注
48文章
7542瀏覽量
151316 -
嵌入式
+關(guān)注
關(guān)注
5082文章
19104瀏覽量
304797 -
移植
+關(guān)注
關(guān)注
1文章
379瀏覽量
28124 -
GUI
+關(guān)注
關(guān)注
3文章
659瀏覽量
39654 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1285瀏覽量
40081
原文標(biāo)題:APM32芯得 EP.47 | APM32F411在RT-Thread系統(tǒng)下移植LVGL-8.3
文章出處:【微信號(hào):geehysemi,微信公眾號(hào):Geehy極海半導(dǎo)體】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論