|
LVGL全稱Light and Versatile Graphics Library,輕量級通用圖形庫。
LVGL是一個(gè)開源的ui圖形庫,能跑在各種單片機(jī)上(樹莓派、荔枝派也行)。支持按鈕,觸摸,編碼器旋鈕,鼠標(biāo)等輸入設(shè)備。支持高級圖形效果,動畫、反鋸齒、透明度等。LVGL的界面非常精美,可以在官網(wǎng)的先感受一下他的強(qiáng)大,這是它demo的鏈接。
lvgl對處理器的要求很低,源自[官方文檔]。(docs.lvgl io/master/intro/index.html#requirements)
二
使用分辨率320*480的屏幕,驅(qū)動芯片LIL9486,16位色TN屏,觸摸是電阻屏,處理器stm32f103zet6,板子是自己畫的,可以使用正點(diǎn)原子的精英板,屏幕接口完全一樣,用的都是FSMC總線。
三、移植前準(zhǔn)備工作
1.準(zhǔn)備原有工程
本教程基于正點(diǎn)原子的觸摸屏實(shí)驗(yàn)移植,源碼可以在正點(diǎn)原子資料下載中心下載。
不一定要用這個(gè)工程,只需要一個(gè)屏幕,能顯示能觸控就行,lvgl用到的屏幕接口只有一個(gè):
/**
* @brief 在指定區(qū)域內(nèi)填充指定顏色塊
* @param sx sy ex ey (sx,sy),(ex,ey):填充矩形對角坐標(biāo),區(qū)域大小為:(ex-sx+1)*(ey-sy+1)
* @param color 要填充的顏色
*/
void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)
對于觸摸識別,只需要有一個(gè)當(dāng)前觸摸的x、y坐標(biāo),有一個(gè)觸摸按下的標(biāo)志。
if(tp_dev.sta&0x80)//tp_dev.sta為觸摸按下的標(biāo)記,有觸摸的時(shí)候最高位標(biāo)記為1,滿足if的條件
{
last_x = tp_dev.x[0];//tp_dev.x[0]為觸摸芯片讀取的x坐標(biāo)
last_y = tp_dev.y[0];//tp_dev.y[0]為觸摸芯片讀取的y坐標(biāo)
data->point.x = last_x;//data->point.x為lvgl內(nèi)部使用
data->point.y = last_y;
data->state = LV_INDEV_STATE_PR;//給lvgl標(biāo)記按下的狀態(tài)
}
else
{
data->point.x = last_x;
data->point.y = last_y;
data->state = LV_INDEV_STATE_REL
}
除此之外,還需要一個(gè)周期為1ms的定時(shí)器中斷,給lvgl提供心跳。
以上三點(diǎn)是lvgl最基本的需求。
我們先把觸摸屏實(shí)驗(yàn)的名子改成touch(養(yǎng)成好習(xí)慣,改成英文名,防止各種坑),由于觸摸屏實(shí)驗(yàn)沒有定時(shí)器中斷,我們先加一個(gè),先把定時(shí)器中斷實(shí)驗(yàn)中HARDWARE/TIMER文件夾復(fù)制到touch/HARDWARE
打開keil,先把添加進(jìn)去的TIMER文件包含了,具體見下圖,都是些搬運(yùn)代碼的基本操作。
編譯成功,0錯誤0警告。到此,我們的工程準(zhǔn)備完畢,這是準(zhǔn)備好的工程,點(diǎn)擊直接下載,本工程就是在正點(diǎn)原子觸摸屏實(shí)驗(yàn)的基礎(chǔ)上加了個(gè)定時(shí)器中斷。
"..\OBJ\TOUCH.axf" - 0 Error(s), 0 Warning(s).
1
跑起來就是這樣,屏幕能顯示,且支持觸摸:
完美。
2.下載LVGL源碼
打開github,國內(nèi)網(wǎng)絡(luò)環(huán)境訪問github有時(shí)候不太行,如果打不開請直接下載,這是lvgl v8.0.2版本的下載鏈接,
點(diǎn)擊lvgl在github的倉庫,依次點(diǎn)擊master、tags、v8.0.2
切換到V8.0.2分支后,再點(diǎn)code、下載zip
把下載好的lvgl-8.0.2.zip文件解壓,至此,源碼下載完畢
LVGL V8.2.0都有了,為什么你還下載V8.02?
問的好,為了減少徒手?jǐn)]代碼的時(shí)間,我們后續(xù)使用另一款軟件,恩智浦的GUI Guider進(jìn)行界面可視化設(shè)計(jì),這個(gè)軟件的V1.3.x版本只支持到lvgl V8.0.2。
用這個(gè)軟件生成代碼,直接搬運(yùn)到工程編譯,界面設(shè)計(jì)嘎嘎快,下圖是演示效果,因?yàn)橹黝}不一樣,顏色有點(diǎn)區(qū)別。
四、開始移植
1.把源碼搬運(yùn)到工程文件夾里
在touch目錄下新建一個(gè)lvgl文件夾
把lvgl-8.0.2\src文件夾直接復(fù)制到新建的lvgl文件夾里,這個(gè)src里面就是源碼
把lvgl-8.0.2\examples\porting文件夾復(fù)制到新建的lvgl文件夾里,這是移植用的接口
把lvgl-8.0.2目錄下的lvgl.h、lv_conf_template.h、LICENCE.txt、README.md一共4個(gè)文件復(fù)制到新建的lvgl文件夾里,后面兩個(gè)可以不用,不影響移植
現(xiàn)在,touch\lvgl目錄下一共這幾個(gè)文件:
搬運(yùn)好了代碼,我們得給文件改個(gè)名字,不然文件內(nèi)部包含的頭文件名字不一致
把touch\lvgl目錄下的lv_conf_template.h文件名字改成lv_conf.h
把touch\lvgl\porting目錄下所有文件名字的_template刪了,改完之后長這樣
至此,我們的代碼搬運(yùn)工作結(jié)束。
2.把搬運(yùn)好的代碼添加到keil工程
打開keil,點(diǎn)擊文件擴(kuò)展按鈕,新建三個(gè)組,名字分別為LVGL_SRC、LVGL_PORTING、LVGL_DEMO
接下來就是愉快(無聊)的添加.C文件過程。
先對LVGL_SRC組添加文件,把touch\lvgl\src路徑下的所有.c文件都添加進(jìn)去,你沒有聽錯,是所有.c文件,包括所有子目錄,可以結(jié)合Ctrl+A快捷鍵全選之后再點(diǎn)擊添加,提高效率。
注意,touch\lvgl\src\extra\widgets這個(gè)目錄下文件非常分散,要一個(gè)一個(gè)添加,不要漏了,LVGL_SRC組一共133個(gè).c文件(一個(gè)一個(gè)數(shù)的),不想自己移植可以直接使用我移植好的工程文件,這是移植完的工程文件,適配正點(diǎn)原子精英板。
添加好之后:(一張圖顯示不下)
把touch\lvgl\porting路徑下所有的.c文件添加到LVGL_PORTING組,這個(gè)文件少,就三個(gè)
LVGL_DEMO組先不管,需要跑DEMO的時(shí)候再添加。
接下來包含頭文件。
把touch\lvgl、touch\lvgl\src、touch\lvgl\porting三個(gè)路徑包含。
好了,現(xiàn)在需要的庫都添加完了。
3.動手改代碼
先點(diǎn)一下編譯,發(fā)現(xiàn) 121 Error(s), 0 Warning(s)。
..\lvgl\src\widgets\../lv_conf_internal.h(41): error: #5: cannot open source input file "../../lv_conf.h": No such file or directory
# include "../../lv_conf.h" /*Else assume lv_conf.h is next to the lvgl folder*/
..\lvgl\src\widgets\lv_textarea.c: 0 warnings, 1 error
compiling lv_port_fs.c...
compiling lv_port_indev.c...
"..\OBJ\TOUCH.axf" - 121 Error(s), 0 Warning(s).
編譯器找不到"…/…/lv_conf.h"這個(gè)文件,lv_conf.h就在touch\lvgl路徑下,我們剛才把lv_conf.h的路徑包含了,所有不用…/…/,直接在lv_conf_internal.h(41行)刪了就行
把lv_conf.h文件#if 0 改成#if 1
同樣的,把lv_port_disp.c、lv_port_disp.h、lv_port_indev.c、lv_port_indev.c四個(gè)文件的#if 0 都改成#if 1 ,這四個(gè)文件包含的頭文件名字還需修改,具體看下圖。這四個(gè)文件中的兩個(gè).h文件中,路徑為#include "lvgl/lvgl.h"改成#include “l(fā)vgl.h”。
把keil改成C99模式,在usart.c的第48行,_sys_exit函數(shù)前面加一個(gè)void,不然在C99模式下編譯會報(bào)錯
//定義_sys_exit()以避免使用半主機(jī)模式
void _sys_exit(int x)
{
x = x;
}
點(diǎn)擊全部保存,我們先把keil關(guān)閉,在touch目錄下,對lvgl文件夾點(diǎn)右鍵-屬性,把只讀的選項(xiàng)取消勾選,應(yīng)用于子文件夾和文件,避免keil重復(fù)編譯,不然每次點(diǎn)擊編譯,所有文件都編譯一遍,等一萬年。
打開keil,為了不讓keil每次都把所有代碼編譯一遍,在設(shè)置-Output選項(xiàng)中,不要勾選Create Batch File 創(chuàng)建批處理文件,在設(shè)置-Target選項(xiàng)中,不要勾選 使用交叉模塊優(yōu)化,也不要勾選 use Micro LIB,因?yàn)長VGL有個(gè)二維碼的控件使用Micro LIB編譯會報(bào)錯。
好了,我們現(xiàn)在再次點(diǎn)擊編譯,發(fā)現(xiàn)又有6個(gè)錯誤。
"..\OBJ\TOUCH.axf" - 6 Error(s), 34 Warning(s).
原來是lv_port_disp.c文件里面有幾個(gè)宏定義沒有定義好。
我們在lv_conf.h中定義好屏幕的水平像素和垂直像素大小,順手把LV_COLOR_DEPTH 改成16位(根據(jù)實(shí)際情況改,如果屏幕是32位色就不用改)
/*====================
COLOR SETTINGS
*====================*/
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 16
#define MY_DISP_HOR_RES 480
#define MY_DISP_VER_RES 320
把lv_port_disp.c的里面的example 2 和3都注釋了,只留example1,點(diǎn)擊編譯,編譯通過,警告不用管,大多是因?yàn)槎x了函數(shù)但是沒有使用而報(bào)警告,不影響。
接著在timer.c中的定時(shí)器中斷中添加lvgl的心跳接口。
先在timer.c文件頂部包含lvgl.h
然后在定時(shí)器中斷中調(diào)用lv_tick_inc(1);
//定時(shí)器3中斷服務(wù)程序
void TIM3_IRQHandler(void) //TIM3中斷
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //檢查TIM3更新中斷發(fā)生與否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中斷標(biāo)志
lv_tick_inc(1);//lvgl的1ms中斷
}
}
文件改動完畢后添加屏幕顯示和觸控支持
4.添加屏幕的接口
在lv_port_disp.c文件的頂部包含自己的lcd.h,用于調(diào)用lcd相關(guān)的接口
根據(jù)實(shí)際情況,在lv_port_disp.c文件中給disp_drv.hor_res和disp_drv.ver_res兩個(gè)參數(shù)賦值,可以是lcd初始化之后獲取的,也可以是固定的
在disp_flush函數(shù)中,注釋原來的for循環(huán),把自己的LCD填充顏色的函數(shù)放進(jìn)去。
至此,我們屏幕顯示的接口移植完畢,簡單吧
5.顯示測試
終于要到跑代碼的環(huán)節(jié)了,萬事萬物先從點(diǎn)燈開始。
LVGL有一個(gè)LED控件,在屏幕上顯示一個(gè)LED,可以開關(guān)、調(diào)亮度等,我們可以先跑起來看看。
在mian.c文件的頂上添加lvgl的頭文件。
#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
注釋原有觸摸實(shí)驗(yàn)的函數(shù),增加lvgl初始化函數(shù),死循環(huán)中放任務(wù)處理函數(shù)。
lv_init(); // lvgl系統(tǒng)初始化
lv_port_disp_init(); // lvgl顯示接口初始化,放在lv_init()的后面
lv_port_indev_init(); // lvgl輸入接口初始化,放在lv_init()的后面
while (1)
{
lv_task_handler(); // lvgl的事務(wù)處理
}
可以看到,keil報(bào)錯(紅色波浪下劃線),因?yàn)?lv_port_disp_init和lv_port_indev_init兩個(gè)函數(shù)找不到,需要我們在lv_port_disp.h和lv_port_indev.h文件中聲明這兩個(gè)函數(shù)。
lv_port_disp.h添加聲明:
void lv_port_disp_init(void);
1
lv_port_indev.h添加聲明:
void lv_port_indev_init(void);
1
添加完聲明后報(bào)錯消失。
接下來我們打開最初從github下載下來,解壓好的lvgl-8.0.2文件夾,在lvgl-8.0.2\examples\widgets\led路徑中打開lv_example_led_1.c文件,復(fù)制lv_example_led_1函數(shù)放在main.c文件中。
/**
* Create LED's with different brightness and color
*/
void lv_example_led_1(void)
{
/*Create a LED and switch it OFF*/
lv_obj_t * led1 = lv_led_create(lv_scr_act());
lv_obj_align(led1, LV_ALIGN_CENTER, -80, 0);
lv_led_off(led1);
/*Copy the previous LED and set a brightness*/
lv_obj_t * led2 = lv_led_create(lv_scr_act());
lv_obj_align(led2, LV_ALIGN_CENTER, 0, 0);
lv_led_set_brightness(led2, 150);
lv_led_set_color(led2, lv_palette_main(LV_PALETTE_RED));
/*Copy the previous LED and switch it ON*/
lv_obj_t * led3 = lv_led_create(lv_scr_act());
lv_obj_align(led3, LV_ALIGN_CENTER, 80, 0);
lv_led_on(led3);
}
在mian.c文件的主函數(shù)初始化中調(diào)用lv_example_led_1,在死循環(huán)中調(diào)用lvgl的事務(wù)處理函數(shù)lv_task_handler。
lv_task_handler(); // lvgl的事務(wù)處理
1
編譯,下載,點(diǎn)燈成功。
6.添加觸摸的接口
和添加顯示驅(qū)動一樣,我們先在lv_port_indev.c文件的頂部包含自己的touch.h,用于調(diào)用touch相關(guān)的接口和引用相關(guān)變量。
由于我們只用到觸摸輸入,為了防止各種誤識別各種坑,先把其它的輸入設(shè)備注釋掉。
注釋好之后,lv_port_indev.c文件的touchpad_read函數(shù)改成如下,對觸摸芯片返回參數(shù)的具體的要求參見2.1小節(jié)觸摸代碼中的注釋。
/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static lv_coord_t last_x = 0;
static lv_coord_t last_y = 0;
/*Save the pressed coordinates and the state*/
if(tp_dev.sta&TP_PRES_DOWN)
{
last_x = tp_dev.x[0];
last_y = tp_dev.y[0];
data->point.x = last_x;
data->point.y = last_y;
data->state = LV_INDEV_STATE_PR;
}
else
{
data->point.x = last_x;
data->point.y = last_y;
data->state = LV_INDEV_STATE_REL;
}
// printf("x %d ,y %d \r\n",data->point.x,data->point.y);
/*Set the last pressed coordinates*/
// data->point.x = last_x;
// data->point.y = last_y;
}
在mian.c文件的主函數(shù)的死循環(huán)中添加自己的觸摸掃描函數(shù),以不斷更新tp_dev.x[0]和tp_dev.y[0]數(shù)值。
while (1)
{
tp_dev.scan(0); //觸摸掃描
lv_task_handler(); // lvgl的事務(wù)處理
}
至此,觸摸輸入移植完成,是不是依舊很簡單。
7.使用keypad_encoder DEMO綜合測試
在touch\lvgl目錄下新建demos文件夾,在此文件夾下新建lv_demo_keypad_encoder.c和lv_demo_keypad_encoder.h文件,復(fù)制以下代碼到這兩個(gè)新建的文件。
.c文件:
/**
* @file lv_demo_keypad_encoder.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_demo_keypad_encoder.h"
#include "lvgl.h"
#if 1
static void selectors_create(lv_obj_t * parent);
static void text_input_create(lv_obj_t * parent);
static void msgbox_create(void);
static void msgbox_event_cb(lv_event_t * e);
static void ta_event_cb(lv_event_t * e);
static lv_group_t* g;
static lv_obj_t * tv;
static lv_obj_t * t1;
static lv_obj_t * t2;
void lv_demo_keypad_encoder(void)
{
g = lv_group_create();
lv_group_set_default(g);
lv_indev_t* cur_drv = NULL;
for (;;) {
cur_drv = lv_indev_get_next(cur_drv);
if (!cur_drv) {
break;
}
if (cur_drv->driver->type == LV_INDEV_TYPE_KEYPAD) {
lv_indev_set_group(cur_drv, g);
}
if (cur_drv->driver->type == LV_INDEV_TYPE_ENCODER) {
lv_indev_set_group(cur_drv, g);
}
}
tv = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, LV_DPI_DEF / 3);
t1 = lv_tabview_add_tab(tv, "Selectors");
t2 = lv_tabview_add_tab(tv, "Text input");
selectors_create(t1);
text_input_create(t2);
msgbox_create();
}
/**********************
* STATIC FUNCTIONS
**********************/
static void selectors_create(lv_obj_t * parent)
{
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(parent, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_t * obj;
obj = lv_table_create(parent);
lv_table_set_cell_value(obj, 0, 0, "00");
lv_table_set_cell_value(obj, 0, 1, "01");
lv_table_set_cell_value(obj, 1, 0, "10");
lv_table_set_cell_value(obj, 1, 1, "11");
lv_table_set_cell_value(obj, 2, 0, "20");
lv_table_set_cell_value(obj, 2, 1, "21");
lv_table_set_cell_value(obj, 3, 0, "30");
lv_table_set_cell_value(obj, 3, 1, "31");
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_calendar_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_btnmatrix_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_checkbox_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_slider_create(parent);
lv_slider_set_range(obj, 0, 10);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_switch_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_spinbox_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_dropdown_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_roller_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
lv_obj_t * list = lv_list_create(parent);
lv_obj_update_layout(list);
if(lv_obj_get_height(list) > lv_obj_get_content_height(parent)) {
lv_obj_set_height(list, lv_obj_get_content_height(parent));
}
lv_list_add_btn(list, LV_SYMBOL_OK, "Apply");
lv_list_add_btn(list, LV_SYMBOL_CLOSE, "Close");
lv_list_add_btn(list, LV_SYMBOL_EYE_OPEN, "Show");
lv_list_add_btn(list, LV_SYMBOL_EYE_CLOSE, "Hide");
lv_list_add_btn(list, LV_SYMBOL_TRASH, "Delete");
lv_list_add_btn(list, LV_SYMBOL_COPY, "Copy");
lv_list_add_btn(list, LV_SYMBOL_PASTE, "Paste");
}
static void text_input_create(lv_obj_t * parent)
{
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_t * ta1 = lv_textarea_create(parent);
lv_obj_set_width(ta1, LV_PCT(100));
lv_textarea_set_one_line(ta1, true);
lv_textarea_set_placeholder_text(ta1, "Click with an encoder to show a keyboard");
lv_obj_t * ta2 = lv_textarea_create(parent);
lv_obj_set_width(ta2, LV_PCT(100));
lv_textarea_set_one_line(ta2, true);
lv_textarea_set_placeholder_text(ta2, "Type something");
lv_obj_t *kb = lv_keyboard_create(lv_scr_act());
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_event_cb(ta1, ta_event_cb, LV_EVENT_ALL, kb);
lv_obj_add_event_cb(ta2, ta_event_cb, LV_EVENT_ALL, kb);
}
static void msgbox_create(void)
{
static const char * btns[] = {"Ok", "Cancel", ""};
lv_obj_t * mbox = lv_msgbox_create(NULL, "Hi", "Welcome to the keyboard and encoder demo", btns, false);
lv_obj_add_event_cb(mbox, msgbox_event_cb, LV_EVENT_ALL, NULL);
lv_group_focus_obj(lv_msgbox_get_btns(mbox));
lv_obj_add_state(lv_msgbox_get_btns(mbox), LV_STATE_FOCUS_KEY);
#if LV_EX_MOUSEWHEEL
lv_group_set_editing(g, true);
#endif
lv_group_focus_freeze(g, true);
lv_obj_align(mbox, LV_ALIGN_CENTER, 0, 0);
lv_obj_t * bg = lv_obj_get_parent(mbox);
lv_obj_set_style_bg_opa(bg, LV_OPA_70, 0);
lv_obj_set_style_bg_color(bg, lv_palette_main(LV_PALETTE_GREY), 0);
}
static void msgbox_event_cb(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * msgbox = lv_event_get_current_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
const char * txt = lv_msgbox_get_active_btn_text(msgbox);
if(txt) {
lv_msgbox_close(msgbox);
lv_group_focus_freeze(g, false);
lv_group_focus_obj(lv_obj_get_child(t1, 0));
lv_obj_scroll_to(t1, 0, 0, LV_ANIM_OFF);
}
}
}
static void ta_event_cb(lv_event_t * e)
{
lv_indev_t * indev = lv_indev_get_act();
if(indev == NULL) return;
lv_indev_type_t indev_type = lv_indev_get_type(indev);
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * ta = lv_event_get_target(e);
lv_obj_t * kb = lv_event_get_user_data(e);
if(code == LV_EVENT_CLICKED && indev_type == LV_INDEV_TYPE_ENCODER) {
lv_keyboard_set_textarea(kb, ta);
lv_obj_clear_flag(kb, LV_OBJ_FLAG_HIDDEN);
lv_group_focus_obj(kb);
lv_group_set_editing(lv_obj_get_group(kb), kb);
lv_obj_set_height(tv, LV_VER_RES / 2);
lv_obj_align(kb, LV_ALIGN_BOTTOM_MID, 0, 0);
}
if(code == LV_EVENT_READY || code == LV_EVENT_CANCEL) {
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
lv_obj_set_height(tv, LV_VER_RES);
}
}
#endif
.h文件:
/**
* @file lv_demo_keypad_encoder.h
*
*/
#ifndef LV_DEMO_KEYPAD_ENCODER_H
#define LV_DEMO_KEYPAD_ENCODER_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_demo_keypad_encoder(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_DEMO_KEYPAD_ENCODER_H*/
在LVGL_DEMO組中添加lv_demo_keypad_encoder.c,并包含頭文件路徑。
在main中包含頭文件。
#include "lv_demo_keypad_encoder.h"
1
在初始化中調(diào)用demo接口,記得把之前的點(diǎn)燈注釋了。
// lv_example_led_1();//LED控件
lv_demo_keypad_encoder();
1
2
編譯下載,完美運(yùn)行,觸摸也好使。
再放一遍之前的圖,這是移植完的工程文件,適配正點(diǎn)原子精英板。
注意:
LVGL在github倉庫有的V8.2的版本,里面有相關(guān)的demo,別的demo如果編譯報(bào)錯,可以在startup_stm32f10x_hd.s文件中修改這兩個(gè)參數(shù)來增加棧空間,注意要選擇合適的參數(shù),本工程用的參數(shù)如下
Stack_Size EQU 0x00000400
Heap_Size EQU 0x00000200
1
2
至此,完成移植,收工。
五、總結(jié)
本文介紹了基于stm32f103zet6正點(diǎn)原子精英板移植LVGL的詳細(xì)過程,期間小編也遇到各種坑,比如移植完顯示之后屏幕一片漆黑,移植完觸控之后點(diǎn)了沒反應(yīng),這些小坑小編就先踩為敬。
當(dāng)你學(xué)會了移植,領(lǐng)悟了精髓,各種處理器,各種屏幕,各種輸入設(shè)備都不是問題。
例如如在esp32上跑,下圖是240X240分辨率的屏幕,輸入設(shè)備是一個(gè)mpu6050(三軸加速度傳感器)。
(下圖的電路參考 稚暉君大佬的HoloCubic)
六.參考文章:
正點(diǎn)原子 LittleVGL開源圖形界面 教程
STM32CubeMX學(xué)習(xí)筆記(40)——LVGL嵌入式圖形庫使用
【LVGL學(xué)習(xí)之旅 01】移植LVGL到STM32
lvgl8.x 移植到 stm32f4
GITCODE開源社區(qū)
七.代碼匯總:
移植前代碼:在觸摸實(shí)驗(yàn)的基礎(chǔ)上加了定時(shí)器中斷
移植后代碼:適配正點(diǎn)原子精英板
LVGL V8.0.2:本套教程使用的LVGL版
|
評分
-
查看全部評分
|