另:本公眾號由於開通得比較晚,所以不具備留言功能。所以大家想看哪些內容,可以在公眾號聊天界面留言,小編會參考大家的意見輸出、整理一些相關的內容。一起成長、一起進步。期待留言~
下面我們一起來看一看LVGL在STM32上的移植使用。
lvgl簡介LittlevGL是一個免費的開源圖形庫,提供了創建嵌入式GUI所需的一切,具有易於使用的圖形元素、漂亮的視覺效果和低內存佔用。
特點:
可裁剪 用於小內存(80 KB FLASH,12 KB RAM)操作模擬器 無需嵌入式硬體就可以在電腦上開始GUI設計運行的硬體要求:
LVGL的資料很豐富,下面列出一些常用的資料連結:
1、lvgl英文官網:https://lvgl.io/
2、lvgl中文網:https://littlevgl.cn/ (還在建設中)
3、lvgl源碼:https://github.com/lvgl/lvgl
4、lvgl基於Visual sudio 的PC模擬器:https://github.com/lvgl/lv_sim_visual_studio
5、正點原子lvgl教程資料:http://www.openedv.com/docs/book-videos/zdyzshipin/4free/littleVGL.html
6、基於荔枝派Nano開發板的lvgl教程:http://nano.lichee.pro/application/littlevgl.html
7、基於野牛開發板的 lvgl 6.0 例程:https://gitee.com/mzy2364/LittlevGL_Demo
8、lvgl在線體驗例程(可在瀏覽器體驗):https://lvgl.io/demos
9、lvgl官網教程:https://docs.lvgl.io/latest/en/html/index.html
10、lvgl官方DEMO:https://github.com/lvgl/lv_examples
lvgl移植到STM321、下載源碼
源碼連結中下載一份源碼,lvgl已經更新迭代了很多個版本,這裡我們選擇目前最新的7.10.1版本來移植:
注意:不同版本之間可能有很大的不同,所以看本篇教程移植的的小夥伴儘量使用與本文相同的版本。
下載得到:
2、準備stm32工程
下面我基於普中的stm32f103開發板來移植,首先準備一個lcd顯示的例程,並更名為lvgl_test:
3、新建GUI文件夾
在工程目錄下新建一個GUI文件夾,GUI文件夾下新建兩個子文件夾:
把剛才下載的lvgl-7.10.1裡的所有內容複製到lvgl文件夾中,lvgl_app文件夾暫時留空。
4、移植文件更名
下面,我們把GUI\lvgl\examples\porting下的文件進行一個更名操作(其實不更名也可以,為了文件名看起來規範一些我們進行一個更名):
這是移植相關的幾個文件,其中:
lv_port_disp:顯示相關。
lv_port_indev:輸入相關。
lv_port_fs:文件系統相關。
5、配置文件更名
把GUI\lvgl\下的lv_conf_template.h文件複製到GUI文件夾下並更名為lv_conf.h:
6、keil工程配置
(1)導入文件
打開keil工程,在工程下新建三個組,並導入文件:
導入完成後得到:
這裡的lvgl_porting中我們暫時只導入lv_port_disp.c文件,這是顯示相關的移植文件。本篇筆記先把顯示打通,其它兩個文件後續有機會再弄。
(2)包含頭文件路徑
下面包含頭文件路徑:
(3)修改堆棧大小
因為官方說明文檔中推薦我們堆、棧大小設置為8k:
所以這裡我們就按推薦進行設置:
(4)設置C99模式
lvgl需要編譯器支持C99或更新的標準:
C99模式可進行如下設置:
(5)使能lv_conf.h的條件編譯
進行上面的設置後我們首先進行編譯,會報很多個錯誤:
這是因為需要lv_conf.h裡的一些東西,打開lv_conf.h裡的條件編譯即可:
再次編譯,編譯通過:
(6)lvgl配置
我們可以對lvgl進行一些定製配置,這些配置內容在lv_conf.h文件中,下面進行一些關鍵配置:
顯示器寬度:#define LV_HOR_RES_MAX (240)顯示器高度:#define LV_VER_RES_MAX (480)色彩深度: #define LV_COLOR_DEPTH 16提供給lvgl的空間: #define LV_MEM_SIZE (32U * 1024U)其中調整LV_DPI 可以調整各控制項間的緊湊,可根據實際情況進行更改;LV_MEM_SIZE 為lvgl可用空間,資源允許的情況下可以稍微設大些,這個設置過小的話,在跑一些稍微複雜的demo時界面就會刷不出來。
這裡只是列出了幾個常用的配置,lv_conf.h還有很多的配置,可根據實際情況進行配置。
(7)填充、修改lv_port_disp.c
lv_port_disp.c裡面的內容主要有:
我們需要重點關注lv_port_disp_init顯示接口初始化函數與disp_flush屏幕刷新兩個函數。
其中,lv_port_disp_init函數裡主要要選擇一種寫緩存的方式及設置顯示分辨。我們選擇第一種寫緩存的方式,修改後的函數如:
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 your display drivers `flush_cb` to copy its content to your display.
* The buffer has to be greater than 1 display row
*
* There are three buffering configurations:
* 1. Create ONE buffer with some rows:
* LVGL will draw the display's content here and writes it to your display
*
* 2. Create TWO buffer with some rows:
* 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. Create TWO screen-sized buffer:
* Similar to 2) but the buffer have to be screen sized. When LVGL is ready it will give the
* whole frame to display. This way you only need to change the frame buffer's address instead of
* copying the pixels.
* */
/* Example for 1) */
static lv_disp_buf_t draw_buf_dsc_1;
static lv_color_t draw_buf_1[LV_HOR_RES_MAX * 10]; /*A buffer for 10 rows*/
lv_disp_buf_init(&draw_buf_dsc_1, draw_buf_1, NULL, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/
// /* Example for 2) */
// static lv_disp_buf_t draw_buf_dsc_2;
// static lv_color_t draw_buf_2_1[LV_HOR_RES_MAX * 10]; /*A buffer for 10 rows*/
// static lv_color_t draw_buf_2_1[LV_HOR_RES_MAX * 10]; /*An other buffer for 10 rows*/
// lv_disp_buf_init(&draw_buf_dsc_2, draw_buf_2_1, draw_buf_2_1, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/
// /* Example for 3) */
// static lv_disp_buf_t draw_buf_dsc_3;
// static lv_color_t draw_buf_3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX]; /*A screen sized buffer*/
// static lv_color_t draw_buf_3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX]; /*An other screen sized buffer*/
// lv_disp_buf_init(&draw_buf_dsc_3, draw_buf_3_1, draw_buf_3_2, LV_HOR_RES_MAX * LV_VER_RES_MAX); /*Initialize the display buffer*/
/*
* Register the display in LVGL
*----*/
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 = 240;
disp_drv.ver_res = 400;
/*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = disp_flush;
/*Set a display buffer*/
disp_drv.buffer = &draw_buf_dsc_1;
#if LV_USE_GPU
/*Optionally add functions to access the GPU. (Only in buffered mode, LV_VDB_SIZE != 0)*/
/*Blend two color array using opacity*/
disp_drv.gpu_blend_cb = gpu_blend;
/*Fill a memory array with a color*/
disp_drv.gpu_fill_cb = gpu_fill;
#endif
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}disp_flush需要調用底層lcd操作接口,這裡修改為:
這裡我們調用一個寫像素點的函數,也可以直接調用一個顯示的填充方形函數。
最後,需要再頭文件中聲明lv_port_disp_init函數:
(8)配置一個定時器為lvgl提供心跳
lvgl需要一個心跳節拍,可以使用系統滴答定時器,也可以使用其它定時器。我們這裡的配置如下:
TIM4_Init(999, 71); // 1ms進入一次中斷,為lvgl提供心跳void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_Update))
{
lv_tick_inc(1);
}
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}(9)測試官方demo
下面開始進行測試,至此我們的GUI\lvgl_app文件夾裡還沒有任何內容,我們下載官方提供的demo來進行測試,同樣地,下載官方demo:
官方給我們提供了很多demo:
複製lv_examples-7.10.1整個文件夾至GUI\lvgl_app文件夾下並更名為lv_examples:
把GUI\lvgl_app\lv_examples下的lv_ex_conf_template.h複製到GUI文件夾下並更名為lv_ex_conf.h,這是demo的配置文件:
想跑哪個demo就配置相關宏。
下面我們跑一個lv_demo_widgets的demo進行演示:
主函數:
運行測試:
至此,lvgl顯示移植成功。要想演示其它綜合demo或控制項例子也同上面一樣導入源文件、包含頭文件、打開demo宏開關等步驟進行演示。
本次要分享的內容就要結束啦,希望對正在學習LVGL的童鞋有幫助,更多精彩內容,歡迎各位加群一起交流。
公眾號點擊加群獲取群二維碼,點擊獲取資料,獲取所有實驗源碼!