基于Keil5移植LVGL,懂得原理之后什么开发板都可以移植

今天我们来移植一下LVGL,其实LVGL和Qt差不多,操作起来都很简单,看着官方文档都可以自己学习使用。

难就难在移植上面,移植个LVGL花了我三天才弄明白(虽然最后发现在一个很弱智的问题上耽误了我两天),网上的教程基本上只说应该怎么做,都没有说为什么要这么做,那么今天我们就来移植一下,知道原理之后就可以举一反三地去移植任何开发板了。

包括移植也是有官方手册的,英文好的小伙伴可以自行去查阅。官方手册讲的肯定比我好。

Porting — LVGL documentationicon-default.png?t=N7T8https://docs.lvgl.io/master/porting/index.html

虽然说是可以移植任何开发板,但是还是有要求的。

而我们常用的STM32C8T6是不符合要求的,GD32E230也是不符合要求的(虽然网上好像有移植成功的案例,但是作为初学者我们尽量还是拉高配置吧,省的不必要的麻烦),我这边用的是GD32F407VET6,配置上是足够的,包括ESP32-S3什么的也是满足要求的。

那么确认手上板子能够移植LVGL之后我们就可以进行下一步了,首先先要获取到LVGL的库文件,这个需要我们到github上面去下载。

https://github.com/lvgl/lvglicon-default.png?t=N7T8https://github.com/lvgl/lvgl考虑到github常常进不去,我把常用的版本给下载下来了。

链接:https://pan.baidu.com/s/1ubfUKtC1EuiZ_fM9rX4aHg?pwd=u5b7 
提取码:u5b7

里面是8.2,8.4和9.1。其中8.4和9.1是官方推荐版本,而8.2是部分网上视频教程里用的(某点原子),我接下来以8.4为例。

我们需要先整一个手上开发板可以用的工程文件,可以是空白的,但是要编译通过,这个不难,你就拿你之前项目的文件就行。

接着我们把下载好的LVGL解压。

得到的是这样的。

其中大部分文件是可以删除的,当然你不删也可以,但是会显得很臃肿。

我们来明确一下LVGL是什么东西,不要把LVGL当成是什么很高大上的东西,说白了就是第三方库,和我们自己封装的头文件什么的是一个样的,只不过人家LVGL的文件数量多了点,仅此而已。

既然和我们写的头文件一样,那么我们只需要保留.c和.h文件即可,其他后缀的都是可以删除了。

接下来我们就对解压过后的LVGL进行删减。

只留下面这三个文件夹和两个.h文件即可。

为什么把其他的删掉呢?那当然是因为它们不包含我们需要的.c和.h文件啦。

顺便把留下的这五个东西介绍一下。

第一个demos,跟它的名字一样,存放的是官方的demo,因此实际上我们也是可以删掉的,留下来的原因就是等我们移植完LVGL之后可以调用一下demo看看效果。

第二个examples,存放的是一些关于示例代码,我们只需要留下里面的porting即可。

然后porting里的文件是三个(一对的.c和.h算一个)。

disp是显示相关的模板,fs是文件管理的模板,indev是输入相关的模板。

因为我的屏幕没有输入,也不需要文件管理,因此对于我来说只需要disp即可,但是其他没用到的最好也别删了,保不齐什么时候就用上了(没事的时候打算整个触摸屏再移植一下LVGL玩玩)。

然后就是src,这个就是核心的文件了,一个都不能少。

lv_conf_tempplate.h这个文件是配置文件。

lvgl.h这个头文件里面包含了我们常用的其他头文件,因此我们只需要包含这个就等同于包含了其他很多头文件了,比较方便。

然后配置文件的名字我们需要把后面的_template给删掉,变成lv_conf.h。

修改名称的原因就在于LVGL里面源文件中包含的配置文件的名称就是lv_conf.h,

那么接下来我们就要把LVGL的文件加入到我们的工程文件里了。

接下来在你工程文件里存放模块的文件夹里新建一个文件夹来存放LVGL的文件(名字随意,我这边就叫LVGL)

