首先使用git獲取到源代碼和例子代碼
git clone https://github.com/littlevgl/lvgl.git
git clone https://github.com/littlevgl/lv_examples.git
也有其他項目,可以自己看看,下載需要的。
https://github.com/littlevgl
切換到發佈穩定版本的tag,目前的版本是 6.0,所以
git checkout v6.0
移植:
編譯器 Keil MDK 4.74
MCU Cortex M3
1,把 lv_conf_template.h 複製一份爲 lv_conf.h,放在上級目錄。
形成這個目錄結構
lv_conf.h
lvgl/
如果不想那樣,也可以把 lv_conf.h 拷貝到自己的項目目錄下
編譯器定義變量 LV_CONF_INCLUDE_SIMPLE 就可以了。
以下3個變量必須配置
#define LV_HOR_RES_MAX (320)
#define LV_VER_RES_MAX (240)
#define LV_COLOR_DEPTH 16
2,src 目錄下的各個子目錄都是源代碼,所有加入編譯
3,程序架構:
void DisplayThread(void)
{
/* Step1 */
lv_init();
/* Step 2 */
lv_port_disp_init();
/* Step 3 */
lv_port_indev_init();
/* Step 4 */
demo_create();
while (true) {
DelayMs(10);
/* Step 5 */
lv_tick_inc(10);
lv_task_handler();
}
}
這是基於RTOS的線程的 LittlevGL 的調用流程,步驟如下:
1,調用圖形庫的初始化 lv_init。
2,調用 lv_port_disp_init 初始化顯示芯片和接口,下面詳細介紹。
3,調用 lv_port_indev_init 初始化輸入設備和接口,例如觸摸屏,下面詳細介紹
4,設計具體的GUI界面,例如我們調用官方的demo程序 demo_create。
5,在一個循環中調用庫自己的處理函數,lv_tick_inc 是圖形庫的tick函數,你這個循環延時了多久就傳入多久
例如我這個循環是 10ms的,所以這裏傳10。這樣做比較簡單,當然也可以在 SysTick_Handler 裏面調用。
4,顯示驅動的移植
在 lvgl/port/lv_port_disp_template.c 文件就是顯示需要的接口文件
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];
disp_init();
lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 10);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = disp_flush;
disp_drv.buffer = &disp_buf_2;
lv_disp_drv_register(&disp_drv);
1)首先做 disp_init 硬件初始化。
2)使用1個或者2個buffer作爲顯示緩衝,這個buffer要求是多行像素點,例如
LV_HOR_RES_MAX * 10 是 10個像素點行。lvgl比較靈活,如果緩衝不夠,那麼只需要
傳入1個緩衝就可以,如果傳入2個緩衝,則可以使用雙緩衝機制,就是一個緩衝送到顯示芯片
另外一個緩衝可以繼續處理。
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*/
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)*/
color_p++;
}
}
/* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
然後需要實現一個刷新數據的函數,傳入的 color_p 是各個顏色點數據,只需要實現一個 put_px
把某個座標的顏色填進去就可以了。當然,這種實現是比較低效率的。可以自由發揮。
注意:
液晶屏,左上角是座標原點(0,0),如果不是,則需要轉換。
5,觸摸屏驅動的移植
在 lvgl/port/lv_port_indev_template.c 就是輸入設備的模版
其中觸摸屏是屬於
/*Initialize your touchpad if you have*/
touchpad_init();
/*Register a touchpad input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = touchpad_read;
indev_touchpad = lv_indev_drv_register(&indev_drv);
流程也是那樣,首先初始化觸摸板。
然後註冊進去系統。
static bool 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(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 `false` because we are not buffering and no more data to read*/
return false;
}
然後就是實現這個一個函數,如果觸摸板有按下,那麼讀取相應的座標返回。
注意
觸摸屏,左上角是座標原點(0,0),如果不是,則需要轉換。
6,如果驅動沒有問題,運行起來之後,就可以玩玩官方的延時程序了。
下載了 lv_examples 倉庫的話,可以看看裏面有很多例子。
遇到的問題,編譯報錯
..\..\gui\lvgl\src\lv_font\lv_font_roboto_16.c(1944):
error: #69: integer conversion resulted in truncation
由於默認的是 roboto_16 所以只有這個加入編譯,其實 roboto_12,roboto_22 一樣是有問題的。
/src/lv_font/lv_font_fmt_txt.h 裏面 lv_font_fmt_txt_dsc_t 定義
這裏莫名其妙,看了很久沒有發現問題,應該是 Keil 的bug 吧。
對位域的處理有問題
/*Scale kern values in 12.4 format*/
// uint16_t kern_scale;
/*Number of cmap tables*/
uint16_t cmap_num :10;
/*Bit per pixel: 1, 2, 4 or 8*/
uint16_t bpp :3;
/*Type of `kern_dsc`*/
uint16_t kern_classes :1;
/*
* storage format of the bitmap
* from `lv_font_fmt_txt_bitmap_format_t`
*/
uint16_t bitmap_format :2;
//xxxx
uint16_t kern_scale;
我將 kern_scale放到後面就可以編譯通過了。這裏沒有理由。
/*Scale kern values in 12.4 format*/
uint16_t kern_scale;
/*Number of cmap tables*/
uint16_t cmap_num;
/*Bit per pixel: 1, 2, 4 or 8*/
uint16_t bpp;
/*Type of `kern_dsc`*/
uint16_t kern_classes;
/*
* storage format of the bitmap
* from `lv_font_fmt_txt_bitmap_format_t`
*/
uint16_t bitmap_format;
或者不要位域,定義爲這樣也可以
GCC 應該是可以編譯通過的,所以我只能懷疑是 Keil 的問題了。