寫(xiě)在前面:本菜鳥(niǎo)結(jié)合了許多大佬的文章,成功實(shí)現(xiàn)了基于LVGL的GUI設(shè)計(jì),小開(kāi)心~淺淺記錄一下!~
本文以單片機(jī)STM32F103VET6為核心,利用ST7796芯片驅(qū)動(dòng)分辨率為480*320的LCD液晶屏模塊,移植LVGL,對(duì)接顯示接口,對(duì)接外部接口——旋轉(zhuǎn)編碼器,完成以上兩步,就可以實(shí)現(xiàn)LVGL的顯示和控制啦!Emmm可以開(kāi)始你的創(chuàng)作了!~
一、顯示接口對(duì)接
具體步驟:
下載源碼文件lvgl-master8.3進(jìn)行移植
這里我們以LCD顯示工程為基礎(chǔ)進(jìn)行移植。
1.新建四個(gè)組,分別存放源文件(source)、配置文件(config)、接口層文件(port)、示例(app)。
2.添加文件,lvgl/src下的.c文件移到source中,lv.conf.h添加到config中,lv_port_xxx.c文件添加到port中,示例文件添加到app中。
3.添加路徑,勾選C99,此時(shí)進(jìn)行編譯會(huì)有四個(gè)錯(cuò)誤,因?yàn)镃99的原因,在部分函數(shù)前要加static,否則會(huì)報(bào)錯(cuò),再進(jìn)行編譯會(huì)發(fā)現(xiàn)還有一個(gè)錯(cuò)誤:

