STM32移植LVGL(LittleVGL)

一、什么是LVGL

https://lvgl.io/ 这是LVGL的官网,

http://lvgl.100ask.org/8.2/intro/index.html 这是lvgl的中文介绍网站。

先通过这两个网站大致了解一下lvgl,在后面移植时会有个大概了解,移植起来会更清晰易懂。

二、移植前准备工作

1、准备STM32工程

1、先准备所用到的屏幕的显示和触摸(有触摸功能的屏幕)的工程。我这里用的是正点原子的F103的精英开发板,用到工程是配套的触摸例程(如果你的屏幕没有触摸功能那只需要屏幕的显示例程),用到的只是里面的颜色填充函数和触摸扫描函数。

更改工程名字为touch(自己命名),


在touch项目根目录下新建GUI和GUI_APP两个文件夹,GUI 目录是用来存放跟 littleVGL 库相关的所有文件的,而 GUI_APP 是用来放我们自己的GUI 应用代码的。

2、还要准备一个周期为1ms的定时器中断,给LVGL提供心跳,我这里直接用的是例程中的定时器中断实验例程。

3、接着我们打开 Keil 工程,点击 图标,打开分组管理面板,在 Groups 栏下新建 GUISRC 、GUIPORTING和GUI_APP 3个分组,GUISRC存放lvgl的源码,GUIPORTING存放lvgl的接口API,GUI_APP存放自己的GUI代码。

g)
添加定时器,选择HARDWARE分组,点击Add Files…添加.c文件
点击Add添加。
添加定时器标准库,选择FWLib分组,点击Add Files…添加.c文件

点击Add添加。然后点击OK。

编译工程没有错误没有警告。

2、下载LVGL源码

1、打开Gitee,直接搜索lvgl。

选择合适的版本,尽量选择v8.0.2以前的版本,因为后我会用到NXP的GUI设计软件,这个软件只支持到v8.0.2。

我这里选择的是v8.0.2,然后下载压缩包。

三、开始移植

1、添加lvgl源码到工程文件中

lvgl-8.0.2\src文件夹直接复制到新建的GUI文件夹里,这个src里面就是源码

lvgl-8.0.2\examples\porting文件夹复制到新建的GUI文件夹里,这是移植用的接口

lvgl-8.0.2目录下的lvgl.h、lv_conf_template.h、LICENCE.txt、README.md一共4个文件复制到新建的GUI文件夹里,后面两个可以不用,不影响移植。

搬运好了代码,我们得给文件改个名字,不然文件内部包含的头文件名字不一致把touch\lvgl目录下的lv_conf_template.h文件名字改成lv_conf.h

touch\GUI\porting目录下所有文件名字的**_template**删了,改完之后的样子

2、在keil中添加.c文件和包含文件目录。

把touch\GUI\src路径下的所有.c文件都添加到GUISRC分组,你没有听错,是所有.c文件,包括所有子目录,可以结合Ctrl+A快捷键全选之后再点击添加,提高效率。(这里添加的时候很容易出错,一定要细心)
把touch\GUI\porting路径下的所有.c文件都添加到GUIPORTING分组
包含文件目录,这里补充一下前面添加定时器时忘记包含文件目录了,这里补上。

接着我们需要做 2 个比较重要的小操作,加大项目的栈空间到 2KB 和使能 C99 编译器功能,打开 Core 分组下的.s 启动文件,修改 Stack_Size 的值到 2KB(0x00000800),如Stack_Size EQU 0x00000800 所示,然后点击
图标,打开面板之后,切换到 C/C++面板,选 中 C99 Mode 复选框即可,因为 littleVGL 要求 C99 或更新的编译器,否则编译是会报错的。

3、修改代码

我们先给lvgl提供心跳让他能够“动”起来:先在timer.c里添加“lvgl.h”头文件,再在定时器中断里调用 lv_tick_inc(1);
编译一下会发现有很多错误,不急我们慢慢修改。

双击第一条错误提示,

然后跳转到"lv_conf.h"头文件 把最上面的 #if 0 改为 #if 1