接下来在这个LVGL的文件夹里再新建两个文件夹,名字随意,一个用来存放源码一个用来存放官方demo,其实是可以省略的,只不过我们要运行官方demo的话区分一下会比较清晰,如果不需要运行官方demo的可以省略这一步,直接跳到下一步。

我这边就借用一下某点原子的命名规则了,建立两个文件夹,GUI用来存放源码,GUI_APP存放官方demo。

接着在把删减过后的LVGL中的demos文件夹放到GUI_APP里(跳过上面一步的小伙伴这一步也可以省略)。然后在GUI里建一个名为lvgl的文件(这里名字是固定的,一定要这么写,否则后续要修改的地方非常多),接着把剩余两个文件夹和两个头文件放到这个lvgl文件夹里。

最后就是这样子的。

其他命名啊,结构啊什么的都无所谓,但是lvgl这个文件夹是一定要安装这个名字去创建的,并且要像上图这样把删减后的LVGL放进去。

我们随便打开一个lvgl源码的头文件,可以发现人家包含头文件是有一定结构的,因此我们需要按照这种结构去存放lvgl的源码。

那么接下来我们的工程里有了LVGL的代码了,我们就需要再Keil里设置包含住他们。

首先现在分组里添加上一些组。

可以看到我设置的分组的名字和我们LVGL文件名称是基本对应的,不过实际上分组名字是可以随便起的,你要是乐意起个ABCD都是可以的,但是名字对应上方便我们查看代码。

这边分组完我们还需要把每个文件夹内的.c文件放进每个分组里,记得不要重复包含,也不要漏掉包含,就这一步是最容易疏漏的。

每个文件夹内的文件夹里的.c文件也是需要包含的,虽然大部分我们用不上,但是作为小白的我们暂时还分不出哪些是可以不用的,所以我们就麻烦一下全部加上。

记住,是对应分组的文件夹里的所有.c文件!!!

这一步是最繁琐也是最容易出问题的,如果移植失败,那么90%的原因是在这里!!!

添加完毕之后在左侧我们就可以看到添加进工程的文件了。

但是光添加进来没有用,我们还得让编译器知道这些文件的存在,因此我们还需要添加头文件路径。就像下图这样,可以顺便把C99给勾上。

一共往上面添加四个路径。

这个根据大家命名的不同需要选择不同的路径,但是通过上面这个图,大体上可以看出需要包含哪些路径的对吧。

上面步骤做完之后我们就可以先编译一下看看有没有什么不对的地方了。

会有警告,但是正常情况不会有报错,我们选择无视警告。

如果有报错的,一般是报这个错误Error: L6218E: Undefined symbol ,这种情况基本就是给分组添加文件的时候没有添加全,换句话说就是没把某些LVGL的文件添加进我们的工程中。

报错的小伙伴重新再把文件添加进工程里,记得不要重复包含。

只有警告的小伙伴可以跟我一起进行下一步了。

我们再新建个分组,把配置文件添加进来,不进行这一步也可以,但是就需要在Keil外面修改配置文件了。

第一步我们就先把配置文件给打开,打开的方式就是把这个判断条件修改为1。

包括其他配置也可以在这个文件里进行修改。

比如下面这个宏定义,就是给LVGL分配的内存大小。

默认给48KB,我的板子是给的起,但是有些板子内存资源可能有些不太够,分太多会编译报错,那么就可以在这边修改小一点,但是最小不要小于2KB。

还有颜色相关的配置也在这边。

默认的颜色像素是RGB565,如果你们的屏幕不是RGB565的话,就是在这边修改的。

下一步把显示相关的.c和.h也打开,也是通过修改判断条件。

接着修改宏定义来指定屏幕大小。

按照顺序分别是宽和高。

如果是8.2版本的是没有这俩宏定义的,需要自己去定义。

接着我们需要指定LVGL的缓冲模式,有三种,按照顺序效果是越来越好的,但是相对的内存消耗会更大,大家量力而行,一般来说模式一都够用了。

