LVGL--轻量级嵌入式图形库

本文详细指导了如何在STM32F407开发板上使用LVGL图形库,包括学习路径、文件准备、裁剪LVGL库、配置定时器和LCD驱动、添加输入设备、以及解决常见错误,为初学者提供了一个在一周内掌握LVGL轻量应用和移植能力的指南。
摘要由CSDN通过智能技术生成

前言:

学习路线:先跟着正点原子的应用视频了解一下LVGL编程思想(然后看怎么创建部件,怎么优化),看个2天。然后就是跟着本文的文件移植(3天),然后gui guider模拟器(2天)。所以在一个星期内就可以对LVGL有轻量的应用,移植能力了。

硬件:stm32f407vet6,屏幕2.8寸电阻屏

文件移植(无系统,外部RAM)

本文根据正点原子视频移植,配合视频阅读本文章效果更好。视频连接

文件准备

首先准备三个文件

  • 第一个就是LVGL官方库文件了,获取地址
  • 第二个是驱动,给显示屏实验是提供LCD的输出驱动(显示)和输入驱动(触摸)。
  • 第三个是给LVGL提供心跳时基的。

接下来给出官方库文件获取方式:

 选择带relese的,然后下载

裁剪LVGL

裁剪的文件夹是从官方获取的LVGL库文件

就保留这五个文件。

文件详情:

把lv_conf_template.h文件改成lv_conf.h文件(更改名字)然后按照下图配置文件

  • GUI:LVGL相关库文件
  • GUI_APP:官方示例,或者自己添加的功能

文件目录:

LGVL:

  • GUI
  • GUI_APP

---------------------- 

GUI:

  • lvgl

lvgl:

  • examples
  • src
  • lv_conf.h
  • lvgl.h

------------------------ 

GUI_APP:

  • demos

GUI的:

GUI_APP的:

注意这里只添加一个demos就行了。

examples剪裁:里面就包含porting就行了。(带porting的一般都是移植文件的意思)

然后官方文件就按照上图这样放置。 

紧接着就是把lv_conf.h的#if 0改成#if 1(已更改)。其目的是使能下面的代码

配置定时器

接下来以显示屏实验为基础,将定时器驱动TIMER文件添加到显示屏实验中去。

配置keil工程

按照这样把刚才裁剪的LVGL文件添加到这里。(只要裁剪的LVGL文件进到工程就行,目录不重要)

接着把这些文件夹添加到keil中 

像这样:

紧接着在keil中配置刚才裁剪的LVGL库文件里面的.c文件:

像这样:

然后添加头文件。

选择C99(C语言标准) 

编译:(警告是因为数据类型不兼容)

配置LCD驱动

输出(显示屏显示)

配置官方的接口显示模版,把 lv_port_disp_template.c/h 的条件编译指令 #if 0 修改成 #if 1

目的同样是使能下面的代码

.c文件: 

.h文件 :

接下来都是在lv_port_disp_templ.c文件里操作 

配置LCD

接下来就是在这个接口显示模版里面接入我们自己的的 LCD驱动程序了:

那么第一步就是接入自己LCD的头文件:

第二步就是接入LCD初始函数了:

数据缓冲模式选择 

官方设置了三个模式:

假如屏幕像素是1000*100

  • 则第一种就是:开辟一个1000*10的数据缓冲区(10可以修改,改大一点也可以)
  • 第二种就是:开辟两个1000*10的数据缓冲区(10同样可以修改),是一遍缓存一遍读出。有点类似CPU的流水线
  • 第三种就是数据DMA,开辟两个1000*100的数据缓冲区(硬件要求高,因为一个单位是2个字节(16位),然后如果像素是1000*100的话,内存占用就是1000*100*2*2=4*10的5次方字节=0.4MB,(开辟两个所以又再次乘2))

选择第一种模式:

宏定义像素大小:

如下图所示依次是上面的三种模式:选择第一种(则把剩下两种屏蔽即可)

设置屏幕尺寸

如果直接设置大小要注意 :

横屏时假如是1000*100 

竖屏时如果没有更改,则会变成水平像素是1000,纵向是100了,则会显示出错。

如下图:竖屏的时候会显示右边红框和黑框交界的地方,则显示错误

配置填充颜色函数

disp_flush()函数功能就是一个点填充颜色

配置输入(触摸屏)  

接下来对lv_port_indev_template.c/h文件进行操作  lv_port_indev_template是接口输入设备模版

首先把 lv_port_indev_template.c/h 的条件编译指令 #if 0 修改成#if 1目的:使能代码

裁剪输入设备

输入设备可以有很多个,比如键盘,按键,编码器,鼠标等。这里选择触摸,故需要裁剪触摸部分就行

头文件修改:也可以在裁剪LVGL中把GUI文件夹里面的LVGL4个官方库文件在存入到GUI文件的新建子文件lvgl(小写)中

只保留触摸屏相关的接口函数:

在lv_port_indev_init中只保留