同样的,把lv_port_disp.c、lv_port_disp.h、lv_port_indev.c、lv_port_indev.h四个文件的#if 0 都改成#if 1 ,这四个文件包含的头文件名字还需修改,具体看下图。这四个文件中的两个.h文件中,路径为#include "lvgl/lvgl.h"改成#include “lvgl.h”。

随带在lv_port_disp.h文件下添加初始化函数:void lv_port_disp_init(void);

随带在lv_port_indev.h文件下添加初始化函数:void lv_port_indev_init(void);

lv_port_disp.c

lv_port_disp.h

lv_port_indev.c、lv_port_indev.h,和上面类似的操作。

我们再次编译一下,还有几条错误,我继续点击第一条错误提示。发现是 lv_port_disp.c 源文件里的几个宏定义没有定义,我们在 “lv_conf.h”头文件下定义一下。

在lv_conf.h中定义好屏幕的水平像素和垂直像素大小,顺手把LV_COLOR_DEPTH 改成16位(根据实际情况改,如果屏幕是32位色就不用改)

把lv_port_disp.c的里面的example 2 和3都注释了,只留example1,点击编译,编译通过,警告不用管,大多是因为定义了函数但是没有使用而报警告,不影响。

4、添加屏幕接口

lv_port_disp.c文件的顶部包含自己的lcd.h,用于调用lcd相关的接口

根据实际情况,在lv_port_disp.c文件中给disp_drv.hor_res和disp_drv.ver_res两个参数赋值,可以是lcd初始化之后获取的,也可以是固定的

disp_flush函数中,注释原来的for循环,把自己的LCD填充颜色的函数放进去。

到此我们的移植工作一准备完成,接下来就是添加测试代码。

5、添加测试显示代码。

我们现在 main.c 源文件下添加一些要用到的头文件和一些初始化函数。删除原来的一些测试代码,

添加测试代码,在lvgl-8.0.2\examples\widgets\led路径中打开lv_example_led_1.c文件,复制lv_example_led_1函数放在main.c文件中。
代码如下:

void lv_example_led_1(void)
{/*Create a LED and switch it OFF*/lv_obj_t * led1  = lv_led_create(lv_scr_act());lv_obj_align(led1, LV_ALIGN_CENTER, -80, 0);lv_led_off(led1);/*Copy the previous LED and set a brightness*/lv_obj_t * led2  = lv_led_create(lv_scr_act());lv_obj_align(led2, LV_ALIGN_CENTER, 0, 0);lv_led_set_brightness(led2, 150);lv_led_set_color(led2, lv_palette_main(LV_PALETTE_RED));/*Copy the previous LED and switch it ON*/lv_obj_t * led3  = lv_led_create(lv_scr_act());lv_obj_align(led3, LV_ALIGN_CENTER, 80, 0);lv_led_on(led3);
}

然后调用。

到这里就能实现屏幕的显示了。接下来就是添加触摸例程了。

6、添加触摸接口

先在 lv_port_indev.c 源文件下添加自己的触摸工程头文件"touch.h",用于调用touch相关的接口和变量。
修改lv_port_indev_init 函数,

修改lv_port_indev.c 源文件下的touchpad_read 函数。

在main.c源文件下的while(1)里添加触摸扫描函数:

在touch\GUIAPP目录下新建一个文件夹demos,在keil中新建两个文件保存到demos文件夹中,分别命名为lv_demo_keypad_encoder.c和lv_demo_keypad_encoder.h,然后再GUIAPP分组中添加lv_demo_keypad_encoder.c,包含文件目录。

为lv_demo_keypad_encoder.c添加代码。

