• 正文
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

基于STM32的LVGL(GUI庫(kù))學(xué)習(xí)日記(1)——LVGL工程移植和Demo測(cè)試

5小時(shí)前
136
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

前言

LVGL是一個(gè)免費(fèi)開(kāi)源嵌入式圖形庫(kù),它特別擅長(zhǎng)為資源受限的微控制器或小型處理器設(shè)備打造漂亮的用戶界面。由于它設(shè)計(jì)得非常輕巧高效,同時(shí)對(duì)內(nèi)存和處理器要求不高,因此能輕松適配各種屏幕尺寸和類型的嵌入式硬件平臺(tái)。它提供了異常豐富的現(xiàn)成組件,像按鈕、圖表、列表這些常用控件一應(yīng)俱全,并且支持高級(jí)特性比如流暢的動(dòng)畫(huà)、抗鋸齒字體顯示和矢量圖形的平滑縮放效果。

開(kāi)發(fā)者可以用C語(yǔ)言相對(duì)便捷地構(gòu)建出視覺(jué)效果現(xiàn)代、交互流暢的界面,加上其完善的文檔和活躍的中文社區(qū)支持,LVGL大大降低了在嵌入式系統(tǒng)上開(kāi)發(fā)專業(yè)級(jí)GUI的門(mén)檻和復(fù)雜度,是物聯(lián)網(wǎng)設(shè)備、工控面板、穿戴設(shè)備等嵌入式屏幕交互開(kāi)發(fā)的強(qiáng)力助手。

本期我們介紹在STM32中移植并使用LVGL進(jìn)行GUI開(kāi)發(fā),開(kāi)發(fā)板采用STM32N6570-DK,開(kāi)發(fā)平臺(tái)采用STM32CubeIDE1.18.1,LVGL版本為v8.2,參考資料為正點(diǎn)原子LGVL教程。

 

1

LGVL庫(kù)下載和精簡(jiǎn)

 

 

 

 

 

 

 

在LVGL的官網(wǎng)中可以跳轉(zhuǎn)到其GitHub倉(cāng)庫(kù)處,分支選擇為v8.2版本并下載。

LVGL源文件僅保留如圖五個(gè)文件即可,其中examples文件夾可以進(jìn)一步裁剪。

examples文件夾中僅保留porting文件夾內(nèi)容即可,因此精簡(jiǎn)完的LVGL庫(kù)只有如下文件:

 

2

工程搭建

 

 

 

 

 

 

 

除了lvgl庫(kù)以外,需要準(zhǔn)備好顯示屏驅(qū)動(dòng)程序和觸摸驅(qū)動(dòng)程序,并有一個(gè)可以用的工程模板。

該工程除了屏幕的驅(qū)動(dòng)之外,還需要開(kāi)啟一個(gè)定時(shí)器用來(lái)給lvgl底層提供時(shí)基,推薦定時(shí)1毫秒。

確認(rèn)頭文件和源文件地址設(shè)置正確并開(kāi)啟了編譯優(yōu)化。

打開(kāi)lv_conf_template.h文件,將宏定義使能修改為1,代表著使能這部分內(nèi)容。

并且將lv_conf_template.h重命名為lv_conf.h!!!

并且將lv_conf_template.h重命名為lv_conf.h!!!

并且將lv_conf_template.h重命名為lv_conf.h!!!

(重要的事情說(shuō)三遍)

接著打開(kāi)examples的porting文件夾中的lv_port_disp_template.c/.h還有l(wèi)v_port_indev_template.c/.h添加刷新和觸摸驅(qū)動(dòng)。

這四個(gè)文件(.c/.h),都要將宏定義使能修改為1。

lv_port_disp_template.c的初始化函數(shù)void lv_port_disp_init(void)提供了三種刷新方式,我們選擇方式1(局部刷新)并修改屏幕寬度和屏幕大小。

這里的800*10可以根據(jù)自己的RAM大小修改,例如我修改為800*480

