一、前言
littlevgl是一个小型开源嵌入式 GUI 库(简称LVGL),界面精美,消耗资源小,可移植度高,支持响应式布局,全库采用纯 c 语言开发,移植上手简单。
littleVGL 的主要特性如下:
• 具有非常丰富的内置控件,像 buttons, charts, lists, sliders, images 等
• 高级图形效果:动画,反锯齿,透明度,平滑滚动
• 支持多种输入设备,像 touchpad, mouse, keyboard, encoder 等
• 支持多语言的 UTF-8 编码
• 支持多个和多种显示设备,例如同步显示在多个彩色屏或单色屏上
• 完全自定制的图形元素
• 硬件独立于任何微控制器或显示器
• 可以缩小到最小内存 (64 kB Flash, 16 kB RAM)
• 支持操作系统、外部储存和 GPU(非必须)
• 仅仅单个帧缓冲设备就可以呈现高级视觉特效
• 使用 C 编写以获得最大兼容性(兼容 C++)
• 支持 PC 模拟器
• 为加速 GUI 设计,提供教程,案例和主题,支持响应式布局
• 提供了在线和离线文档
• 基于自由和开源的 MIT 协议
效果图以及更多详细的说明请见官网
littlevgl中文官网:https://littlevgl.cn/
littlevgl英文官网:https://lvgl.io/
二、学习资料
- 官方文档:https://docs.lvgl.io/latest/en/html/index.html(注:官网打不开的话可能会需要梯子)
- Github: https://github.com/lvgl/lvgl
三、移植前的准备工作
开发环境:
- Keil MDK5 v5.28
- ARM Compiler 6.0版本或以上
关于编译器,老版本的5.x编译器也能编译,但是新的6版本的编译器在编译速度与效率上有很大的提升,并且解决了一些莫名其妙的bug,强烈建议升级到6版本的编译器。笔者使用的版本是v6.14.1。
硬件:
- STM32开发板
- 屏幕一块(单色点阵屏或者是LCD彩屏都可以)
笔者使用的开发板是正点原子的战舰V3开发板,芯片是STM32F103ZET6,72M主频+512k flash+64k ram,这样的性能足够跑LVGL了,当然,你的芯片性能越高肯定越好。哦,板上还外挂了一颗1M字节的SRAM,这对提升性能很有帮助。如果你用的不是这款芯片或者这块开发板,那也没关系,笔者会详细指出移植过程中不同的芯片移植需要注意的地方。
获取源码:
源码地址:https://github.com/lvgl/lvgl
源码有很多的发行版,不同的发行版对应着不同的LVGL版本,注意不同的版本之间是不同的,比如版本V6与版本V7之间就变化很大,具体的版本变化信息可以看它的release note,这里我以v7.1.0版本为例来移植,并且今后的学习都会使用这个版本。
打开下载好的文件夹
我们重点关注src/目录和lv_conf_template.h, lvgl.h 这几个文件,其它的暂时不用管。
准备模板工程:
- 为你的开发板准备好一个模板工程
要求:这个模板工程至少能够驱动一块屏幕(做GUI必须得有屏幕呀= =)
如果你的屏幕带有触摸功能,那你的工程还需要有触摸屏的驱动,其实触摸屏驱动需要但非必须,没有触摸功能的话你也可以做一些展示的界面。事实上LVGL也支持键盘,鼠标,触控板等外设,因为在LVGL核心那里,它会将这些全部抽象为输入设备,它只需要从输入设备那里取得数据,并不关心你所用的是何种设备。
当然,触摸屏已经用得相当广泛,笔者使用的屏幕同样是正点原子家开发板配套的屏幕,型号:4.3英寸MCU屏,800*480分辨率,带电容触摸功能,其接口为16位并口,驱动IC:NT35510,触摸控制IC:GT9147,触摸控制接口为IIC。
因此我需要提前准备好并且测试好这些驱动,对于屏幕控制器,除了初始化API(就是函数),还需要提供填充LCD的API,像这样:
LCD_Color_Fill(x1,y1,x2,y2,(u16*)color_p);
(x1,y1), (x2,y2)为俩坐标点,color_p为显存指针,该API要实现的功能为:将显存区域内的像素数据点,依次填充到以(x1,y1)为起点, (x2,y2)为重点的对角矩形区域内。
注意,这个API是LVGL渲染屏幕的唯一API,哈哈哈简单吧。同样LVGL内部也不关心使用的何种屏幕,他们之间仅通过一个填充色块儿的API耦合,这种高内聚、低耦合的模块儿化设计思想是非常值得我们学习借鉴的。
四、开始移植
①修改MDK工程(默认你已经会使用keil了)
用keil mdk打开我们的模板工程,添加4个Groups:GUI_core, GUI_drv, GUI_demo, GUI_app,这些组用于添加我们的c代码到工程中,不同的组名意味着会存放不同功能的c代码。(注意:工程中的组与实际文件目录并不相同)
- GUI_core:GUI核心文件层
- GUI_drv:GUI驱动设备层,包括显示设备与输入设备
- GUI_demo:存放官方demo
- GUI_app:存放我们自己写的GUI应用
修改后的工程结构:
②添加源文件
在项目的根路径下新建GUI目录,以及GUI_app目录,然后将准备工作第三步下载到的源码直接解压到GUI/目录下,然后把解压出来的文件夹改名为lvgl;在GUI/目录下新建lvgl_driver目录,然后:
//从GUI\lvgl\examples\porting\目录拷贝:
lv_port_disp_template.c
lv_port_disp_template.h
lv_port_indev_template.c
lv_port_indev_template.h
// 到GUI/lvgl_driver/目录下并分别改名为:
lv_port_disp.c
lv_port_disp.h
lv_port_indev.c
lv_port_indev.h
//添加:
dma.c
dma.h
//这两个文件时我编写的使用DMA进行加速的代码,如果你不使用DMA请忽略
然后把GUI/lvgl/lv_conf_template.h拷贝到GUI/目录下并改名为lv_conf.h。
修改后的目录结构:
③添加源文件到工程中
在GUI_core组中添加以下文件夹中所有的.c文件:
GUI/lvgl/src/lv_core
GUI/lvgl/src/lv_draw
GUI/lvgl/src/lv_font
GUI/lvgl/src/lv_hal
GUI/lvgl/src/lv_misc
GUI/lvgl/src/lv_themes
GUI/lvgl/src/lv_widgets
//注意不要添加 GUI/lvgl/src/lv_gpu中的文件,除非你用到了相关功能
在GUI_drv组中添加以下.c文件:
GUI/lvgl_driver/dma.c
GUI/lvgl_driver/lv_port_disp.c
GUI/lvgl_driver/lv_port_indev.c
④添加头文件路径
⑤修改配置文件
打开GUI/lv_conf.h
首先第十行设置为#if 1 使能整个配置文件
找到以下几个宏定义并修改
#define LV_HOR_RES_MAX (480)//定义屏幕的最大水平分辨率
#define LV_VER_RES_MAX (800)//定义屏幕的最大垂直分辨率
//修改为你的屏幕分辨率即可
/* Color depth:
* - 1: 1 byte per pixel
* - 8: RGB332
* - 16: RGB565
* - 32: ARGB8888
*/
#define LV_COLOR_DEPTH 16
//定义颜色深度,如果是单色屏的话就改为1
# define LV_MEM_SIZE (30U * 1024U)
//给LVGL分配内存的大小,至少需要2k