/*** @file lv_demo_keypad_encoder.c**//**********************      INCLUDES*********************/
#include "lv_demo_keypad_encoder.h"
#include "lvgl.h"
#if 1static void selectors_create(lv_obj_t * parent);
static void text_input_create(lv_obj_t * parent);
static void msgbox_create(void);static void msgbox_event_cb(lv_event_t * e);
static void ta_event_cb(lv_event_t * e);static lv_group_t*  g;
static lv_obj_t * tv;
static lv_obj_t * t1;
static lv_obj_t * t2;void lv_demo_keypad_encoder(void)
{g = lv_group_create();lv_group_set_default(g);lv_indev_t* cur_drv = NULL;for (;;) {cur_drv = lv_indev_get_next(cur_drv);if (!cur_drv) {break;}if (cur_drv->driver->type == LV_INDEV_TYPE_KEYPAD) {lv_indev_set_group(cur_drv, g);}if (cur_drv->driver->type == LV_INDEV_TYPE_ENCODER) {lv_indev_set_group(cur_drv, g);}}tv = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, LV_DPI_DEF / 3);t1 = lv_tabview_add_tab(tv, "Selectors");t2 = lv_tabview_add_tab(tv, "Text input");selectors_create(t1);text_input_create(t2);msgbox_create();
}/***********************   STATIC FUNCTIONS**********************/static void selectors_create(lv_obj_t * parent)
{lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);lv_obj_set_flex_align(parent, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);lv_obj_t * obj;obj = lv_table_create(parent);lv_table_set_cell_value(obj, 0, 0, "00");lv_table_set_cell_value(obj, 0, 1, "01");lv_table_set_cell_value(obj, 1, 0, "10");lv_table_set_cell_value(obj, 1, 1, "11");lv_table_set_cell_value(obj, 2, 0, "20");lv_table_set_cell_value(obj, 2, 1, "21");lv_table_set_cell_value(obj, 3, 0, "30");lv_table_set_cell_value(obj, 3, 1, "31");lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);obj = lv_calendar_create(parent);lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);obj = lv_btnmatrix_create(parent);lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);obj = lv_checkbox_create(parent);lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);obj = lv_slider_create(parent);lv_slider_set_range(obj, 0, 10);lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);obj = lv_switch_create(parent);lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);obj = lv_spinbox_create(parent);lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);obj = lv_dropdown_create(parent);lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);obj = lv_roller_create(parent);lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);lv_obj_t * list = lv_list_create(parent);lv_obj_update_layout(list);if(lv_obj_get_height(list) > lv_obj_get_content_height(parent)) {lv_obj_set_height(list, lv_obj_get_content_height(parent));}lv_list_add_btn(list, LV_SYMBOL_OK, "Apply");lv_list_add_btn(list, LV_SYMBOL_CLOSE, "Close");lv_list_add_btn(list, LV_SYMBOL_EYE_OPEN, "Show");lv_list_add_btn(list, LV_SYMBOL_EYE_CLOSE, "Hide");lv_list_add_btn(list, LV_SYMBOL_TRASH, "Delete");lv_list_add_btn(list, LV_SYMBOL_COPY, "Copy");lv_list_add_btn(list, LV_SYMBOL_PASTE, "Paste");
}static void text_input_create(lv_obj_t * parent)
{lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);lv_obj_t * ta1 = lv_textarea_create(parent);lv_obj_set_width(ta1, LV_PCT(100));lv_textarea_set_one_line(ta1, true);lv_textarea_set_placeholder_text(ta1, "Click with an encoder to show a keyboard");lv_obj_t * ta2 = lv_textarea_create(parent);lv_obj_set_width(ta2, LV_PCT(100));lv_textarea_set_one_line(ta2, true);lv_textarea_set_placeholder_text(ta2, "Type something");lv_obj_t *kb = lv_keyboard_create(lv_scr_act());lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);lv_obj_add_event_cb(ta1, ta_event_cb, LV_EVENT_ALL, kb);lv_obj_add_event_cb(ta2, ta_event_cb, LV_EVENT_ALL, kb);
}static void msgbox_create(void)
{static const char * btns[] = {"Ok", "Cancel", ""};lv_obj_t * mbox = lv_msgbox_create(NULL, "Hi", "Welcome to the keyboard and encoder demo", btns, false);lv_obj_add_event_cb(mbox, msgbox_event_cb, LV_EVENT_ALL, NULL);lv_group_focus_obj(lv_msgbox_get_btns(mbox));lv_obj_add_state(lv_msgbox_get_btns(mbox), LV_STATE_FOCUS_KEY);
#if LV_EX_MOUSEWHEELlv_group_set_editing(g, true);
#endiflv_group_focus_freeze(g, true);lv_obj_align(mbox, LV_ALIGN_CENTER, 0, 0);lv_obj_t * bg = lv_obj_get_parent(mbox);lv_obj_set_style_bg_opa(bg, LV_OPA_70, 0);lv_obj_set_style_bg_color(bg, lv_palette_main(LV_PALETTE_GREY), 0);
}static void msgbox_event_cb(lv_event_t * e)
{lv_event_code_t code = lv_event_get_code(e);lv_obj_t * msgbox = lv_event_get_current_target(e);if(code == LV_EVENT_VALUE_CHANGED) {const char * txt = lv_msgbox_get_active_btn_text(msgbox);if(txt) {lv_msgbox_close(msgbox);lv_group_focus_freeze(g, false);lv_group_focus_obj(lv_obj_get_child(t1, 0));lv_obj_scroll_to(t1, 0, 0, LV_ANIM_OFF);}}
}static void ta_event_cb(lv_event_t * e)
{lv_indev_t * indev = lv_indev_get_act();if(indev == NULL) return;lv_indev_type_t indev_type = lv_indev_get_type(indev);lv_event_code_t code = lv_event_get_code(e);lv_obj_t * ta = lv_event_get_target(e);lv_obj_t * kb = lv_event_get_user_data(e);if(code == LV_EVENT_CLICKED && indev_type == LV_INDEV_TYPE_ENCODER) {lv_keyboard_set_textarea(kb, ta);lv_obj_clear_flag(kb, LV_OBJ_FLAG_HIDDEN);lv_group_focus_obj(kb);lv_group_set_editing(lv_obj_get_group(kb), kb);lv_obj_set_height(tv, LV_VER_RES / 2);lv_obj_align(kb, LV_ALIGN_BOTTOM_MID, 0, 0);}if(code == LV_EVENT_READY || code == LV_EVENT_CANCEL) {lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);lv_obj_set_height(tv, LV_VER_RES);}
}#endif

