当前位置: 首页 > news >正文

STM32进行LVGL裸机移植

本文的移植参考的是正点原子的课程《手把手教你学LVGL图形界面编程》

基于该课程和《LVGL开发指南_V1.3》“第二章 LVGL 无操作系统移植”,然后结合自身的实际情况进行整理。

先根据自己的习惯,创建基础的单片机工程,然后在APP业务层和DRIVER驱动层之间加上MIDDLEWARE层,在这一层中加入lvgl。

另外,这里还有句话:

所以如果用到lvgl,尽可能使用裸机开发。

基于LVGL版本V8.2。

先看下移植要求

这个图形缓冲区的意义是,不会来一个点就刷新一次,而是至少缓冲到一行之后再刷新,防止画面不断闪烁卡顿,效率更高。所以才要求>水平分辨率像素。缓冲区其实就是个数组,数组大小,至少是一行像素所占用字节的大小,假如屏幕大小是300*240,所用的颜色是16位的,也就是一个像素点占两个字节,那么数组大小就要求至少是300*2=600字节大小。

如果想要更流畅,就建议大于1/10屏幕总像素。也就是300*240/10*2=14400字节,也就是15k字节左右。(貌似对内存要求有点高,那么点内存好像不够用呀???待解决。)

另外注意要勾选C99,要不然编译时会报很多错误。

优化LVGL运行效果的方法

关键点其实就是:缩短图像刷新所需要的时间。

注意:内部SRAM会比外部SRAM快很多,原则上只有内部SRAM不够用的情况下才会使用外部的SRAM。

接下来开始移植……

1、获取处理好的源码

不要重复造轮子,无需自己精简文件。

直接下载正点原子的A盘里的“程序源码”,打开“扩展例程”里的“LVGL例程”,打开以下路径:LVGL例程1 无操作系统移植\Middlewares,将内部的LVGL拿过来放在自己所建的基础工程的MIDDLEWARE目录下,并且,删除LVGL中的GUI_APP,因为我们实际开发中不必使用例程来查看效果。

2、添加到工程

直接查看《LVGL开发指南_V1.3》“第二章 LVGL 无操作系统移植”这里开始的一段内容:

第31页,搜索关键字:3. 添加工程分组、 LVGL 源文件
只需到这里即可结束。
注意,keil只有两级目录,新建分组时可以直接输入全路径
最后的结果显示如下:
这里写下来,后面直接拿来复制即可。
Middlewares/lvgl/example/porting
Middlewares/lvgl/src/core
Middlewares/lvgl/src/draw
Middlewares/lvgl/src/extra
Middlewares/lvgl/src/font
Middlewares/lvgl/src/gpu
Middlewares/lvgl/src/hal
Middlewares/lvgl/src/misc
Middlewares/lvgl/src/widgets

3、配置显示屏驱动

该部分配置步骤如下:

注意,因为上面使用的是正点原子整理过后的文件,所以,很多地方已经是现成的,我们要做的就是在调用我们自己函数的地方给替换掉即可。

不过,为了加深印象,还是做个简单的过程记录吧。

第一步(现成的):

修改条件编译指令,对应的头文件也要改

第二步(需要我们操作):

将lcd的驱动头文件包含到刚才的lvgl显示文件lv_port_disp_template.c中

第三步(需要我们操作):

在lv_port_disp_template.c里找到lv_port_disp_init函数,里面调用了disp_init函数,跳转到disp_init函数中,写入我们自己的屏幕初始化函数,并设置为横屏(可选)

第四步(需要修改分辨率大小):

配置图形单缓冲、双缓冲(要用DMA)或者全缓冲;

单缓冲为最常用的,V8.2版本双缓冲相对单缓冲提升效果不明显,全缓冲对内存要求太高。

缓冲策略是:缓冲区大小是屏幕横向分辨率*10,也就是一次刷新10行。如果效果不太理想,可以尝试增大一次刷新的行数,也就是修改10这个参数。

注意,这里的MY_DISP_HOR_RES宏定义表示水平分辨率大小,有的版本没有给我们定义,所以需要我们在该文件前面自行定义一下。

比如:

#define MY_DISP_HOR_RES 320

另外还有个垂直分辨率的宏MY_DISP_VER_RES,也可以一并定义了。

