当前位置:   article > 正文

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

lvgl教程


前言

网上教程那么多,为什么你要写这个教程?

问的好,csnd上很多类似的教程,他们写的都很好,但是有些过于简洁,对刚上手的小伙伴不太友好,移植到一半遇到bug就想放弃。一些第三方的教程很详细,但是由于lvgl的版本迭代很快,移植的过程有了一些变化,所谓失之毫厘差之千里,要么编译报错,要么移植好了文件,编译过了,屏幕却一片漆黑(移植了个寂寞),不知道问题出在哪里。
在这里插入图片描述

本教程结合keil5编译的报错,在和大家分享移植过程(分享踩坑)的同时,也作为自己的学习笔记,再次遇到问题的时候可以回来看看,说的不好的地方请各位大佬批评指正。


老样子,介绍东西

一、什么是LVGL?

在这里插入图片描述
LVGL全称Light and Versatile Graphics Library,轻量级通用图形库。

LVGL是一个开源的ui图形库,能跑在各种单片机上(树莓派、荔枝派也行)。支持按钮,触摸,编码器旋钮,鼠标等输入设备。支持高级图形效果,动画、反锯齿、透明度等。LVGL的界面非常精美,可以在官网的先感受一下他的强大,这是它demo的链接

lvgl对处理器的要求很低,下图是具体的需求,源自[官方文档]。(https://docs.lvgl.io/master/intro/index.html#requirements)
在这里插入图片描述

二、先看效果

使用分辨率320*480的屏幕,驱动芯片LIL9486,16位色TN屏,触摸是电阻屏,处理器stm32f103zet6,板子是自己画的,可以使用正点原子的精英板,屏幕接口完全一样,用的都是FSMC总线。

下图为 Widgets 的demo:
在这里插入图片描述
下图是 keypad_encoder 的DEMO:
在这里插入图片描述
横屏模式下:
在这里插入图片描述

三、移植前准备工作

1.准备原有工程

本教程基于正点原子的触摸屏实验移植,源码可以在正点原子资料下载中心下载。
在这里插入图片描述
在这里插入图片描述
不一定要用这个工程,只需要一个屏幕,能显示能触控就行,lvgl用到的屏幕接口只有一个:

/**
 * @brief 在指定区域内填充指定颜色块
 * @param sx sy ex ey (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)  
 * @param color 要填充的颜色
 */
void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

对于触摸识别,只需要有一个当前触摸的x、y坐标,有一个触摸按下的标志。

if(tp_dev.sta&0x80)//tp_dev.sta为触摸按下的标记,有触摸的时候最高位标记为1,满足if的条件
{
        last_x = tp_dev.x[0];//tp_dev.x[0]为触摸芯片读取的x坐标
		last_y = tp_dev.y[0];//tp_dev.y[0]为触摸芯片读取的y坐标
		data->point.x = last_x;//data->point.x为lvgl内部使用
		data->point.y = last_y;
		data->state = LV_INDEV_STATE_PR;//给lvgl标记按下的状态
}
else
{
        data->point.x = last_x;
		data->point.y = last_y;
		data->state = LV_INDEV_STATE_REL
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

除此之外,还需要一个周期为1ms的定时器中断,给lvgl提供心跳。

以上三点是lvgl最基本的需求。

我们先把触摸屏实验的名子改成touch(养成好习惯,改成英文名,防止各种坑),由于触摸屏实验没有定时器中断,我们先加一个,先把定时器中断实验中HARDWARE/TIMER文件夹复制到touch/HARDWARE
在这里插入图片描述
打开keil,先把添加进去的TIMER文件包含了,具体见下图,都是些搬运代码的基本操作。

在这里插入图片描述
编译成功,0错误0警告。到此,我们的工程准备完毕,这是准备好的工程,点击直接下载,本工程就是在正点原子触摸屏实验的基础上加了个定时器中断。

"..\OBJ\TOUCH.axf" - 0 Error(s), 0 Warning(s).
  • 1

跑起来就是这样,屏幕能显示,且支持触摸:
在这里插入图片描述
完美。
在这里插入图片描述

2.下载LVGL源码

打开github,国内网络环境访问github有时候不太行,如果打不开请直接下载,这是lvgl v8.0.2版本的下载链接
点击lvgl在github的仓库,依次点击master、tags、v8.0.2
在这里插入图片描述
切换到V8.0.2分支后,再点code、下载zip
在这里插入图片描述
把下载好的lvgl-8.0.2.zip文件解压,至此,源码下载完毕
在这里插入图片描述

LVGL V8.2.0都有了,为什么你还下载V8.02?

问的好,为了减少徒手撸代码的时间,我们后续使用另一款软件,恩智浦的GUI Guider进行界面可视化设计,这个软件的V1.3.x版本只支持到lvgl V8.0.2。

在这里插入图片描述
用这个软件生成代码,直接搬运到工程编译,界面设计嘎嘎快,下图是演示效果,因为主题不一样,颜色有点区别。
在这里插入图片描述

四、开始移植

1.把源码搬运到工程文件夹里

在touch目录下新建一个lvgl文件夹

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

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

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

现在,touch\lvgl目录下一共这几个文件:

在这里插入图片描述

搬运好了代码,我们得给文件改个名字,不然文件内部包含的头文件名字不一致

把touch\lvgl目录下的lv_conf_template.h文件名字改成lv_conf.h

在这里插入图片描述
把touch\lvgl\porting目录下所有文件名字的_template删了,改完之后长这样

在这里插入图片描述
至此,我们的代码搬运工作结束。

2.把搬运好的代码添加到keil工程

打开keil,点击文件扩展按钮,新建三个组,名字分别为LVGL_SRC、LVGL_PORTING、LVGL_DEMO
在这里插入图片描述
接下来就是愉快(无聊)的添加.C文件过程。

先对LVGL_SRC组添加文件,把touch\lvgl\src路径下的所有.c文件都添加进去,你没有听错,是所有.c文件,包括所有子目录,可以结合Ctrl+A快捷键全选之后再点击添加,提高效率。

注意,touch\lvgl\src\extra\widgets这个目录下文件非常分散,要一个一个添加,不要漏了,LVGL_SRC组一共133个.c文件(一个一个数的),不想自己移植可以直接使用我移植好的工程文件,这是移植完的工程文件,适配正点原子精英板。

添加好之后长这样:(一张图显示不下)

在这里插入图片描述
把touch\lvgl\porting路径下所有的.c文件添加到LVGL_PORTING组,这个文件少,就三个
LVGL_DEMO组先不管,需要跑DEMO的时候再添加。

在这里插入图片描述
接下来包含头文件。

把touch\lvgl、touch\lvgl\src、touch\lvgl\porting三个路径包含。

在这里插入图片描述
好了,现在需要的库都添加完了。

3.动手改代码

先点一下编译,发现 121 Error(s), 0 Warning(s)。

..\lvgl\src\widgets\../lv_conf_internal.h(41): error:  #5: cannot open source input file "../../lv_conf.h": No such file or directory
  #    include "../../lv_conf.h"                 /*Else assume lv_conf.h is next to the lvgl folder*/
..\lvgl\src\widgets\lv_textarea.c: 0 warnings, 1 error
compiling lv_port_fs.c...
compiling lv_port_indev.c...
"..\OBJ\TOUCH.axf" - 121 Error(s), 0 Warning(s).
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述
编译器找不到"…/…/lv_conf.h"这个文件,lv_conf.h就在touch\lvgl路径下,我们刚才把lv_conf.h的路径包含了,所有不用…/…/,直接在lv_conf_internal.h(41行)删了就行
在这里插入图片描述
把lv_conf.h文件#if 0 改成#if 1

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

在这里插入图片描述
把keil改成C99模式,在usart.c的第48行,_sys_exit函数前面加一个void,不然在C99模式下编译会报错
在这里插入图片描述

//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
  • 1
  • 2
  • 3
  • 4
  • 5

点击全部保存,我们先把keil关闭,在touch目录下,对lvgl文件夹点右键-属性,把只读的选项取消勾选,应用于子文件夹和文件,避免keil重复编译,不然每次点击编译,所有文件都编译一遍,等一万年。
在这里插入图片描述
打开keil,为了不让keil每次都把所有代码编译一遍,在设置-Output选项中,不要勾选Create Batch File 创建批处理文件,在设置-Target选项中,不要勾选 使用交叉模块优化,也不要勾选 use Micro LIB,因为LVGL有个二维码的控件使用Micro LIB编译会报错。
在这里插入图片描述

好了,我们现在再次点击编译,发现又有6个错误。

"..\OBJ\TOUCH.axf" - 6 Error(s), 34 Warning(s).
  • 1

在这里插入图片描述

原来是lv_port_disp.c文件里面有几个宏定义没有定义好。

在这里插入图片描述

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

/*====================
   COLOR SETTINGS
 *====================*/

/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH     16

#define MY_DISP_HOR_RES     480
#define MY_DISP_VER_RES     320
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

在这里插入图片描述
接着在timer.c中的定时器中断中添加lvgl的心跳接口。

先在timer.c文件顶部包含lvgl.h

然后在定时器中断中调用lv_tick_inc(1);

//定时器3中断服务程序
void TIM3_IRQHandler(void)   //TIM3中断
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
		{
			TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
			lv_tick_inc(1);//lvgl的1ms中断
		}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

好了,现在文件改动完毕,接下来添加屏幕显示和触控支持

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.显示测试

终于要到跑代码的环节了,万事万物先从点灯开始。

LVGL有一个LED控件,在屏幕上显示一个LED,可以开关、调亮度等,我们可以先跑起来看看。

在mian.c文件的顶上添加lvgl的头文件。

#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
  • 1
  • 2
  • 3

注释原有触摸实验的函数,增加lvgl初始化函数,死循环中放任务处理函数。

	lv_init();			  // lvgl系统初始化
	lv_port_disp_init();  // lvgl显示接口初始化,放在lv_init()的后面
	lv_port_indev_init(); // lvgl输入接口初始化,放在lv_init()的后面
	 
	while (1)
	{
		lv_task_handler(); // lvgl的事务处理
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

具体如下图:
在这里插入图片描述
可以看到,keil报错(红色波浪下划线),因为 lv_port_disp_init和lv_port_indev_init两个函数找不到,需要我们在lv_port_disp.h和lv_port_indev.h文件中声明这两个函数。

lv_port_disp.h添加声明:

void lv_port_disp_init(void);
  • 1

lv_port_indev.h添加声明:

void lv_port_indev_init(void);
  • 1

添加完声明后报错消失。

接下来我们打开最初从github下载下来,解压好的lvgl-8.0.2文件夹,在lvgl-8.0.2\examples\widgets\led路径中打开lv_example_led_1.c文件,复制lv_example_led_1函数放在main.c文件中。

/**
 * Create LED's with different brightness and color
 */
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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在mian.c文件的主函数初始化中调用lv_example_led_1,在死循环中调用lvgl的事务处理函数lv_task_handler。

lv_task_handler(); // lvgl的事务处理
  • 1

在这里插入图片描述
编译,下载,点灯成功。

在这里插入图片描述

6.添加触摸的接口

和添加显示驱动一样,我们先在lv_port_indev.c文件的顶部包含自己的touch.h,用于调用touch相关的接口和引用相关变量。

由于我们只用到触摸输入,为了防止各种误识别各种坑,先把其它的输入设备注释掉。

在这里插入图片描述
注释好之后,lv_port_indev.c文件的touchpad_read函数改成如下,对触摸芯片返回参数的具体的要求参见2.1小节触摸代码中的注释。

/*Will be called by the library to read the touchpad*/
static void 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(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;
    }
//	printf("x %d ,y %d \r\n",data->point.x,data->point.y);
    /*Set the last pressed coordinates*/
//    data->point.x = last_x;
//    data->point.y = last_y;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在mian.c文件的主函数的死循环中添加自己的触摸扫描函数,以不断更新tp_dev.x[0]和tp_dev.y[0]数值。

	while (1)
	{
		tp_dev.scan(0);	   //触摸扫描
		lv_task_handler(); // lvgl的事务处理
	}
  • 1
  • 2
  • 3
  • 4
  • 5

至此,触摸输入移植完成,是不是依旧很简单。

在这里插入图片描述

7.使用keypad_encoder DEMO综合测试

在touch\lvgl目录下新建demos文件夹,在此文件夹下新建lv_demo_keypad_encoder.c和lv_demo_keypad_encoder.h文件,复制以下代码到这两个新建的文件。

.c文件:

/**
 * @file lv_demo_keypad_encoder.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_demo_keypad_encoder.h"
#include "lvgl.h"
#if 1

static 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_MOUSEWHEEL
    lv_group_set_editing(g, true);
#endif
    lv_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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202

.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*/

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

在LVGL_DEMO组中添加lv_demo_keypad_encoder.c,并包含头文件路径。

在main中包含头文件。

#include "lv_demo_keypad_encoder.h"
  • 1

在初始化中调用demo接口,记得把之前的点灯注释了。

//	lv_example_led_1();//LED控件
	lv_demo_keypad_encoder();
  • 1
  • 2

在这里插入图片描述

编译下载,完美运行,触摸也好使。

再放一遍之前的图,这是移植完的工程文件,适配正点原子精英板。

注意:
LVGL在github仓库有的V8.2的版本,里面有相关的demo,别的demo如果编译报错,可以在startup_stm32f10x_hd.s文件中修改这两个参数来增加栈空间,注意要选择合适的参数,本工程用的参数如下

Stack_Size      EQU     0x00000400
Heap_Size       EQU     0x00000200
  • 1
  • 2

在这里插入图片描述
至此,完成移植,收工。

在这里插入图片描述

五、总结

本文介绍了基于stm32f103zet6正点原子精英板移植LVGL的详细过程,期间小编也遇到各种坑,比如移植完显示之后屏幕一片漆黑,移植完触控之后点了没反应,这些小坑小编就先踩为敬。

在这里插入图片描述

当你学会了移植,领悟了精髓,各种处理器,各种屏幕,各种输入设备都不是问题。

例如如在esp32上跑,下图是240X240分辨率的屏幕,输入设备是一个mpu6050(三轴加速度传感器)。
(下图的电路参考 稚晖君大佬的HoloCubic

在这里插入图片描述

六.参考文章:

正点原子 LittleVGL开源图形界面 教程
STM32CubeMX学习笔记(40)——LVGL嵌入式图形库使用
【LVGL学习之旅 01】移植LVGL到STM32
lvgl8.x 移植到 stm32f4

七.代码汇总:

移植前代码:在触摸实验的基础上加了定时器中断
移植后代码:适配正点原子精英板
LVGL V8.0.2:本套教程使用的LVGL版本

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/382311
推荐阅读
相关标签
  

闽ICP备14008679号