选择的方式就是把另外两种模式的代码注释掉。

看的出来我们上面的宏定义是有用在这边的。

然后因为这是和显示相关的,因此我们肯定是需要自己的屏幕驱动代码的,不懂写的小伙伴可以回顾一下我之前的文章。

【硬件模块】ST7735S(1.8寸TFT-LCD)-CSDN博客SPI,英文全称Serial Peripheral Interface,即串行外围设备接口,是一种高速、全双工、同步的串行通信总线。我们之前说过I2C,那么我们就拿I2C和SPI做个对比。SPI和I2C对比,优势在于SPI的传输速率比I2C快得多,劣势在于SPI需要用的通信线比较多。SCK(Serial Clock):串行时钟线,由主设备产生,用于同步数据传输。MOSI(Master Output Slave Input):主机输出从机输入线,主设备通过这条线发送数据给从设备。https://blog.csdn.net/m0_63235356/article/details/139422591?spm=1001.2014.3001.5502

在LVGL显示相关的文件中包含我们的屏幕驱动代码。

接着在disp_init这个函数里调用我们屏幕的初始化函数。

disp_flush函数里调用我们的打点函数。

其中函数的形参area是个结构体,一共有四个成员,分别是x1,x2,y1,y2,表示打点的范围,color_p是像素点的数组,我们一般是要强转一下类型再给我们的打点函数。

上面是我写的打点函数,大家根据自己的驱动去填写参数即可。

那么关于显示的配置我们就算配置完了,因为我的屏幕不是触摸的,因此我就不配置输入相关的了,不过大致流程也是这样的。

接下来我们回到我们的主函数。

先包含两个头文件,我这是只有输出的,如果配置输入的话,还需要包含另外一个"lv_port_indev_template.h"。

#include "lvgl.h"
#include "lv_port_disp_template.h"

我们最后还需要给LVGL一个心跳,也就是我们需要使用定时器,在一定的时间里调用一个LVGL的函数lv_tick_inc。

不懂定时器的小伙伴可以参考我之前的文章。

STM32,ESP32,GD32都有,往前翻一翻。

然后我们每隔1ms进入一次中断,我们就给lv_tick_inc这个函数传入1,如果是隔5ms一次进入中断,那么给的参数就是5,也就是说隔几毫秒,传的参数就是几。

接着在主循环里每隔5ms调用一次lv_timer_handler就可以了。

那么我们就算是移植完LVGL了。

但是我们要看效果,还需要调用一些初始化函数,下面是输出的初始化,如果有输入的话,还需哟啊调用输入初始化函数。

    lv_init();lv_port_disp_init();

初始化完之后我们再创建组件,鉴于大家都是小白(包括我),因此我们直接从官方文档里复制示例代码来看看效果。

我这里就只贴出main.c的内容,大家大概知道流程是怎么样的就可以了。

#include "board.h"
#include "Z_TFT.h"
#include "Z_Timer.h"#include "lvgl.h"
#include "lv_port_disp_template.h"void TIMER0_UP_TIMER9_IRQHandler(void){if(timer_interrupt_flag_get(TIMER9, TIMER_INT_FLAG_UP) == SET)    {        timer_interrupt_flag_clear(TIMER9, TIMER_INT_FLAG_UP); // 清除中断标志位   lv_tick_inc(1);}
}int main(void){board_init();Z_Timer_Init();lv_init();lv_port_disp_init();lv_obj_t * bar1 = lv_bar_create(lv_scr_act());lv_obj_set_size(bar1, 100, 20);lv_obj_center(bar1);lv_bar_set_value(bar1, 70, LV_ANIM_OFF);while (1){delay_ms(5);lv_timer_handler();}
}

效果是这样的。

那么至此,各位就成功地移植LVGL了,完整做下来之后实际上没有那么困难,LVGL就是普普通通的第三方库,我们要做的就是把这一堆文件塞进我们工程里,再让我们的编译器识别到这些文件就行了。