第五步(需要我们操作):

将刚才的那个函数再往下拉就能找到分辨率设置的地方

分别对应水平分辨率和垂直分辨率,直接填入即可。

第六步,配置打点函数

在刚才的文件中,找到函数disp_flush,在里面调用我们自己的打点函数。

打点函数通常有5个参数,也就是起始坐标,结束坐标,要打点的颜色。

从disp_flush的形参中获取当前的参数值即可,如下所示:

lcd_color_fill(area->x1, area->y1, area->x2, area->y2, (uint16_t *)color_p);

最后,在main函数中初始化时调用函数lv_port_disp_init进行初始化即可。

4、配置输入设备(可选)

如果不需要输入设备,直接保持条件编译指令为#if 0即可。

如果需要,则按步骤配置即可。

本人因开发工程时暂不需要输入设备,所以此步骤暂且略过。

5、 为LVGL提供任务处理的时基

在自己的定时器驱动中创建一个1ms的定时器,然后在自己的app_timer的中断处理函数中,调用LVGL的 lv_tick_inc 函数:lv_tick_inc(1); /* lvgl 1ms 心跳 */

该函数需要包含如下头文件:#include "lvgl.h"

直接调用即可,无需其他内容。

6、main函数中需要的内容

包含必要的头文件。

#include "lvgl.h"
#include "lv_port_indev_template.h"(可选)
#include "lv_port_disp_template.h"

在main函数中初始化时对lvgl进行初始化;

lv_init();                          /* lvgl系统初始化 */
lv_port_disp_init();         /* lvgl显示接口初始化,放在lv_init()的后面 */
lv_port_indev_init();       /* lvgl输入接口初始化,放在lv_init()的后面 */

定时处理 LVGL 任务。用户需要每隔几毫秒调用一次 lv_timer_handler 函数,以处理 LVGL 相关的任务,该函数可以放在 while 循环中,但延时不宜过大,需要确保 5 毫秒以内。

这里有个问题,那就是正点原子教程中直接delay延时了5ms,我们实际使用时,不可能直接在主循环里面进行延时的,所以我们就直接调用即可。

7、编写测试代码

lv_obj_t *switch_obj = lv_switch_create(lv_src_act());

lv_obj_set_size(switch_obj, 120, 60);

lv_obj_align(switch_obj, LV_ALIGN_CENTER, 0, 0);

如果没问题,可以看到界面中会有个切换按钮。

注意:

编译时,如果提示内存问题,可以尝试调整LVGL管理的内存空间。

因为LVGL默认管理的内存空间是48K字节,这其实是蛮大的,如果你单片机的内存都没有48K,那LVGL就肯定会报错。

如何调整?

在lv_conf.h中可以找到MEMORY SETTINGS部分的内容,将48的值改小一些,至少保证自己的单片机能提供这么多内存空间。

配置文件lv_conf.h

lv_conf.h 是一个用户级别的文件,它不属于内核的部分,因此,在不同的工程中,该文件有可能存在差异。

lv_conf.h 文件具有两大功能:

(1) 配置功能:内存、屏幕刷新周期、输入设备的读取周期,等等;
(2) 裁剪功能:使能 / 失能某些功能,有效地优化 Flash 的分配。
lv_conf.h 文件的内容可划分为 10 个板块,如下表所示:
配置项还是蛮多的,这里记录下常用的配置项
总开关
#if 1 /*Set it to "1" to enable content*/
颜色设置
/* 颜色深度: 1(每像素1字节), 8(RGB332), 16(RGB565), 32(ARGB8888) */
#define LV_COLOR_DEPTH                      16
内存设置
/* 0: 使用内置的 `lv_mem_alloc()` 和 `lv_mem_free()`*/
#define LV_MEM_CUSTOM                       0
HAL设置
/* 输入设备的读取周期(以毫秒为单位) */
#define LV_INDEV_DEF_READ_PERIOD            4     /*[ms]*/
字库设置
/* 始终设置默认字体 */
#define LV_FONT_DEFAULT                     &lv_font_montserrat_14
后续控件和特别功能等等,如果不需要就置0.
这几部分正点原子为了教学方便,好多都开了,实际中可选择性关闭。
更多详细内容直接参考《LVGL开发指南_V1.3》“ 第五章 LVGL 移植的相关知识

