Linux 環境中使用 LVGL

2022-12-29 15:00:50

之前有記錄過在 esp32 中使用 LVGL 的筆記,需要的小夥伴可以瞭解一下,esp-idf 移植 lvgl8.3.3
我之前整理的學習資料:https://www.cnblogs.com/jzcn/p/16647106.html

一、準備材料

開發板:一塊 linux 的開發板 或 linux 的虛擬機器器
lvgl:8.3.3
系統:ubuntu 18.04

注意:在 linux 環境下使用 lvgl 就相對比較簡單了,這裡記錄了兩個方式。

二、方式一

因為 linux 環境下,官方已經簡歷好專案的,所以只需要直接拉取就好了。
倉庫地址:https://github.com/lvgl/lv_port_linux_frame_buffer

  1. git 命令

    git clone --recursive https://github.com/lvgl/lv_port_linux_frame_buffer.git
    # 如果拉取不下來,可以使用下面的加速地址,我也不知道是否會失效
    https://github.moeyy.xyz/https://github.com/lvgl/lv_port_linux_frame_buffer.git
    
    

    注意:拉取的時候已經要加 --recursive,否則專案中的子工程拉不下來,如果拉取時忘記加 --recursive 引數,可以在拉取完成是使用 git submodule update --init --recursive 命令更新一下即可。

  2. 工程目錄
    拉取完成後,工程目錄如下所示:

  3. 編譯工程
    直接使用 make 命令編譯即可,完成後如下圖所示:會直接生成可執行檔案,如下圖所示:

    注意: 發現可執行檔案後,基本就完成了,直接執行即可,./demo ,毫無疑問基本會執行失敗,結果如下圖所示:

  4. 修改顯示驅動
    這裡的顯示驅動都是使用的 Framebuffer 緩衝區,我之間有個簡單的筆記使用,不瞭解的小夥伴,可以看我之前的筆記,Linux Framebuffer 實驗,知道自己的緩衝區裝置後,就可以直接在檔案 lv_drv_conf.h 中進行修改,不過多數情況下都是 /dev/fb0 可以不用修改,如下圖所示:

  5. 修改滑鼠或觸控驅動
    在修改滑鼠或觸控驅動時,需要藉助 evtest 工具,找到自己裝置的輸入事件。

    • 安裝 evtset 工具

      sudo apt-get install evtest
      
    • 使用命令 sudo evtest 找到對應的事件編號,如下圖所示:

    找到滑鼠事件後,直接在 lv_drv_conf.h 檔案中,更改對應的事件編號即可,如下圖所示:

  6. 執行測試
    完成驅動修改後,重新編譯測試,因為使用的是 Framebuffer 緩衝區,所以在 ubuntu 緩衝區中使用是,需要關閉圖形顯示後,才是正常使用 Framebuffer ,命令如下

    # 關閉圖形顯示
    systemctl set-default multi-user.target
    reboot
    
    # 開啟圖形顯示
    systemctl set-default graphical.target
    reboot
    

    關閉圖形顯示後,測試結果如下圖所示:

三、方式二

上面我們已經完成了,在 ubuntu 中測試 LVGL 操作還是比較簡單的,現在我們開始嘗試手動建立工程,並將編譯後生成的.o檔案放到指定目錄下,然後更改編譯工具,使其在arm開發板中進行使用。