/*Initialize your display and the required peripherals.*/staticvoiddisp_init(void){? ??/*You code here*/??BSP_LCD_Init(0,?0);//屏幕初始化,換做自己原來(lái)的}
/*Flush the content of the internal buffer the specific area on the display?*You can use DMA or any hardware acceleration to do this operation in the background but?*'lv_disp_flush_ready()' has to be called when finished.*/staticvoiddisp_flush(lv_disp_drv_t * disp_drv, constlv_area_t * area, lv_color_t * color_p){? ??/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/? ??BSP_LCD_FillRGBRect(0, area->x1, area->y1, (uint16_t *)color_p, area->x2-area->x1+1, area->y2-area->y1+1);? ??/*IMPORTANT!!!? ? ?*Inform the graphics library that you are ready with the flushing*/? ??lv_disp_flush_ready(disp_drv);}

并在disp_init函數(shù)和disp_flush函數(shù)中提供屏幕初始化和區(qū)域刷新驅(qū)動(dòng)。

lv_port_indev_template.c/.h提供了輸入設(shè)備邏輯,我們將沒(méi)有用到的設(shè)備內(nèi)容全部刪除/注釋掉,由于我們僅采用觸摸屏故僅保留touchpad內(nèi)容。

所以初始化中僅保留touchpad相關(guān)函數(shù)和語(yǔ)句,其他函數(shù)也僅保留如下四個(gè)函數(shù)。

TS_State_t TS_State;//觸摸屏全局變量/*Initialize your touchpad*/staticvoidtouchpad_init(void){? ??/*Your code comes here*/? TS_Init_t TS_Init;? ??/* 初始化觸摸屏 */? TS_Init.Width?=?800; ? ? ? ?// 屏幕寬度? TS_Init.Height?=?480; ? ? ??// 屏幕高度? ? TS_Init.Orientation?=?TS_SWAP_NONE;?// 方向,不旋轉(zhuǎn)? TS_Init.Accuracy?=?5; ? ? ??// 精度,5個(gè)像素的抖動(dòng)會(huì)被過(guò)濾??BSP_TS_Init(0, &TS_Init);}
/*Will be called by the library to read the touchpad*///這個(gè)函數(shù)沒(méi)做修改staticvoidtouchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data){? ? staticlv_coord_t last_x =?0;? ? staticlv_coord_t last_y =?0;
? ??/*Save the pressed coordinates and the state*/? ??if(touchpad_is_pressed()) {? ? ? ??touchpad_get_xy(&last_x, &last_y);? ? ? ? data->state =?LV_INDEV_STATE_PR;? ? }?else?{? ? ? ? data->state =?LV_INDEV_STATE_REL;? ? }
? ??/*Set the last pressed coordinates*/? ? data->point.x?= last_x;? ? data->point.y?= last_y;}
/*Return true is the touchpad is pressed*/staticbooltouchpad_is_pressed(void){? ??/*Your code comes here*/? ??//檢測(cè)到觸摸??if?(BSP_TS_GetState(0, &TS_State) ==?BSP_ERROR_NONE) {? ? ?if?(TS_State.TouchDetected) {? ? ? ? ? returntrue;//檢測(cè)到返回真? ? ?}? }? ? returnfalse;}
/*Get the x and y coordinates if the touchpad is pressed*/staticvoidtouchpad_get_xy(lv_coord_t * x, lv_coord_t * y){? ??/*Your code comes here*/??// 獲取觸摸坐標(biāo)? ? (*x) = TS_State.TouchX;? ? (*y) = TS_State.TouchY;}

保留touchpad內(nèi)容并完成“觸摸初始化”,“檢測(cè)觸摸生效”,“獲取觸摸位置”三個(gè)內(nèi)容。

??HAL_TIM_Base_Start_IT(&htim18);//開(kāi)啟定時(shí)器??lv_init();//Lvgl初始化??lv_port_disp_init();//屏幕初始化??lv_port_indev_init();//輸入設(shè)備輸出化//上述三個(gè)步驟順序不能調(diào)換while?(1)? {? ??lv_timer_handler();? ??HAL_Delay(5);? }

在main主函數(shù)中加入lvgl初始化和設(shè)備初始化,并在While循環(huán)中添加延時(shí)并觸發(fā)定時(shí)器時(shí)基句柄(這里的時(shí)間不用太精確)。

voidHAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){? ?static?Timnumber?=?0;? ?if(htim->Instance?==?TIM18)? ?{? ? ?lv_tick_inc(1);//lvgl時(shí)基觸發(fā) 1? ? ?//如果是5ms延時(shí)就填入5? ? ?Timnumber++;? ? ?if(Timnumber?==?500)? ? ?{? ? ? ?//每500秒LED反轉(zhuǎn)? ? ? ?HAL_GPIO_TogglePin(GPIOO,?GPIO_PIN_1);? ? ? ?Timnumber?=?0;? ? ?}? ?}}

定時(shí)器回調(diào)函數(shù)中添加lvgl時(shí)基函數(shù)。(記得開(kāi)啟定時(shí)器TIM哦),至此lvgl的工程配置完畢。

 

3

lvgl測(cè)試

 

 

 

 

 

 

 

 

lvgl提供了好幾個(gè)測(cè)試Demo,我們將stressDemo進(jìn)行測(cè)試。

在lvgl.h中找到LV_USE_DEMO_STRESS宏定義并將其設(shè)置為1使能。

main中包含這個(gè)Demo的頭文件,并在lvgl初始化后調(diào)用demo例程。

??HAL_TIM_Base_Start_IT(&htim18);//開(kāi)啟定時(shí)器??lv_init();//Lvgl初始化??lv_port_disp_init();//屏幕初始化??lv_port_indev_init();//輸入設(shè)備輸出化??lv_demo_stress();//demo例程??while(1)? {? ??lv_timer_handler();? ??HAL_Delay(5);??

效果如下:

 

相關(guān)推薦