补充::::::::

外部SRAM、自定义的内存管理算法

需要时再来研究

第9讲 基础篇-LVGL移植(外部SRAM)_哔哩哔哩_bilibili

第10讲 基础篇-LVGL移植(内存管理)_哔哩哔哩_bilibili

DMA2D

DAM2D需要硬件支持,如果板子不支持DMA2D,则无法使用。

首先了解下什么是DMA2D:STM32的“GPU”——DMA2D实例详解 - 知乎

根据上面的文章可知,DMA2D可以理解成专门用来处理2D图像的DMA,类似于“GPU”。

因为STM32F103和STM32F407没有该外设,所以此处不赘述。

F429单片机就支持:STM32F429的图形加速器DMA2D的基础知识

以后有需要再研究。

第11讲 基础篇-LVGL移植(DMA2D)_哔哩哔哩_bilibili

相关文章:

STM32进行LVGL裸机移植

本文的移植参考的是正点原子的课程《手把手教你学LVGL图形界面编程》 基于该课程和《LVGL开发指南_V1.3》“第二章 LVGL 无操作系统移植”,然后结合自身的实际情况进行整理。 先根据自己的习惯,创建基础的单片机工程,然后在APP业务层和DRIVE…...

python解析robot framework的output.xml并生成html

一、用pyh模块解析stat结点数据(output.py) #codingutf-8import xml.dom.minidom import xml.etree.ElementTree#打开xml文档 dom xml.dom.minidom.parse(./ui/output.xml);root2 xml.etree.ElementTree.parse(./ui/output.xml) #得到文档元素对象 ro…...

【RuoYi移动端】uni-app中的单击和双击事件

1、单击事件: click"enterpriseSelect" 2、双击事件: touchend"userinfo"...

使用 conda 在 Ubuntu 16.04 上安装 Python 3.9 的步骤:和 VSCode配置

一、使用conda在 Ubuntu 16.04 上安装 Python 3.9 的步骤: 当然可以,conda 是一个非常强大的包管理器,它可以方便地管理不同版本的 Python 和各种库包。以下是使用 conda 在 Ubuntu 16.04 上安装 Python 3.9 的步骤: 1. 安装 Miniconda Miniconda 是 Anaconda 的轻量级版…...

spring6-国际化:i18n | 数据校验:Validation

文章目录 1、国际化:i18n1.1、i18n概述1.2、Java国际化1.3、Spring6国际化1.3.1、MessageSource接口1.3.2、使用Spring6国际化 2、数据校验:Validation2.1、Spring Validation概述2.2、实验一:通过Validator接口实现2.3、实验二:B…...

【MicroSoft Edge】格式化的显示JSON格式的数据

当我们没有进行任何操作的时候,默认浏览器给我们展示的JSON的数据是这样的: 看着十分不便。 解决方案: 首先点击 MicroSoft Edge 浏览器右上角的三点,如何选择扩展 点击 获取Microsoft Edge 扩展 搜索 JSONView,第一…...

【c++】跟webrtc学std array 2:TaskExecutorMap单例用法

D:\XTRANS\m98_rtc\ndrtc-webrtc\src\base\task\task_executor.ccstd array实现的map:TaskExecutorMap // Maps TaskTraits extension IDs to registered TaskExecutors. Index |n| // corresponds to id |n - 1|. using TaskExecutorMap =std::array<TaskExecutor*, Task…...

力扣每日一题59:螺旋矩阵||

题目描述&#xff1a; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]]示例 2&#xff1a; 输入&am…...

codeforces (C++ In Love )

题目&#xff1a; 翻译&#xff1a; 思路&#xff1a; 1、在一个集合中有多组线段&#xff0c;如果有不相交的两组线段&#xff0c;则输出YES&#xff0c;否则输出NO。 2、每次操纵可以选择增加一组线段或者删除一组线段后&#xff0c;输出YES或者NO。 3、用flag标记该线段是否…...

【python】py文件全自动打包成spec文件

说明&#xff1a; 自动获取当前根目录下所有py文件生成spec文件&#xff0c;直接运行pyinstaller进行打包即可。直接打包成单执行文件。 直接上代码 import ospathex []def recursion(path, main):if path[:1] ! /:path /listpath os.listdir(path)for item in listpath:if…...