最后再总结一下可能会出错的点。

第一个点就将文件包含进工程里,这是最容易出错的地方,多了少了都可能会出错。

第二就是配置显示的时候自己的屏幕驱动了,不过跟我的驱动走没什么大问题。

我这边留个课后作业,我们做删减的时候不是把LVGL的官方demo留下来了嘛,给大家的作业就是运行这些官方demo,流程是一样的,就是把文件包含进工程里,再添加头文件路径,然后改个配置调用即可。

算了,带大家做一遍吧。

一样是先创建分组,再把文件弄进来,板子配置一般的小伙伴运行stress那个demo,配置好的可以用music。我这边用stress,本来想玩一玩那个music的,但是调了一会还是运行不了music然后就放弃了。

接着是头文件路径,我们一样是加进来,不同的demo用不同的路径。

然后在配置文件里打开stress的宏定义,不同的demo打开不同的宏定义。

完成上面步骤之后就可以运行了,在main.c里包含一下lv_demo_stress.h,再调用lv_demo_stress就可以了。

我们就可以看见屏幕正在飞快刷新着,这是LVGL在不断地调用各种组件。

至此,我相信各位小伙伴都已经会移植LVGL了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/23086.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle 打补丁遇到 check “CheckActiveFilesAndExecutables“ failed报错处理方法

该报错是因为打补丁的时候停止集群没有停止干净进程导致的 问题 处理方法 强制停止打补丁所在节点集群服务 查看grid和oracle相关进程是否停止干净,发现有未关闭的进程手动kill 处理完毕继续打补丁即可

跟着大佬学RE(四)

几个API函数 [ACTF新生赛2020]Universe_final_answer 一个很多方程组的函数,还有一个嗯,对input进行一些操作的函数 嗯,确实方程解出来得到 key 直接运行就可以得到 flag 了,不过还是去分析了一下。 v22 __readfsqword(0x28u);…

【深度学习】安全帽检测,目标检测,Faster RCNN训练

文章目录 资料环境尝试训练安全帽数据训练测试预测全部数据、代码、训练完的权重等资料见: 资料 依据这个进行训练: https://github.com/WZMIAOMIAO/deep-learning-for-image-processing/tree/master/pytorch_object_detection/faster_rcnn ├── bac…

nt9856_sensor_driver camera i2c无响应

前言 最新更换了不同的平台进行开发,所以一心在研究和学习中,没有太多的时间发布文章,最近开开始上手了,抽空把之前的工作记录进行总结和发布。从原来的高通和瑞芯微转到了国科和海思联咏,整体的架构不太一致&#xff…

【JVM】已验鼎真,鉴定为:妈妈加载的(双亲委派模型)