还有像这种别的输入设备驱动函数也给删了:

 导入头文件

初始化触摸屏 

在 touchpad_init 函数中初始化触摸屏

配置检测函数

配置坐标检测函数

配置时基

添加定时器驱动

配置定时器步骤中的定时器驱动添加到keil工程当中:

在btim.c文件中添加#include "lvgl.h"

添加心跳

添加相关函数:

在定时器回调函数里面调用lv_tick_inc(1);

  • 具体来说,lv_tick_inc(1); 函数的作用是增加 LVGL 内部的时间计数器。在嵌入式系统中,LVGL 需要定期更新内部的时间计数器,以便正确地管理动画、定时器、事件处理等功能。通过调用 lv_tick_inc(1); 函数,LVGL 将内部的时间计数器增加 1 个时间单位,通常是毫秒(ms)。
  • 这个函数通常在系统的主循环或定时器中断服务函数中被调用,以确保 LVGL 内部的时间计数器保持同步。在调用该函数后,LVGL 将会处理任何过期的定时器事件、动画更新或其他需要基于时间的操作。
  • 所以说lv_tick_inc(1);作用就是为LVGL提供心跳,类似单片机的基准时钟(借用单片机的时钟来为自己提供时钟)
  • 需保证LVGL里面的基准时钟是多少ms,定时器进入中断就是多少ms

如果要配置配置自己的时钟源,如FreeRTOS里面的tick,则可以不在中断中配置,而是在下面函数中修改相应宏为1,且在第二个箭头里添加FreeRTOS的心跳。

修改main函数

因为是按照正点原子的驱动代码修改,所以这些步骤可以自行判断哪里需要改

删除除了main函数以外的函数(根据自己代码判断)

添加头文件:(必须)

#include "./BSP/TIMER/btim.h"
#include "lvgl.h"
#include "lv_port_disp_template.h"
#include "lv_port_indev_template.h"

添加下面函数 (必须)

btim_timx_int_init(10-1, 9000-1);//初始化定时器,需要考虑自己开发板时钟频率,1ms进一次中断即可
lv_init(); //初始化LVGL库
lv_port_disp_init(); //初始化输出设备
lv_port_indev_init();//初始化输入设备

调用 lv_timer_handler(必须)

在while(1)中每隔5ms调用一次lv_timer_handler();(必须)

    while(1)
    {
        delay_ms(5);
        lv_timer_handler();

    }

lv_timer_handler()和lv_tick_inc()关系 

lv_timer_handler() 函数和lv_tick_inc() 函数在 LittlevGL(LVGL)图形库中通常一起使用,它们之间存在密切的关系。

  1. lv_tick_inc() 函数

    • lv_tick_inc()函数用于增加 LVGL 内部的时间计数器,通常以毫秒(ms)为单位。
    • 它是用来告诉 LVGL 时间已经流逝了多少,从而更新内部的时间状态,例如动画、定时器等需要根据时间变化的功能。
    • lv_tick_inc()函数通常由系统的主循环或定时器中断服务函数中调用,以保持 LVGL 内部时间计数器的同步。
  2. lv_timer_handler() 函数

    • lv_timer_handler()函数用于处理定时器事件,包括检查定时器是否到期,并执行相应的回调函数或任务。
    • 它通常在应用程序的主循环中被调用,以处理与时间相关的任务,例如动画更新、定时事件处理等。
    • 在处理定时器事件之前,通常需要先调用lv_timer_handler() 函数来更新 LVGL 内部的时间状态,以确保定时器事件的准确处理。

因此,这两个函数通常是配合使用的:首先调用 lv_tick_inc() 函数来更新 LVGL 内部的时间状态,然后再调用lv_timer_handler() 函数来处理定时器事件,从而实现图形界面的正常运行和响应

最后填写测试代码(可修改)

lv_obj_t* switch_obj = lv_switch_create(lv_scr_act());
lv_obj_set_size(switch_obj, 120, 60);
lv_obj_align(switch_obj, LV_ALIGN_CENTER, 0, 0);

整体main函数代码:


#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/TOUCH/touch.h"

#include "./BSP/TIMER/btim.h"
#include "lvgl.h"
#include "lv_port_disp_template.h"
#include "lv_port_indev_template.h"




int main(void)
{
    HAL_Init();                         
    sys_stm32_clock_init(336, 8, 2, 7);
    delay_init(168);                   
    usart_init(115200);                
    led_init();                       
   // lcd_init();         //因为之前在lvgl哪里调用过了            
    key_init();                    
    tp_dev.init();                      

    btim_timx_int_init(10-1, 9000-1);//初始化定时器,需要考虑自己开发板时钟频率,1ms进一次中断即可
    lv_init(); //初始化LVGL库
    lv_port_disp_init(); //初始化输出设备
    lv_port_indev_init();//初始化输入设备

	lv_obj_t* switch_obj = lv_switch_create(lv_scr_act());
	lv_obj_set_size(switch_obj, 120, 60);
	lv_obj_align(switch_obj, LV_ALIGN_CENTER, 0, 0);

    while(1)
    {
      delay_ms(5);
        lv_timer_handler();

    }
}

