首先使用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 的问题了。