为lv_demo_keypad_encoder.h添加代码。

/*** @file lv_demo_keypad_encoder.h**/#ifndef LV_DEMO_KEYPAD_ENCODER_H
#define LV_DEMO_KEYPAD_ENCODER_H#ifdef __cplusplus
extern "C" {#endif/**********************      INCLUDES*********************/
/**********************      DEFINES*********************//***********************      TYPEDEFS**********************//*********************** GLOBAL PROTOTYPES**********************/
void lv_demo_keypad_encoder(void);/***********************      MACROS**********************/#ifdef __cplusplus
} /* extern "C" */
#endif#endif /*LV_DEMO_KEYPAD_ENCODER_H*/

在main.c源文件下添加头文件

#include "lv_demo_keypad_encoder.h"

注释原来的测试代码调用新代码

编译下载,就可以在板子上看到我们的例程了。

后面我们可以通过NXP的一个GUI设计软件(GUI Guider)进行设计自己的UI界面生成代码添加到自己的工程中。后面我会写博客介绍。

STM32移植LVGL(LittleVGL)相关推荐

  1. STM32移植LVGL+旋转编码器接口对接

    写在前面:本菜鸟结合了许多大佬的文章,成功实现了基于LVGL的GUI设计,小开心~浅浅记录一下!~ 本文以单片机STM32F103VET6为核心,利用ST7796芯片驱动分辨率为480*320的LCD ...

  2. stm32移植lvgl

    1.lvgl简介 lvgl是一款全部用c语言实现的ui图形库,对硬件的要求比较低,可以较为流畅的运行在单片机上.并且完全开源,对按钮,触摸,编码器旋钮等支持的非常到位.且开发的界面较为美观,符合时下主 ...

  3. STM32移植lvgl遇到的bug(坑)

    1-\Output\Template.axf: Error: L6218E: Undefined symbol __aeabi_assert (referred from qrcodegen.o). ...

  4. 【LVGL】学习笔记--(1)Keil中嵌入式系统移植LVGL

    一 LVGL简介 最近emwin用的比较烦躁,同时被LVGL酷炫的界面吸引到了,所以准备换用LVGL试试水. LVGL(轻量级和通用图形库)是一个免费和开源的图形库,它提供了创建嵌入式GUI所需的一切 ...

  5. STM32移植Littlevgl(LVGL)V8.0.2使用文件系统+BMP解码显示外部FLASH中图片

    说明:选择BMP解码图片的方式,是因为此方式不需要占用太多的RAM 一.主要参数及版本 MCU:STM32F103ZET6 LCD:2.8寸ILI9341,使用FSMC驱动 SPI FLASH:W25 ...

  6. STM32移植LVGL8.0.2超详细的保姆级教程附移植好的工程文件

    文章目录 前言 一.什么是LVGL? 二.先看效果 三.移植前准备工作 1.准备原有工程 2.下载LVGL源码 四.开始移植 1.把源码搬运到工程文件夹里 2.把搬运好的代码添加到keil工程 3.动 ...

  7. 乐鑫ESP32移植LVGL 7.10

    零. 声明 本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下: 第一篇:ESP-IDF基本介绍,主要会涉及模组,芯片,开发板的介绍,环境搭建,程序编译下载,启动流程等一些基本的操作,让你对 ...

  8. 来了!STM32移植LuatOS,潘多拉示例全新教程

    进击的五月,继上期<使用Air724UG制作简易贪吃蛇>教程之后,@打盹的消防车 又为大家带来基于STM32的潘多拉LuatOS移植全新教程: 为什么使用潘多拉作为教程呢? STM32不能 ...

  9. TFT-LCD移植LVGL详细过程记录

    TFT-LCD移植LVGL LVGL(轻量级和通用图形库)是一个免费和开源的图形库,它提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素,美丽的视觉效果和低内存占用. LVGL更多介绍:http ...