解決方法是取消勾選Use MicroLIB,再編譯就會(huì)發(fā)現(xiàn)零錯(cuò)誤。
4.lv_conf.h配置:主要是一些宏定義,只需要修改一些宏定義即可進(jìn)行一些定制配置,如顯示器的寬度高度、色彩深度、DPI、提供給LVGL的空間等,可根據(jù)自己的需求打開(kāi)即可使用。
5.修改lv_port_disp.c接口文件:
使能后開(kāi)始對(duì)其進(jìn)行配置,修改頭文件名稱(chēng)并添加LCD頭文件,添加兩個(gè)宏,分別是屏幕的寬(480)和高(320)。
修改lv_port_disp_init()顯示接口初始化函數(shù),它是一個(gè)最頂層的初始化顯示設(shè)備的函數(shù)。然后選擇一種寫(xiě)緩存的方式及設(shè)置顯示分辨,這里我們選擇保留第一種寫(xiě)緩存的方式:只使用一個(gè)緩沖區(qū)
/* Example for 1) */
static lv_disp_draw_buf_t draw_buf_dsc_1;
static lv_color_t buf_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);
該文件內(nèi)還有兩個(gè)函數(shù)disp_init()和disp_flush()。在disp_init()中,需要提供屏幕的初始化代碼,這里直接調(diào)用驅(qū)動(dòng)成功的LCD模塊初始化代碼LCD_init()。接下來(lái)是disp_flush屏幕刷新函數(shù),這個(gè)函數(shù)需要調(diào)用底層LCD的操作接口,這里調(diào)用一個(gè)畫(huà)點(diǎn)的函數(shù),因?yàn)槠聊皇侵饌€(gè)繪制像素點(diǎn),從而填充一塊區(qū)域的,所以也可以直接調(diào)用一個(gè)繪制方形函數(shù)填充區(qū)域顯示。
/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
/*You code here*/
LCD_Init();
}
/*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.*/
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_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*/
int32_t x;
int32_t y;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
/*Put a pixel to the display. For example:*/
/*put_px(x, y, *color_p)*/
LCD_DrawPoint(x,y,color_p->full);
color_p++;
}
}
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
6.最后需要配置一個(gè)定時(shí)器為L(zhǎng)VGL提供心跳,這里可以使用系統(tǒng)滴答定時(shí)器,也可以使用其他定時(shí)器配置,然后在主循環(huán)中調(diào)用lv_task_handler()函數(shù),這樣需要顯示的內(nèi)容才會(huì)實(shí)時(shí)更新到屏幕上,至此LVGL的顯示配置完成。
while(1)
{
lv_tick_inc(5);
lv_task_handler();
delay_ms(5);
}
二、旋轉(zhuǎn)編碼器接口對(duì)接
首先在lv_port_indev.c的接口初始化中保留Encoder部分,在encoder_init()中編寫(xiě)旋轉(zhuǎn)編碼器相關(guān)的初始化代碼,再指定用于讀取按鍵狀態(tài)的函數(shù)encoder_read,將旋轉(zhuǎn)編碼器注冊(cè)到LVGL中。最后對(duì)encoder相關(guān)函數(shù)進(jìn)行編寫(xiě),主要是encoder_read,分為三種情形,分別是旋轉(zhuǎn)編碼器左旋、右旋和按下時(shí)對(duì)應(yīng)控制界面的功能。
void lv_port_indev_init(void)
{
/**
* Here you will find example implementation of input devices supported by LittelvGL:
* - Touchpad
* - Mouse (with cursor support)
* - Keypad (supports GUI usage only with key)
* - Encoder (supports GUI usage only with: left, right, push)
* - Button (external buttons to press points on the screen)
*
* The `..._read()` function are only examples.
* You should shape them according to your hardware
*/
static lv_indev_drv_t indev_drv;
/*------------------
* Encoder
* -----------------*/
/*Initialize your encoder if you have*/
encoder_init();
/*Register a encoder input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_ENCODER;
indev_drv.read_cb = encoder_read;
indev_encoder = lv_indev_drv_register(&indev_drv);
/*Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
*add objects to the group with `lv_group_add_obj(group, obj)`
*and assign this input device to group to navigate in it:
*`lv_indev_set_group(indev_encoder, group);`*/
lv_group_t * group= lv_group_create();
lv_indev_set_group(indev_encoder, group);
/*------------------
* Encoder
* -----------------*/
/*Initialize your keypad*/
static void encoder_init(void)
{
/*Your code comes here*/
Encoder_Init();
}
/*Will be called by the library to read the encoder*/
static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static uint32_t last_key = 0;
uint32_t act_key = Encoder_Scan(0);
if(act_key != 0) {
switch(act_key) {
case 1:
act_key = LV_KEY_ENTER;
encoder_state = LV_INDEV_STATE_PR;
break;
case 2:
act_key = LV_KEY_LEFT;
encoder_diff = -1;
encoder_state = LV_INDEV_STATE_REL;
break;
case 3:
act_key = LV_KEY_RIGHT;
encoder_state = LV_INDEV_STATE_REL;
encoder_diff = 1;
break;
}
last_key = act_key;
}
else{
encoder_diff = 0;
encoder_state = LV_INDEV_STATE_REL;
}
data->key = last_key;
data->enc_diff = encoder_diff;
data->state = encoder_state;
encoder_diff=0;
}
/*Call this function in an interrupt to process encoder events (turn, press)*/
static void encoder_handler(void)
{
/*Your code comes here*/
encoder_diff += 0;
encoder_state = LV_INDEV_STATE_REL;
}
與其他輸入設(shè)備接口不同的是,旋轉(zhuǎn)編碼器較特殊,光移植完還無(wú)法使用,如需使用還要?jiǎng)?chuàng)建“組”。這里引入“組”這一概念,當(dāng)需要用鍵盤(pán)或者編碼器來(lái)模擬按鍵控制對(duì)象時(shí),就需要把控制對(duì)象添加進(jìn)“組”。例如,如果一個(gè)旋鈕被聚焦,當(dāng)向左或向右旋轉(zhuǎn)編碼器時(shí),旋鈕的值會(huì)隨之改變。這種操作的前提便是將輸入設(shè)備與“組”關(guān)聯(lián)起來(lái),即通過(guò)lv_group_add_obj()函數(shù)將控件添加進(jìn)“組”,才能實(shí)現(xiàn)編碼器與LVGL接口對(duì)接和實(shí)現(xiàn)界面控制。但是需要注意的是,并非所有控件都能夠加入“組”并且被使用。比如我們添加“標(biāo)簽”這個(gè)控件時(shí),即使將它加入到“組”中,用編碼器旋轉(zhuǎn)聚焦時(shí)也不會(huì)切換到這個(gè)“標(biāo)簽”。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-687025.html
將所需控件加入“組”旋轉(zhuǎn)編碼器即可正常使用,即可完成編碼器接口與LVGL的對(duì)接。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-687025.html
到了這里,關(guān)于STM32移植LVGL+旋轉(zhuǎn)編碼器接口對(duì)接的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!