错误可能

最后编译可能f103系列的可能会出现报错,可能是因为内存分配问题所导致的。此时可以打开lv_conf.h文件把内存大小改小

也可能是启动文件的栈内存分配太小:

..\..\Output\atk_f407.axf: Error: L6406E: No space in execution regions with

原因是:keil默认把所有代码,包括没有用到的代码链接起来放进flash,但是我们不用这么多,所以选择这个:(根据等级越高程序的可调试性逐渐变差

当你屏幕点不了的时候可能是在touch.c文件里面的tp_init函数里最后屏蔽tp_get_adjust_data();

原因:不详

测试 

成功Run起来

VID_20240421_145916

Gui Guider-实现模拟+生成代码

下载

官网:下载地址

操作步骤

设备-模拟器

空模版:

填写尺寸(太大了,flash可能受不了),名称:

选择代码

把文件生成的lv_anim.h和lv_anim.c替换原本keil工程目录下(Middlewares\LVGL\GUI\lvgl\src\misc)的的lv_anim.h和lv_anim.c

把lv_anim.h头文件添加到lvgl.h中

然后.c文件同理.h文件一样 

添加宏定义

然后main.c文件

添加头文件

#include "gui_guider.h"
#include "events_init.h"

在main函数外定义:

lv_ui guider_ui;

在main函数调用:

setup_ui(&guider_ui);
events_init(&guider_ui);

整体main.c


#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/TOUCH/touch.h"

#include "./BSP/TIMER/btim.h"
#include "lvgl.h"
#include "lv_port_disp_template.h"
#include "lv_port_indev_template.h"

#include "gui_guider.h"
#include "events_init.h"


lv_ui guider_ui;




int main(void)
{
    HAL_Init();                         
    sys_stm32_clock_init(336, 8, 2, 7);
    delay_init(168);                   
    usart_init(115200);                
    led_init();                       
   // lcd_init();         //因为之前在lvgl哪里调用过了            
    key_init();                    
    tp_dev.init();                      

    btim_timx_int_init(10-1, 9000-1);//初始化定时器,需要考虑自己开发板时钟频率,1ms进一次中断即可
    lv_init(); //初始化LVGL库
    lv_port_disp_init(); //初始化输出设备
    lv_port_indev_init();//初始化输入设备

//	lv_obj_t* switch_obj = lv_switch_create(lv_scr_act());
//	lv_obj_set_size(switch_obj, 120, 60);
//	lv_obj_align(switch_obj, LV_ALIGN_CENTER, 0, 0);
setup_ui(&guider_ui);
events_init(&guider_ui);

    while(1)
    {
      delay_ms(5);
        lv_timer_handler();

    }
}

运行

然后烧录成功run :

注意事项

  • 若出现 ..\..\Output\atk_f407.axf: Error: L6406E: No space in execution regions with
  • 解决方法:类似错误则参考目录中  移植->修改main函数->错误可能(看目录)
  • 若出现..\..\Output\atk_f407.axf: Error: L6218E: Undefined symbol_btn_list_pause_alpha_28x28 (referred from custom.o).
  • 解决方法:这种错误可能是你再更换不同的这三个文件时(比如说,这次你选择尺寸是300*200但是你下次新建文件选择的是320*240,这时候导出的这三个文件夹里面的.c/.h不一样),没更换keil中三个文件所对应的.c文件所导致的

以下编程未整理可跳过(根据正点原子)可以去看对应视频

编程

编程思想

部件基本属性

第一个的LV_ALIGN_.....(模式):只能选择在内部的模式(阴影部分)

第二个的LV_ALIGN_.....(模式):能选择所有的 

 

第一个能共享,第二个只能用于单个部件。第一个变量只能是静态全局,使动态分配的,不然会出错。

轮廓是在边框的外面。

相关枚举参数可以去官网查找,也可以去原子,百问网去。

cb --Callback回调函数

同一回调函数,同一部件,不同触发方式

同一回调函数,不同部件(里面函数是上面那个类型)

状态切换必须要开启

当设置颜色不对时,考虑覆盖问题。

lv_obj_add_state(switch1,LV_STATE_CHECKED|LV_STATE_DISABLED)表示打开且不可修改

lv_obj_add_state(switch1,LV_STATE_CHECKED表示打开可

lv_lear_clear_state()同理

lv_obj_add_state(switch1,LV_STATE_CHECKED|LV_STATE_DISABLED)

lv_obj_clear_state(switch1,LV_STATE_CHECKED|LV_STATE_DISABLED)

表示默认关,且可以修改。

上面三个示例由于LVGL版本不一样所导致

下拉部件:

e那个是另外添加到d的后面

滚轮部件:

滑块部件:

可以有三个照片 C语言数组(照片转数组,从官网),二进制,官网定义图标。

  • 24
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值