最新文章

  1. 设计模式-Adapter模式
  2. 报错整理:ImportError: cannot import name ‘mean_absolute_percentage_error‘ from ‘sklearn.metrics‘
  3. mysql免安装服务器配置_MYSQL免安装环境配置
  4. 用bit字段来判断性别等
  5. springMVC-配置Bean
  6. django 怎么加权限 静态资源目录_Django:settings中关于static静态文件目录的设置...
  7. Android之实现Room升级需要给一个表增加一个字段
  8. [Mechine Learning Algorithm] 集成学习方法——Bagging和 Boosting
  9. 反向输出一个三位数(信息学奥赛一本通-T1031)
  10. Leetcode 118 杨辉三角
  11. python编程(supervisor程序管理)
  12. python网络爬虫系列教程——python网络数据爬虫误区,让你的爬虫更像人类
  13. Oracle 学习笔记(Windows 环境下安装 + PL/SQL)
  14. OKHttp 的使用
  15. poj 1287 Networking (最小生成树Kruskal算法)
  16. 英语骂人脏话大全(from ndi) scarlk scarlk 2011-12-28 10:09:21
  17. ERROR: Pool overlaps with other one on this address space
  18. Android WebView加载网页进度监听
  19. jQuery EasyUI详解-EasyUI环境配置
  20. 【转】加油站压力/真空阀(PV阀)的工作原理及安全注意事项

热门文章

  1. [渝粤教育] 西南科技大学 列车牵引制动 在线考试复习资料
  2. TextView的走马灯效果
  3. vue框架根据antd封装的走马灯组件
  4. .jpg .jpeg 区别
  5. 上云精品,实力认证丨思迈特软件入驻华为云严选商城
  6. 第二行代码第三章笔记
  7. 【Golang开发面经】B站(两轮技术面)
  8. 自定义的仿美团,飞猪日期选择控件一
  9. 微信企业号通讯录异步更新(java)
  10. MFC用CButtonST类实现图片透明按钮(免费源码下载)