LVGL(Light and Versatile Graphics Library,輕巧而多功能的圖形庫)是一個免費的開放源代碼圖形庫,它提供建立具有易于使用的圖形元素,精美的視覺效果和低記憶體占用的嵌入式GUI所需的一切。作為嵌入式開發者,想移植到國産單片機中,N32G45X系列微控制器産品采用高性能32位ARM Cortex™-M4F核心,內建浮點運算單元(FPU)和數字信 号處理(DSP),支援并行計算指令。最高工作主頻144MHz,內建高達512KB加密存儲Flash并支援多使用者 分區管理,最大144KB SRAM,且可通過XFMC接口外擴FLASH和SRAM。内置一個内部高速AHB總線,二 個低速外設時鐘總線APB及總線矩陣,性能碉堡了,完全可以帶動LVGL任何元件,建立複雜絢麗的顯示。。
下面進入移植:
1、進行資料的準備:
由于IVGL主要用于互動界面,移植LVGL選擇一個屏:2.4寸液晶屏2.4寸TFT LCD SPI序列槽TFT彩屏240x320 驅動: ST7789,這種屏比較火。SPI四線驅動節省GPIO。不過不帶觸摸。
需要一個可以正常點亮LCD螢幕的驅動,屏的廠家有demo。基礎工作移植到國民的庫函數工程之中。IVGL源碼的配置檔案(野火,原子哥資料有源碼省事);還有為IVGL添加心跳節拍的定時器。
3、将檔案導入到keil工程中
在項目根目錄下建立 GUI 和 GUI_APP 兩個子目錄,和 USER 目錄是同級别的,GUI 目錄是用來存放IVGL庫相關的檔案,而 GUI_APP 是用來放 GUI 應用代碼的,重點是來介紹 GUI 目錄.
以上就是可以保證完成搭建IVGL的相關檔案。
目錄建立完成之後,把IVGL的配置檔案複制到GUI目錄下并解壓,解壓後删除壓縮封包件
注:01-中景園電子3.2LCD顯示屏STM32F103ZET6_并口FSMC例程\GUI此路徑為防止客戶浏覽過程比較混亂下文統一用template\GUI代表
複制此路徑下:template\GUI\lvgl中的lv_conf_template.h檔案和路徑:template\GUI\lv_examples中的lv_ex_conf_templ.h檔案,把以上兩個檔案複制到此路徑下:template\GUI;并把檔案名修改為lv_conf.h 和lv_ex_conf.h。接着還要在 template\GUI目錄下建立一個 lvgl_driver子目錄,這個目錄是用來 放底層顯示驅動和觸摸驅動檔案的,最後 template\GUI的目錄結構如下圖所示.
注:在實際項目中,可以删除掉 lv_examples 目錄來減少項目所占的磁盤空間,因為此目錄就是
專門用來存放官方的示範 demo,對我們的實際項目沒有任何作用。
接着我們打開 Keil 工程,點選
圖示,打開分組管理面闆,在 Groups 欄下建立 GUI 和
GUI_APP 倆個分組,選中 GUI 分組,接着點選 Add Files 按鈕,把
template\GUI\lvgl\src\lv_core
template\GUI\lvgl\src\lv_draw
template\GUI\lvgl\src\lv_font
template\GUI\lvgl\src\lv_hal
template\GUI\lvgl\src\lv_misc
template\GUI\lvgl\src\lv_objx
template\GUI\lvgl\src\lv_themes
所有目錄下的所有.c 檔案依次全部添加到 GUI 分組下面,最後如下圖所示最後點選 OK 按鈕儲存。
接着我們需要做 2 個比較重要的小操作,加大項目的棧空間到 2KB 和使能 C99 編譯器功能,打開 Core 分組下的.s 啟動檔案,修改 Stack_Size 的值到 2KB(0x00000800),如 Stack_Size EQU 0x00000800 所示,然後點選
圖示,打開面闆之後,切換到 C/C++面闆,選 中 C99 Mode 複選框即可,因為 IVGL要求 C99 或更新的編譯器,否則編譯是會報錯的,具體操作内容如下圖所示。
修改lv_conf.h和lv_ex_conf.h配置檔案
先打開 template\GUI 下的 lv_conf.h 檔案,裡面的配置項還是很多的,先不要糾結每個配置項到底什麼意思,大家先按照我的步驟來,我會對修改的部分會先進行一點簡單的介紹。打開lv_conf.h檔案之後進行如下修改如圖所示。
注:縮放比例的值在本教程中設定為60;動态配置設定空間的值修改為16U*1024U即16KB
注:以下宏定義使能為1不使能為0;
下面兩個修改為不使能;即修改為0
下面九個修改為使能;即修改為1;
完成以上修改之後lv_conf.h已經修改完畢,現在對lv_ex_conf.h這個檔案進行修改,如圖所示。
添加定時器為IVGL添加心跳節拍
本示範例程中采用定時器 3,設定其每隔 1ms 進入中斷,為IVGL提供 1ms 的心跳節拍,當然也可以采用其他的定時器,原理都是一樣的。然後在 main 函數中加入定時器的 TIM3_Int_Init(arr, psc)初始化代碼,必須保證中斷間隔為1ms,不同開發闆,傳入的 arr, psc 參數可能會不同的,請注意!把定時器中的TIMER檔案夾直接複制到HANDWARE檔案目錄下;如圖所示
然後打開keil點選
圖示将timer.c檔案添加到HANDWARE檔案夾内如圖所示
接着我們還需要配置Keil 中定時器和IVGL的頭檔案路徑,點選
圖示,面闆打開之後,切換到 C/C++面闆,點選 圖示,打開 Include Paths 面闆,添加頭檔案路徑,如下圖所示點選OK儲存
此時修改main函數中的内容,把定時器的頭檔案檔案以及對定時器初始化添加進去,修改之後如圖所示;(注:在移植LCD 串行SPI的例程的時候需要先找到如下檔案并引用定時器有關的頭檔案否則會報錯)修改很簡單取消注釋就可以了
此時進行編譯會産生很多警告,
此時仔細看其實就隻有 68, 111, 550 這三種警告,我可以告訴大家,這個警告對我們項目沒有任何影響的;不過Keil 可以通過設定,把某種警告給屏蔽掉,點選
圖示,切換到 C/C++頁籤,在 Misc Controls 中填入--diag_suppress=68 --diag_suppress=111 --diag_suppress=550;如圖所示:
然後再進行編譯如下圖所示;可以看到0 error 0 warning;
完成以上操作并沒有産生錯誤之後開始移植底層顯示驅動。
移植底層顯示驅動
官方給我們提供了顯示驅動,輸入驅動,檔案系統驅動的模闆檔案,存放在 template\GUI\lvgl\porting 目錄下,這裡我們不需要檔案系統,是以隻需要把
lv_port_disp_template.c,
lv_port_disp_template.h,
lv_port_indev_template.c,
lv_port_indev_template.h
四個檔案拷 貝到 template\GUI\lvgl_driver 目錄下面,并分别重命名為lv_port_disp.c, lv_port_disp.h, lv_port_indev.c, lv_port_indev.h,前面 2 個檔案是跟顯示驅動相關的,後面倆個檔案是跟觸摸驅動相
關的,我們先隻需要修改 lv_port_disp.c, lv_port_disp.h 倆個檔案的内容就可以了,在這裡直接貼出正确代碼可以直接複制
lv_port_disp.h修改如下:
#if 1
#ifndef LV_PORT_DISP_H
#define LV_PORT_DISP_H
#ifdef __cplusplus
extern "C" {
#endif
#include "lvgl/lvgl.h"
void lv_port_disp_init(void);
#ifdef __cplusplus
}
#endif
#endif
#endif
lv_port_disp.c修改如下
#if 1
#include "lv_port_disp.h"
#include "lcd.h"
static void disp_init(void);
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
#if LV_USE_GPU
static void gpu_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
static void gpu_fill(lv_color_t * dest, uint32_t length, lv_color_t color);
#endif
void lv_port_disp_init(void)
{
disp_init();
static lv_disp_buf_t disp_buf_1;
static lv_color_t buf1_1[LV_HOR_RES_MAX * 10];
lv_disp_buf_init(&disp_buf_1, buf1_1, NULL, LV_HOR_RES_MAX * 10);
//
// static lv_disp_buf_t disp_buf_2;
// static lv_color_t buf2_1[LV_HOR_RES_MAX * 10];
// static lv_color_t buf2_2[LV_HOR_RES_MAX * 10];
// lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 10);
//
//
// static lv_disp_buf_t disp_buf_3;
// static lv_color_t buf3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX];
// static lv_color_t buf3_2[LV_HOR_RES_MAX * LV_VER_RES_MAX];
// lv_disp_buf_init(&disp_buf_3, buf3_1, buf3_2, LV_HOR_RES_MAX * LV_VER_RES_MAX);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = lcddev.width;
disp_drv.ver_res = lcddev.height;
disp_drv.flush_cb = disp_flush;
disp_drv.buffer = &disp_buf_1;
#if LV_USE_GPU
disp_drv.gpu_blend = gpu_blend;
disp_drv.gpu_fill = gpu_fill;
#endif
lv_disp_drv_register(&disp_drv);
}
static void disp_init(void)
{
}
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(u16*)color_p);
lv_disp_flush_ready(disp_drv);
}
#if LV_USE_GPU
static void gpu_blend(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)
{
uint32_t i;
for(i = 0; i < length; i++) {
dest = lv_color_mix(dest, src, opa);
}
}
static void gpu_fill_cb(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
const lv_area_t * fill_area, lv_color_t color);
{
uint32_t x, y;
dest_buf += dest_width * fill_area->y1;
for(y = fill_area->y1; y < fill_area->y2; y++) {
for(x = fill_area->x1; x < fill_area->x2; x++) {
dest_buf[x] = color;
}
dest_buf+=dest_width;
}
uint32_t i;
for(i = 0; i < length; i++) {
dest = color;
}
}
#endif
#else
typedef int keep_pedantic_happy;
#endif
相關介紹如下:
不同螢幕LCD_Color_FIll函數需要對應重新編寫;可以本示例LCD螢幕做參考;
移植底層觸摸驅動
(注:如果沒有觸摸功能可以跳過此過程)
lv_port_indev.h修改如下:
lv_port_indev.c修改如下:
(注:由于此驅動是基于LCD觸摸螢幕的是以其他輸入方式的全部删除了)
#include "lv_port_indev.h"
#include "touch.h"
static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
void lv_port_indev_init(void)
{
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = touchpad_read;
lv_indev_drv_register(&indev_drv);
}
static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
//u16 lastpos[2];//最後一次的資料
//lastpos[0]=0xffff;
static uint16_t last_x = 0;
static uint16_t last_y = 0;
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;
}
return false;
}
将修改好的底層驅動添加到keil工程中
打開keil點選
圖示将lv_port_disp.c檔案和lv_port_indev.c檔案(沒有觸摸功能的螢幕可以忽略此檔案)和添加到GUI檔案夾内如圖所示
因為lv_port_disp.h檔案和lv_port_indev.h檔案是在GUI目錄下的;上面已經對GUI的頭檔案路徑添加過了是以此處不需要二次添加。
移植官方例程進行示範
現在我們隻需要把官方的示範例程代碼添加到 Keil 工程中的 GUI_APP分組下就可以了,官方的例程源碼全部位于template\GUI\lv_examples目錄下我們把 demo例程按照上面所描述的源碼路徑添加到 Keil 中的 GUI_APP 分組下如圖所示:
此時需要GUI_APP添加頭檔案路徑,,點選
圖示,面闆打開之後,切換到 C/C++面闆,點選 圖示,打開 Include Paths 面闆,添加頭檔案路徑,如下圖所示點選OK儲存
此時修改main函數把相關檔案導入進去
進行編譯之後會發現有錯誤:錯誤詳情如下
這是因為官方的 demo 例程有一個小疏 忽,我們打開 GUI_APP 分組下的 demo.c 檔案,把 a.user_data = NULL;的代碼給删除掉就行了, 總共有 2 處,分别是在 215 行和 249 行.修改之後進行編譯0 error 0 warning此時進行燒錄就可以看到demo的示範效果了。
IVGL移植成功示範
---------------------
作者:abner_ma
連結:https://bbs.21ic.com/icview-3281162-1-1.html
來源:21ic.com
此文章已獲得原創/原創獎标簽,著作權歸21ic所有,任何人未經允許禁止轉載。