【JVM】已验鼎真,鉴定为:妈妈加载的(双亲委派模型) 在Java的世界中,类加载器(ClassLoader)是Java虚拟机(JVM)用来动态加载类的基础组件。双亲委派模型(Paren…

安装和使用conda

Conda 是一个开源的软件包管理系统和环境管理系统,用于安装多个版本的软件包及其依赖关系,并在它们之间轻松切换。可以创建多个环境,并在环境中使用不同的python版本,并安装环境专属的python依赖包,可以用来避免python…

MySQL中:cmd下输入命令mysql -uroot -p 连接数据库错误

目录 问题cmd下输入命令mysql -uroot -p错误 待续、更新中 问题 cmd下输入命令mysql -uroot -p错误 解决 配置环境变量:高级系统设置——环境变量——系统变量——path编辑——新建——MySQL.exe文件路径(如下图所示) phpstudy2018软件下&am…

王学岗鸿蒙开发(北向)——————(二)TS基本语法详解

1,Ts(TypeScript)语法相当于JAVAScript类型,鸿蒙arkTs是基于TS语言的,当然artTs也融合了其它的语言。 2,本篇文章是基于n9版本。注意,有些语法是已经不能用的。 3, 4,变量:用来存储数据,数字字母组成,数字不…

泛微开发修炼之旅--07通过后端代码实现创建并发送待办、源码及示例

文章链接:泛微开发修炼之旅--07通过后端代码实现创建并发送待办、源码及示例

解决找不到api-ms-win-crt-runtime-l1-1-0.dll问题的5种方法

电脑已经成为我们生活和工作中不可或缺的工具,然而,由于各种原因,我们可能会遇到一些常见的问题,其中之一就是电脑缺失api-ms-win-crt-runtime-l1-1-0.dll文件。这个问题可能会导致电脑出现错误提示、程序无法正常运行等困扰。为了…

[Redis]Zset类型

Zset有序集合相对于字符串、列表、哈希、集合来说会有一些陌生。 它保留了集合不能有重复成员的特点,但与集合不同的是,有序集合中的每个元素都有一个唯一的浮点类型的分数(score)与之关联,着使得有序集合中的元素是可…

Python04:python代码设置作者/创建时间/文件名称

我们新建一个py文件时,如果希望文件开头有固定的内容,怎么设置呢? 比如代码作者、文件创建时间等。。。 1、点击左上角【Python】–>【Settings】设置 2、在弹出的新窗口找到【File and Code Templates】–>【Python Script】–>在右…

6_5 test

Lucene 存储引擎 https://www.cnblogs.com/tech-lee/p/15225276.html\ 规范 问问题的技巧 提问者:要实现怎样的目标?自己计划是如何实现这个目标的?问题出现在哪个环节?自己为了解决这个问题,已经做了哪些尝试和工…

【ubuntu软件版本管理】利用update-alternatives管理ubuntu软件

​ 我们有的时候希望在安装了新软件之后保留旧版本的软件,比如希望保留旧版本的gcc,以防以前写的C编译出问题,这时候就需要版本管理软件update-alternatives。 ​ 在此之前我们需要先弄清楚,什么是ubuntu的软件?拿C源…

推荐系统学习 一

参考:一文看懂推荐系统:召回08:双塔模型——线上服务需要离线存物品向量、模型更新分为全量更新和增量更新_数据库全量更新和增量更新流程图-CSDN博客 一文看懂推荐系统:概要01:推荐系统的基本概念_王树森 小红书-CSD…

Python 全栈体系【四阶】(五十七)

第五章 深度学习 十三、自然语言处理(NLP) 2. 传统NLP处理技术 2.4 关键词提取 关键词提取是提取出代表文章重要内容的一组词,对文本聚类、分类、自动摘要起到重要作用。此外,关键词提取还能使人们便捷地浏览和获取信息。现实…

Qt 的 d_ptr (d-pointer) 和 q_ptr (q-pointer)解析;Q_D和Q_Q指针

篇一: Qt之q指针(Q_Q)d指针(Q_D)源码剖析---源码面前了无秘密_qtq指针-CSDN博客 通常情况下,与一个类密切相关的数据会被作为数据成员直接定义在该类中。然而,在某些场合下,我们会…

这才是大模型价格战背后的真相

想必大家今天肯定被各家大模型厂商的降价新闻刷圈了,如果说 Meta Llama 3 的开源是国外大模型市场的搅局者,那 DeepSeek-V2 就是国内大模型市场的鲶鱼,但是价格战背后是大模型基础设施优化带来的物美价廉,还是浑水摸鱼的噱头&…

引擎:Shader

一、原理 创建Shader脚本,创建材质球,将物体的渲染效果Shader脚本挂载到材质球,最后把材质球挂到3d物体上面从而实现渲染。 二、模型边缘发光 原理:正对着摄像机的模型三角面边缘光最弱,垂直于摄像机的模型三角面边缘光…

解锁下载EasyRecovery2024电脑版软件 3步破解下载秘籍!

在数字时代,数据已成为我们生活中不可或缺的一部分。无论是工作中的重要文件,还是珍贵的家庭照片和视频,数据都承载着我们的回忆和努力。然而,数据的丢失也是我们常常遇到的问题。硬盘损坏、误删除、病毒攻击等都可能导致数据丢失…