lvgl

lvgl

目录

lvgl

Lvgl移植到STM32

[-- 1、下载LVGL源码](#-- 1、下载LVGL源码)

[-- 2、将必要文件复制到工程目录](#-- 2、将必要文件复制到工程目录)

[-- 3、修改配置文件](#-- 3、修改配置文件)

将lvgl与底层屏幕结合到一块

[-- lvgl也需要有定时器,专门给自己做了一个函数,告诉lvgl经过了多长时间(ms(毫秒)级别)](#-- lvgl也需要有定时器,专门给自己做了一个函数,告诉lvgl经过了多长时间(ms(毫秒)级别))

编写代码

lvgl的中文教程手册网站

lvgl的基础知识

[-- 重点是lvgl基础控件的使用](#-- 重点是lvgl基础控件的使用)

[-- 如何用lvgl去制作软件](#-- 如何用lvgl去制作软件)

更改错误

[-- 8、只要使用汉字,都按照下面这种方式修改](#-- 8、只要使用汉字,都按照下面这种方式修改)

屏幕显示调用

如何实现界面刷新(界面中的数据如何变化)

总结


  • 主要用于界面设计

-- 我们在做的项目是空气质量检测仪,下面这些是项目在开发阶段分的模块

  • 分为项目硬件,项目软件,项目结构(产品外壳),UI(界面设计),APP,测试

-- 对于界面开发,有很多,如qt,但是qt开发出来的程序比较大,占用内存比较多,所以选择了lvgl

-- GUI:LVGL,emwin,qt,touchgfx,minigui,simplegui(嵌入式开发阶段的界面开发工具)


-- LVGL(轻巧而多功能的图形库)是一个免费的开放源代码图形库,它提供创建具有易于使用的图形元素,精美的视觉效果和低内存占用的嵌入式GUI所需的一切。

-- lvgl官方网站


-- 硬件要求:

基本上,每个现代控制器(肯定必须要能够驱动显示器)都适合运行LVGL。LVGL的最低运行要求很低: 16、32或64位微控制器或处理器

最低 16 MHz 时钟频率

Flash/ROM::对于非常重要的组件要求 >64 kB(建议 > 180 kB)

-- Lvgl系统框架

-- 应用程序创建 GUI 并处理特定任务的应用程序。 -- LVGL 本身是一个图形库。我们的应用程序通过调用 LVGL 库来创建 GUI 。它包含一个 HAL (硬件抽象层)接口,用于注册显示和输入设备驱动程序。 驱动程序除特定的驱动程序外,它还有其他的功能,可驱动显示器到 GPU (可选)、读取触摸板或按钮的输入。

Lvgl移植到STM32

-- 1、下载LVGL源码

-- 其中lvgl/src文件夹内存放的是LVGL的核心源码,lvgl/examples/porting文件夹内存放的是lvgl与底层的接口函数,这些函数需要我们根据自己的项目进行修改。

-- 源码在文件夹中可以找到

-- 2、将必要文件复制到工程目录

-- 1、在个人的工程目录下创建一个名为Lvgl的文件夹,并将lvgl/src目录复制到Lvgl目录下,将lvgl/examples/porting文件夹复制到Lvgl目录下,同时将lvgl/lvgl.h文件以及lvgl/lv_conf_template.h文件复制到Lvgl目录下。如下图所示:

-- 2、将lv_conf_template.h文件更名为lv_conf.h,如下图所示:

-- 3、修改port目录下所需要的文件名字,我们只使用了屏幕的显示功能,因此我们只修改显示接口的文件名字,将lv_port_disp_template.c/.h更名为lv_port_disp.c/.h如下图所示:

-- 4、在Lvgl目录下再创建一个app目录,用于存放我们后期自己写的应用层界面代码,具体操作如下图所示:

-- 5、打开工程,在工程目录下新建三个分组,分别为Lvgl/app、Lvgl/porting、Lvgl/src三个目录,具体操作如下图所示:

-- 6、添加文件到工程目录中,porting目录下只添加lv_port_disp.c,以及Lvgl目录下的lv_conf.h文件,这两个文件后面需要修改。

在src目录下,添加Lvgl/src目录下除去gpu文件夹外的所有文件夹内的c文件。

-- 7、配置头文件路径,把Lvgl文件夹下所有包含h文件的路径,在工程属性中进行配置,具体操作如下图:

-- 3、修改配置文件

-- 1、打开lv_port_disp.c/.h文件,修改如下内容

-- 2、修改lv_conf.h文件如下图所示,修改后编译代码,这个时候代码就没有错误了。

-- 3、接下来适配屏幕接口到lvgl上,先修改lv_conf.h内的宏定义,通过它可以设置库的基本行为,裁剪不需要模块和功能,在编译时调整内存缓冲区的大小等等,我们先修改一些必须修改的定义,后期的功能我们在具体项目中再做裁剪。

-- 注:

-- 竖屏和横屏可以自己选择

-- 更改单片机分给lvgl的空间大小

-- 是否要适配v6版本,我们这里选择v7版本,就不适配v6了,将宏定义改为0

将lvgl与底层屏幕结合到一块

-- 更改初始化函数,进入初始化函数中

-- 将lcd初始化加进来,以后就不用lcd初始化了,直接调用lvgl的初始化函数即可

-- 绘制缓冲区,屏蔽其他两种方法

-- 更改参数

-- 找到lcd中的指定区域内填充指定颜色快的函数

-- 并在.h中声明

-- 将lv_port_disp.c中的函数进行修改

-- lvgl也需要有定时器,专门给自己做了一个函数,告诉lvgl经过了多长时间(ms(毫秒)级别)
  • 先将操作系统中的宏定义改变

  • 我们要写一个时钟节拍钩子函数

  • 参考我们之前写的任务栈溢出函数

编写代码

-- 创建任务句柄

cs 复制代码
TaskHandle_t xLvglTaskHandle = NULL;

-- 创建任务主题函数

cs 复制代码
void vLvglTaskFunction( void * pvParameters )
{
	TickType_t xLastWakeTime;
	const TickType_t xPeriod = pdMS_TO_TICKS( 5 );//5ms的延时
	xLastWakeTime = xTaskGetTickCount();  
	for(;;)
	{		
		lv_task_handler();//在裸机里放在while循环中即可
		vTaskDelayUntil( &xLastWakeTime, xPeriod );//绝对延时
	}
}

-- 创建任务(放在main函数中)

cs 复制代码
			
		xTaskCreate(vLvglTaskFunction, "lvgl_task", 512, NULL, 2, &xLvglTaskHandle);

-- 启动任务

cs 复制代码
if(xReturn == pdPASS)
					vTaskStartScheduler();//任务调度器			//当程序执行完这句话之后,正常情况下下面的代码不会再运行,只会运行任务主题函数

-- 上述内容我们就已经成功配置了lvgl的环境,下面我们写入一个测试代码,看看是否能够正常显示。写在初始化函数后面即可。

-- 完整代码

cs 复制代码
#include "lvgl.h"
#include "lv_port_disp.h"

TaskHandle_t xLvglTaskHandle = NULL;

void vLvglTaskFunction( void * pvParameters )
{
	TickType_t xLastWakeTime;
	const TickType_t xPeriod = pdMS_TO_TICKS( 5 );//5ms的延时
	xLastWakeTime = xTaskGetTickCount();  
	for(;;)
	{		
		lv_task_handler();//在裸机里放在while循环中即可
		vTaskDelayUntil( &xLastWakeTime, xPeriod );//绝对延时
	}
}


int main(void)
{

    lv_init();
	lv_port_disp_init();

	//测试代码--显示一个label
	lv_obj_t * label1 = lv_label_create(lv_scr_act(), NULL);
	lv_label_set_long_mode(label1, LV_LABEL_LONG_BREAK);     
	lv_label_set_recolor(label1, true);                      
	lv_label_set_align(label1, LV_LABEL_ALIGN_CENTER);
	lv_label_set_text(label1, "#0000ff Re-color# #ff00ff words# #ff0000 of a# label "
																										"and  wrap long text automatically.");
	lv_obj_set_width(label1, 150);
	lv_obj_align(label1, NULL, LV_ALIGN_CENTER, 0, -30);

    BaseType_t xReturn  = pdPASS;

    xTaskCreate(vLvglTaskFunction, "lvgl_task", 512, NULL, 2, &xLvglTaskHandle);
    //xTaskCreate(arc_loader, "lvgl_task", 512, NULL, 2, &xLvglTaskHandle);
            
    if(xReturn == pdPASS)
                vTaskStartScheduler();//任务调度器			//当程序执行完这句话之后,正常情况下下面的代码不会再运行,只会运行任务主题函数
}

-- 注意:这里用了lvgl的初始化函数,不用再用lcd的初始化了,前面已经把lcd初始化函数写在了lvgl的初始化函数里面了。

-- 测试效果图

lvgl的中文教程手册网站

-- 该网站包含各种事例代码和图形库

-- 英文 Layers --- LVGL documentation

-- 中文 基础对象(lv_obj) --- 百问网LVGL中文教程手册文档 1.0 文档

lvgl的基础知识

-- lvgl是一个图形库

-- 那么什么叫做图形库呢?

-- 这些就是一个一个的图形

-- 每个图形又可以称为对象

-- 对象的属性:假如要绘制一个仪表盘,那么他的大小设置多大,位置放在哪里。能不能拖动呢?是否被拖动?

-- 对象的层级:父子,小介面基于大介面的基础上创建出来的,例如在大介面上点击一个按钮导致小介面生成。

-- 事件:点击,拖动,长按,松开,滚动等等

-- 这个事件怎么处理呢?

  • 当事件发生时,lvgl会跟根据提前定义好的回调函数进行处理,回调函数可以自己定义,也可以使用lvgl提供的回调函数。

  • 不同的对象所对应的事件也不同

-- 还有特殊的事件,键盘或者事件编码

-- 输入设备:触摸屏,键盘,鼠标,编码器等等

-- 显示:

-- 字体:LVGL 支持 UTF-8 编码的 Unicode 字符。需要配置的编辑器,以将的代码/文本保存为 UTF-8 (通常是默认值)

-- 在lvgl里面,只要显示汉字,一定要在UTF-8格式下写汉字

-- lvgl是有自己的一个操作系统的,只是目前我们还没有使用

-- 重点是lvgl基础控件的使用

-- 例子:圆弧展示进度条

-- 首先将代码复制到咱们的程序里面

cs 复制代码
static void arc_loader(lv_task_t * t)
    {
            static int16_t a = 270;

            a+=5;

            lv_arc_set_end_angle(t->user_data, a);

            if(a >= 270 + 360) {
                    lv_task_del(t);
                    return;
            }
    }

int main()
{

    lv_init();
	lv_port_disp_init();

    //显示一个圆弧(进度条)
/*Create an Arc*/
    lv_obj_t * arc = lv_arc_create(lv_scr_act(), NULL);
    lv_arc_set_bg_angles(arc, 0, 360);
    lv_arc_set_angles(arc, 270, 270);
// lv_obj_align(arc, NULL, LV_ALIGN_CENTER, 0, 0);//改变了对象的位置
    lv_obj_set_pos(arc,20,60);//设置起点位置
    lv_obj_set_size(arc,200,200);//设置对象大小

    /* Create an `lv_task` to update the arc.
* Store the `arc` in the user data*/
    lv_task_create(arc_loader, 20, LV_TASK_PRIO_LOWEST, arc);
	
}

-- 结果图太小了,需要找个能改变自身大小的

  • 相关api

  • 设置位置

cs 复制代码
lv_obj_set_pos(arc,20,60);//设置起点位置
  • 设置对象大小
cs 复制代码
lv_obj_set_size(arc,200,200);//设置对象大小

-- 至此就可以添加一个圆弧图形了,但是这个圆弧是静态的,需要添加一个定时器,让圆弧动起来。所以前面写的时钟钩子函数就可以派上用场了。

-- 如何用lvgl去制作软件

-- 安装软件

-- 1、先安装Java环境(注意一定要先安装java环境)

-- 2、安装软件

-- 3、打开软件,点击创建,选择v7

-- 4、工程的名字和路径都不能出现中文,屏幕的类型如果选项中没有的话,可以自己定义

-- 5、创建成功后,会跳转新的界面,将右上角英文切换成中文,界面的颜色也可以选择,可以改为深蓝色或者其他颜色

-- 6、可以先选择一个图片当作背景,将图片拖拽过来,可以通过更改参数让它显示在全屏

-- 7、新增界面

-- 8、可以更改背景的颜色

-- 9、也可以更改图片的透明度,255是不透明,0是完全透明

-- 10、设置文本

-- 11、将表格拖进界面

-- 12、有些是不能用的

-- 13、将图形界面设计完之后,点击编译,编译成功后就会将配置好的界面显示出来

-- 14、注意:这个编译默认编译的是第一个界面,如果向编译其他界面。

-- 都编译成功后,开始将代码放到工程中

-- 15、先找到工程所在地方

-- 16、

-- 17、了解这些文件的作用

-- 18、在工程中新建文件夹

-- 19、添加头文件路径

-- 20、之后编译,出现错误

更改错误

-- 1、修改界面文件

-- 2、更改图模文件

-- 3、更改字模文件

-- 4、修改系统自带文件

-- 5、之后编译,然后有的电脑还会出现错误,有的没有

-- 6、添加一个定义

-- 7、修改错误,一般就是中文汉字编码的错误

  • 只要有汉字,就会报两个错
-- 8、只要使用汉字,都按照下面这种方式修改

-- 解决方案一:显示的字符串,最后不能以汉字结束。在字符串结束,加一个空格

  • 点击错误跳转到出错的地方,将字符串最后加一个空格
  • 其中这个摄氏度就是中文的。

-- 解决方案二:将keil的编码格式修改为utf-8,然后在这种编码格式下重新输入汉字

-- 然后在这个格式下重新输入汉字,为了保险起见,后面也加上空格

屏幕显示调用

-- 将代码复制到main函数中

-- 加上头文件

-- 这两个代码分别是创建和显示

-- 只有创建函数的话,只会创建,创建完之后不会显示

-- 要想在屏幕中显示,必须要调用显示函数

-- 此时显示的界面是screen1,如果想要显示其他界面,如screen,只需要将screen1改为screen即可

-- 但是如果两个显示函数都调用的话,只会显示后面调用的那个

-- 那么如何实现切换界面

  • 1、将创建函数写在main函数中
  • 2、然后在按键任务中调用显示函数
  • 3、加一个标志位,防止多次点击同一按键,导致界面反复切换同一个界面无意义
  • 3、代码
cs 复制代码
uint8_t GUI_flag = 0;
//2
void KETTaskCreat(void *pvParameters)
{
	uint8_t keyflag = 0;
	uint8_t buff[10]={0};
    while(1)
    {
				keyflag = get_key();
				switch(keyflag)
				{
					case 1:
						
					
						if(GUI_flag!=2)
						{
								lv_scr_load(guider_ui.screen);	//显示
							GUI_flag=2;
						}

					break;
					case 2: 

					if(GUI_flag!=1)
					{
						GUI_flag =1;
						lv_scr_load(guider_ui.screen_1);	//显示
					}
					break;
				}  
			vTaskDelay(50);				//在任务周期时可以释放cpu
    }
}
如何实现界面刷新(界面中的数据如何变化)

-- 1、实现文本数据刷新

-- 要想实现数据更新,必须要找到对应的对象,然后调用对应的赋值函数

-- 例如界面一的温度数值,先找到界面一对应的赋值函数,复制

-- 将函数复制到lcd显示任务函数中,直接将数值更改为变量,就可以实现动态更新数值了。

cs 复制代码
void LCDTaskCreat(void *pvParameters)//函数名称不固定,参数格式是固定的(任务一定是一个while循环,每个任务一定要有自己的任务周期)//设置任务周期的目的就是可以让任务可以主动释放cpu(指的是任务能够自动释放cpu)
{
	//BaseType_t xReturn = pdPASS;//有没有获取成功,再显示LCD
	EventBits_t r_event;
	while(1)
	{
		r_event = xEventGroupWaitBits(Event_Handle, /* 事件对象句柄 */
																	0x07,/* 接收任务感兴趣的事件 */
																	pdTRUE,/* 退出时清除事件位 */
																	pdFALSE,/* 满足感兴趣的所有事件 *///逻辑或
																	500);/* 指定超时事件,一直等 */
		//dht
		if(r_event &(0x1<<0))//判断这个数中的位0是否为真
		{

			sprintf(D_wen, "tem: %.2d鈩?",(int)dht.tem);
			
			 //实现数据更新
                        
       //找到对应对象的赋值函数
			
			lv_label_set_text(guider_ui.screen_1_label_1, D_wen);
			
		}

    }
    }

-- 2、实现表格数据刷新(折线图)

-- 找到对应的赋值函数

-- 在lcd函数中调用

将值改为变量

-- 效果图

总结

-- 1、进行界面设计,注意先考虑好布局(做几个界面,每个界面显示什么内容,如何规划)

-- 2、保证每个界面在屏幕上都能显示出来

-- 3、保证界面相互切换不会卡死

-- 4、界面刷新

相关推荐
子朔不言7 小时前
[ARM-2D 专题]5 MDK编译器一个旧版本-Ofast优化bug的问题及解决办法
arm开发·mcu·方案开发·arm-2d
青山师1 天前
Mqtt协议快速入门Demo
物联网·mqtt
周珂呀3 天前
Linux 命令行学习:数据流控制、文本处理、文件管理与自动化脚本 (第二天)
linux·前端·chrome·操作系统·终端·基础知识
编程老船长4 天前
献给刚入学的大学生-如何使用微PE工具箱或其他工具制作 Windows 11 U 盘启动盘
windows·操作系统
Eloudy4 天前
关注 dlopen(handle, mode) 中的 mode,dlsym dlclose示例
操作系统·动态库
_小猪沉塘5 天前
【哈工大_操作系统理论】L26&27 IO与显示器&键盘
操作系统
Harper. Lee5 天前
【OS】2.1.2 进程的状态与转换_进程的组织
笔记·操作系统·os·1024程序员节
tt5555555555555 天前
操作系统学习笔记2.3互斥
笔记·操作系统·1024程序员节
碳苯5 天前
【rCore OS 开源操作系统】Rust trait 特性快速上手
开发语言·人工智能·后端·rust·操作系统·trait