YOLOv5-调用官方权重进行检验(目标检测)

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客 &#x1f366; 参考文章&#xff1a;365天深度学习训练营-第7周&#xff1a;咖啡豆识别&#xff08;训练营内部成员可读&#xff09; &#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制](https…...

springMVC中统一异常处理@ControllerAdvice

1.在DispatcherServlet中初始化HandlerExceptionResolver 2.controller执行完成后执行processDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException),有异常则处理异常 3.ExcepitonHandlerExceptionResolver中执行方法doResolveHandlerMethodExceptio…...

【Java】<泛型>,在编译阶段约束操作的数据结构,并进行检查。

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ JAVA泛型 泛型介绍&#xff1a; ①泛型&#…...

解决谷歌学术bib信息不全的问题

在我们撰写学术论文时&#xff0c;经常需要引用参考文献。如果用latex撰写论文&#xff0c;势必会用到文献的bib信息&#xff0c;大部分的教程都会告诉我们去google scholar上去搜索。 一、问题描述 搜索一篇文章&#xff0c;然后选择cite&#xff0c;再选择bib。 很明显&…...

初始Redis 分布式结构的发展演变

目录 Redis的特点和使用场景 分布式系统的引入 单机系统 分布式系统 应用服务器的增多&#xff08;处理更多的请求&#xff09; 数据库读写分离&#xff08;数据服务器的增多) 引入缓存 应对更大的数据量 业务拆分&#xff1a;微服务 Redis的特点和使用场景 我们先来…...

关于动态内存管理中的常见练习题

文章目录 前言练习1&#xff1a;练习2&#xff1a;练习3&#xff1a;练习4&#xff1a; 前言 学习完C语言中的动态内存管理&#xff0c;大家开始利用动态内存管理来去开辟空间&#xff0c;经过一顿狂敲代码后&#xff0c;发现了问题&#xff0c;程序要么崩掉&#xff0c;要么运…...

冒泡排序、插入排序、选择排序和快速排序的原理

下面是对冒泡排序、插入排序、选择排序和快速排序的原理的简要解释&#xff1a; 冒泡排序&#xff08;Bubble Sort&#xff09;&#xff1a;冒泡排序是一种简单的排序算法。它通过多次迭代比较相邻的元素&#xff0c;并交换它们的位置&#xff0c;使得较大&#xff08;或较小&…...

VB.NET之SqlCommand详解

目录 一.前言 二.SqlCommand的背景方法 1.构造函数 2.属性 3.方法 三.SqlCommand的使用实例 1.创建SqlCommand对象 2.执行SQL查询语句 3.执行存储过程 四.总结 一.前言 VB.NET的SqlCommand是ADO.NET的一部分&#xff0c;主要用于执行SQL语句并返回受影响的行数、查询…...

.NET主流的ORM框架 2023年

1. Entity Framework Entity Framework是Microsoft开发的一款强大的ORM框架。适用于.NET开发&#xff0c;支持多种数据库&#xff0c;并提供了广泛的文档和教程。Entity Framework基于面向对象的数据模型&#xff0c;使用LINQ进行查询。它的强大功能和易用性使得它成为.NET开发…...

第三节——Vue 基础语法

vue语法分为选项是API&#xff08;Option api&#xff09;和组合式api&#xff08;Composition Api&#xff09;,我们以选项式Api入门 一、基本构成 template、script、style三部分构成。template可以理解成编写html的地方&#xff0c;script编写逻辑js的地方&#xff0c;sty…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...

虚幻基础:角色旋转

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录 移动组件使用控制器所需旋转&#xff1a;组件 使用 控制器旋转将旋转朝向运动&#xff1a;组件 使用 移动方向旋转 控制器旋转和移动旋转 缺点移动旋转&#xff1a;必须移动才能旋转&#xff0c;不移动不旋转控制器…...

简单介绍C++中 string与wstring

在C中&#xff0c;string和wstring是两种用于处理不同字符编码的字符串类型&#xff0c;分别基于char和wchar_t字符类型。以下是它们的详细说明和对比&#xff1a; 1. 基础定义 string 类型&#xff1a;std::string 字符类型&#xff1a;char&#xff08;通常为8位&#xff09…...