注意: 在建立過程中,有什麼問題可以直接參考上面的工程,可以解決我們過程中遇到的問題

  1. 下載 LVGL

  2. 建立工程目錄
    這裡我就不詳細說明了,直接上圖,只要檔案目錄如圖所示一樣即可,路徑圖下圖所示:

  3. 將 lvgl 移動到 lib 檔案下,並刪除多餘的檔案,如下圖所示:

    注意:其中的 lv_conf.h 檔案是直接將 lv_conf_template.h 拷貝後進行重新命名的,完成後將檔案中的 #if 0 改為 #if 1

  4. 將 lvgl 目錄下的 demos 檔案拷貝到 lib 檔案下,如下圖所示:

    注意:這裡為了 demos 使用中減少問題,我直接拷貝了 lvgl 檔案下的 demos 並重新命名為 lv_demos

  5. 將 lv_drivers 拷貝到 lib 檔案下,並刪除多餘的檔案,如下圖所示:

    注意:其中 lv_drv_conf.h 檔案是拷貝 lv_drv_conf_template.h 檔案重新命名後得到的,完成後將檔案中的 #if 0 改為 #if 1

  6. 將 lvgl 目錄下的 examples 檔案拷貝到 lib 檔案下,如下圖所示:

  7. 在 application 檔案下建立 main.c 檔案,內容如下:

    #include "lvgl.h"
    #include "../lib/lv_demos/lv_demos.h"
    #include "../lib/lv_drivers/display/fbdev.h"
    #include "../lib/lv_drivers/indev/evdev.h"
    #include <unistd.h>
    #include <pthread.h>
    #include <time.h>
    #include <sys/time.h>
    
    #define DISP_BUF_SIZE (128 * 1024)
    
    int main(void)
    {
        /*LittlevGL init*/
        lv_init();
    
        /*Linux frame buffer device init*/
        fbdev_init();
    
        /*A small buffer for LittlevGL to draw the screen's content*/
        static lv_color_t buf[DISP_BUF_SIZE];
    
        /*Initialize a descriptor for the buffer*/
        static lv_disp_draw_buf_t disp_buf;
        lv_disp_draw_buf_init(&disp_buf, buf, NULL, DISP_BUF_SIZE);
    
        /*Initialize and register a display driver*/
        static lv_disp_drv_t disp_drv;
        lv_disp_drv_init(&disp_drv);
        disp_drv.draw_buf   = &disp_buf;
        disp_drv.flush_cb   = fbdev_flush;
        disp_drv.hor_res    = 800;
        disp_drv.ver_res    = 480;
        lv_disp_drv_register(&disp_drv);
    
        evdev_init();
        static lv_indev_drv_t indev_drv_1;
        lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/
        indev_drv_1.type = LV_INDEV_TYPE_POINTER;
    
        /*This function will be called periodically (by the library) to get the mouse position and state*/
        indev_drv_1.read_cb = evdev_read;
        lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1);
    
    
        /*Set a cursor for the mouse*/
        LV_IMG_DECLARE(mouse_cursor_icon)
        lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
        lv_img_set_src(cursor_obj, &mouse_cursor_icon);           /*Set the image source*/
        lv_indev_set_cursor(mouse_indev, cursor_obj);             /*Connect the image  object to the driver*/
    
    
        /*Create a Demo*/
        lv_demo_widgets();
    
        /*Handle LitlevGL tasks (tickless mode)*/
        while(1) {
            lv_timer_handler();
            usleep(5000);
        }
    
        return 0;
    }
    
    /*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/
    uint32_t custom_tick_get(void)
    {
        static uint64_t start_ms = 0;
        if(start_ms == 0) {
            struct timeval tv_start;
            gettimeofday(&tv_start, NULL);
            start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
        }
    
        struct timeval tv_now;
        gettimeofday(&tv_now, NULL);
        uint64_t now_ms;
        now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;
    
        uint32_t time_ms = now_ms - start_ms;
        return time_ms;
    }
    
    
  8. 拷貝滑鼠檔案 mouse_cursor_icon.c
    將方式一中獲取到的滑鼠檔案拷貝到 application 檔案下

  9. 在 lib 目錄下建立 lib.mk 檔案,內容如下:

    ##################################### lvgl庫 #####################################
    # 檔案路徑
    LVGL_DIR ?= $(PROJECT_PATH)/lib
    
    # 所需的宏定義
    CFLAGS += -DLV_CONF_INCLUDE_SIMPLE
    CFLAGS += -DLV_LVGL_H_INCLUDE_SIMPLE
    # lvgl庫
    LVGL_DIR_NAME ?= lvgl
    
    # 所需標頭檔案的路徑
    CFLAGS += -I$(LVGL_DIR)/lvgl
    
    # 收集需要編譯的原始檔
    include $(LVGL_DIR)/lv_demos/lv_demos.mk
    include $(LVGL_DIR)/lv_examples/lv_examples.mk
    include $(LVGL_DIR)/lv_drivers/lv_drivers.mk
    include $(LVGL_DIR)/$(LVGL_DIR_NAME)/lvgl.mk
    
  10. 在主目錄下建立 Makefile 檔案,內容如下:

    #
    # Makefile
    # 編譯的.o檔案和.c檔案在同一路徑下
    #
    
    $(info "start...")
    # 可執行檔名
    PROJECT_NAME = lvgl_app
    
    ##################################### 專案路徑 #####################################
    PROJECT_PATH ?= ${shell pwd}
    OBJ_DIR := $(PROJECT_PATH)/build
    
    ##################################### 設定編譯器,預設使用GCC #####################################
    CC = arm-linux-gnueabihf-gcc
    CC ?= gcc
    
    ##################################### 所需標頭檔案的路徑 #####################################
    # lv_conf.h
    CFLAGS += -I$(PROJECT_PATH)/lib/lvgl
    # lv_drv_conf.h
    CFLAGS += -I$(PROJECT_PATH)/lib/lv_drivers
    
    ##################################### 編譯和連結引數 #####################################
    CFLAGS ?= -O3 -g0 -Wall -Wshadow -Wundef -Wmissing-prototypes -Wno-discarded-qualifiers -Wextra -Wno-unused-function \
    -Wno-error=strict-prototypes -Wpointer-arith -fno-strict-aliasing -Wno-error=cpp -Wuninitialized -Wmaybe-uninitialized \
    -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral \
    -Wno-cast-qual -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wformat-security -Wno-ignored-qualifiers \
    -Wno-error=pedantic -Wno-sign-compare -Wno-error=missing-prototypes -Wdouble-promotion -Wclobbered -Wdeprecated -Wempty-body \
    -Wshift-negative-value -Wstack-usage=2048 -Wno-unused-value
     
    LDFLAGS ?= -lm
    
    ##################################### 收集需要編譯的原始檔 #####################################
    CSRCS += $(PROJECT_PATH)/application/main.c
    CSRCS += $(PROJECT_PATH)/application/mouse_cursor_icon.c
    include $(PROJECT_PATH)/lib/lib.mk
    
    
    ##################################### 將檔名替換為.o檔案 #####################################
    AOBJS = $(ASRCS:.S=.o)
    COBJS = $(CSRCS:.c=.o)
    # CXX_SOURCES = $(foreach dir,$(CSRCS), $(wildcard $(dir)/*.c))
    # CXX_OBJCTS = $(patsubst  %.c, $(OBJ_DIR)/%.o, $(CSRCS))
    
    all: default
    
    %.o: %.c
    	@$(CC)  $(CFLAGS) -c $< -o $@
    	#@echo "CC $<"
        
    default: $(COBJS)
    	$(CC) -o $(PROJECT_NAME)  $(COBJS) $(AOBJS) $(LDFLAGS)
    
    clean: 
    	rm -f $(PROJECT_NAME) $(COBJS) $(AOBJS)
    
    

注意: 到此工程檔案已經建立好了,接下來只需要解決我們工程放置檔案路徑導致的問題即可,目錄結構如下圖所示:

  1. 修改 lib/lv_demos/lv_demos.mk 檔案內容如下:

    CSRCS += $(shell find -L $(LVGL_DIR)/lv_demos -name "*.c")
    
  2. 修改 lib/lv_examples/lv_examples.mk 檔案,內容如下:

    CSRCS += $(shell find -L $(LVGL_DIR)/lv_examples -name \*.c)
    
  3. 修改 lib/lvgl/lvgl.mk

  4. 啟動相應的功

    • USE_FBDEV:在檔案 lv_drv_conf.h 中
    • USE_EVDEV:在檔案 lv_drv_conf.h 中
    • LV_USE_DEMO_WIDGETS:在檔案 lv_conf.h,主要作用是啟動相應的案例
  5. 在編譯的過程中會有 lvgl.h 標頭檔案的參照錯誤。如下所示:

    #include "../../../lvgl.h"
    

    這是因為我們移動路徑導致的,所以只需要將所以檔案參照改為 #include "lvgl.h" 即可

注意:到此我們自己在 Linux 環境下建立的 LVGL 工程就已經完成了,這裡自己建立 lvgl 的目的主要是方便版本的選擇,可以根據自己的需要選擇相應的 LVGL 版本。

四、指定 .o 檔案的存放路徑

上面的工程中會發現編譯生成的.o檔案和.c檔案是在同一路徑下的,那麼在實際開發中有不方便之處,所以將.o檔案指定到build檔案下,操作比較簡單,只需要將 Makefile 檔案進行更改即可,如下所示:

Makefile 檔案

#
# Makefile
# 編譯的.o檔案和.c檔案在同一路徑下
#

$(info "start...")
# 可執行檔名
PROJECT_NAME = lvgl_app

##################################### 專案路徑 #####################################
PROJECT_PATH ?= ${shell pwd}
OBJ_DIR := $(PROJECT_PATH)/build

##################################### 設定編譯器,預設使用GCC #####################################
CC = arm-linux-gnueabihf-gcc
CC ?= gcc

##################################### 所需標頭檔案的路徑 #####################################
# lv_conf.h
CFLAGS += -I$(PROJECT_PATH)/lib/lvgl
# lv_drv_conf.h
CFLAGS += -I$(PROJECT_PATH)/lib/lv_drivers

##################################### 編譯和連結引數 #####################################
CFLAGS ?= -O3 -g0 -Wall -Wshadow -Wundef -Wmissing-prototypes -Wno-discarded-qualifiers -Wextra -Wno-unused-function \
-Wno-error=strict-prototypes -Wpointer-arith -fno-strict-aliasing -Wno-error=cpp -Wuninitialized -Wmaybe-uninitialized \
-Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral \
-Wno-cast-qual -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wformat-security -Wno-ignored-qualifiers \
-Wno-error=pedantic -Wno-sign-compare -Wno-error=missing-prototypes -Wdouble-promotion -Wclobbered -Wdeprecated -Wempty-body \
-Wshift-negative-value -Wstack-usage=2048 -Wno-unused-value
 
LDFLAGS ?= -lm

##################################### 收集需要編譯的原始檔 #####################################
CSRCS += $(PROJECT_PATH)/application/main.c
CSRCS += $(PROJECT_PATH)/application/mouse_cursor_icon.c
include $(PROJECT_PATH)/lib/lib.mk


##################################### 將檔名替換為.o檔案 #####################################
CXX_OBJCTS = $(patsubst  %.c, $(OBJ_DIR)/%.o, $(notdir $(CSRCS)))
SOURSE_DIR = $(dir $(CSRCS))

vpath %.c $(SOURSE_DIR)

$(OBJ_DIR)/%.o: %.c
	@$(CC) $(CFLAGS) -c $< -o $@
	#@echo "CC $<"

all: $(CXX_OBJCTS)
	@$(CC) -o $(PROJECT_NAME)  $(CXX_OBJCTS) $(LDFLAGS)

clean: 
	@rm -f $(PROJECT_NAME) $(CXX_OBJCTS)

筆記到此結束,有寫得不好的地方望各位大佬指出