本帖最后由 dffzh 于 2025-5-12 08:53 编辑
#申请原创#
@21小跑堂
LVGL,全称Light and Versatile Graphics Library,是一款免费的开源的轻量级多功能的嵌入式图形库,能够为任何MCU、MPU及显示设备创建优美的UI界面。 做HMI(人机交互界面)显示屏开发的行业会经常用到LVGL库,作者就通过本文与大家分享一下自己实操的关于LVGL的代码移植和操作,因初识LVGL,也参考了其他大佬的文章,不足之处,还望指正。 大家可以在github链接里下载合适的LVGL的SDK(软件开发套件)版本: https://github.com/lvgl/lvgl
其中v8.3版本是目前广泛使用的版本,当然其他版本也可以。 另外,可以通过CHANGELOG.md文件查看版本更新及修改的日志记录: 下载:
在根目录的lvgl.h头文件里可以查询到版本信息:主版本号.次版本号.补丁版本号 SDK裁剪:lvgl-release-v8.3文件夹的根目录内容如下:其中需要用到的主要是3个文件夹+2个头文件,如红色框所示: 查看lvgl.h文件,里面都是使用相对路径包含头文件的,为了使裁剪和移植后的文件能直接使用这些相对路径,我们复制文件时,按以下的目录结构来操作:新建文件夹“lvgl”,将用到的3个文件夹和2个h文件放到里面,如下: 其中:lvgl.h文件:包括所有LVGL用到的头文件,以及读取LVGL固件版本的接口;lv_conf_template.h文件:LVGL配置参数的重要文件,默认为关闭功能;使用时需将其名称更改为lv_conf.h,并开启功能; 修改后如下: 删除lvgl\examples目录下面不需要的文件夹,只保留porting文件夹; 并将porting文件夹下面的6个文件的文件名上的_template去掉,修改如下: 至此,lvgl文件夹的构架基本完成,并且这个可以复制给各类工程使用。
接下来就可以将其移植到具体的MCU工程中去了。移植后的LVGL目录结构如下,红色方框为需要使用的文件/文件夹: 注册显示功能的相关代码操作 1、启用lv_conf.h 2、启用lv_port_disp.h 3、启用lv_port_disp.c 4、添加LCD驱动的头文件 在lv_port_disp.c文件里包含你的LCD驱动头文件,目的是让这个C文件可以调用LCD的画点函数,比如:#include “bsp_lcd.h”,查看你的显示屏参数,修改实际像素:
5、选择创建缓存的方式 在lv_port_disp.c文件中,LVGL提供了创建显示缓冲区的3种方式,必须3选1,;在绝大多数情况下,使用第1种方法,即只创建1个缓冲区:
6、关联画点函数 在lv_port_disp.c文件中,找到disp_flush()函数,并调用你的画点函数,比如:
LCD_DrawPoint( x, y, color_p->full) ; 这里给LVGL一个画点函数后,LVGL就能完成需要的显示操作了。至此,显示的注册已经完成。
注册触摸屏功能的相关代码操作 1、启用lv_port_indev.h 2、启用lv_port_indev.c 3、添加触摸屏的驱动头文件 在lv_port_indev.c文件中包含触摸屏的驱动头文件,比如:
#include “bsp_touch.h”,这样这个C文件就可以调用触摸屏的触摸状态检测函数、坐标获取函数; 4、注释掉不需要的输入任务注册 在lv_port_indev.c文件中,包含了5种输入方式的任务注册: 触摸屏 鼠标 键盘 编码器 物理按键 保留触摸屏输入的任务注册,其他4种可以先注释掉;即在lv_port_indev_init函数里,只保留与触摸屏注册任务相关的代码即可; 5、添加触摸检测函数 在lv_port_indev.c文件中,找到触摸状态检测函数touchpad_is_pressed,改成如下: 其中返回FALSE表示未触摸,TRUE表示触摸中。 6、添加坐标获取函数 在lv_port_indev.c文件中,找到坐标获取函数 touchpad_get_xy,本函数可以使LVGL能够获取到触摸按下时的x和y坐标,可以改成如下:
至此,触摸屏的注册已经完成。
添加LVGL的文件引用到MCU工程
在修改完成LVGL的显示、触摸注册后,即可正式应用LVGL。 1、添加LVGL头文件到工程 可以在main.c头部包含以下三个LVGL的头文件: #include "lvgl.h" // 它为整个LVGL提供了更完整的头文件引用 #include "lv_port_disp.h" // LVGL的显示支持 #include "lv_port_indev.h" // LVGL的触屏支持 2、初始化LCD、触摸屏 比如按以下格式初始化: LCD_Init(); // 初始化 LCDLCD_SetDir(1); // 设置LCD的显示方向:横屏 touch_Init(xLCD.width, xLCD.height, xLCD.dir); // 初始化触摸屏 注意: 也可以在lv_port_disp.c文件的disp_init函数里填入LCD的初始化函数,在lv_port_indev.c文件的touchpad_init函数里填入触摸屏的初始化函数,两种方式均可,自己选择。 3、初始化LVGL、LCD和触摸屏在硬件的初始化代码之后,进行LVGL的初始化: lv_init(); // LVGL 初始化 lv_port_disp_init(); // 注册LVGL的显示任务 lv_port_indev_init(); // 注册LVGL的触屏检测任务 4、显示按钮控件、文本控件在LVGL的初始化之后,可以添加LVGL控件,用来测试LVGL的显示: 添加一个按钮; 为按钮添加文本; 添加一个独立的标签文本; 代码如下:
LVGL的心跳和任务刷新 LVGL需要处理两个时间任务:心跳和任务刷新 1、心跳 间隔1ms,精准的调用时基函数(心跳函数)lv_tick_inc(),让LVGL精确地知道时间的流逝,对于图形界面的流畅运行比较重要; 如果心跳函数调用间隔不准确,可能会导致显示卡顿、任务处理不及时; 建议使用MCU的外设定时器外设产生1ms中断,并设置其优先级为高,通过中断函数调用LVGL的心跳函数。 心跳函数的定义如下: 被调用如下: 另外,其实你也可以在LVGL的官网https://lvgl.io查询到相关资料: 2、任务刷新 间隔5ms左右,调用周期性函数 lv_timer_handler(),其作用是检查所有注册任务的时间戳,执行那些已经到期的任务,如屏显刷新、触控、定时器事件等。 简单地理解,就是每隔5ms左右让LVGL刷新(活)一次,定期检查所有已注册任务的时间戳; 可以在main.c的while(1)循环里每隔5ms调用一次周期性函数;由于该函数的执行时间有点长,为避免霸占中断资源,不要直接在定时器中断里调用它;在LVGL的8.1.0版本里,该函数还被封装了一层,在 lv_api_map.h文件中,如下所示:
因此,使用时直接调用lv_task_handler()函数即可,如下:
控件的事件添加、响应处理LVGL的学习,其实可以分为两个部分: 1、界面绘制 LVGL的界面绘制,更常规的操作其实是先使用可视化工具进行设计,再把界面工程移植到MCU; 2、事件处理 这块逻辑在MCU代码里直接编写; 举例说明事件添加和响应处理:
在原来添加按钮的代码后面,增加一行,为控件添加事件: 参数解释: myBtn:要添加回调函数的控件的名称,不限于按钮; myBtn_event:事件响应时,LVGL调用的为对象分配的回调处理函数,需要自行手动编写; LV_EVENT_CLICKED:点击事件;不同的控件,有不同的事件类型(见lv_event_code_t); NULL:传递给回调函数的可选用户数据,这里暂时不用.
添加事件的函数简介如下: 手动编写的事件响应处理函数: 功能:按一次按钮,按钮上的文本数字加1后显示;
“Button 1” “Button2” ……“Button n” 删除事件:
可以通过以下两种方法对事件进行删除: 关于LVGL的SDK文件介绍,详细使用方法和具体应用操作等,可以在官网上学习,资料还是比较丰富的:
|
一篇教你如何简单入门MCU的LVGL,作者通过分享实操过程中的LVGL的移植过程,带你初识LVGL,助力入门参考,提供一定的开发帮助。
@21小跑堂 管理员,求原创审核哦!