[LVGL] 配置lv_conf.h | 条件编译 | 显示屏lv_display

链接:https://docs.lvgl.io/master/
在这里插入图片描述

docs:LVGL

LVGL(Light and Versatile Graphics Library)是用于在资源受限的嵌入式系统上创建图形用户界面(GUI)的开源解决方案。

它提供丰富的控件和灵活的**事件系统**来实现动态交互。

该库能高效处理绘制/渲染到各类显示屏的操作,并支持来自多种**输入设备**的输入,所有功能都可通过中心化的配置进行定制。

概览

在这里插入图片描述

章节

  1. 配置(lv_conf.h)
  2. 显示屏(lv_display)
  3. 控件(lv_obj)
  4. 样式(lv_style)
  5. 布局(lv_flex, lv_grid)
  6. 输入设备(lv_indev)
  7. 事件系统(lv_event)
  8. 绘制/渲染(lv_draw)

第一章:配置(lv_conf.h)

欢迎开启LVGL之旅~

在嵌入式系统图形用户界面(GUI),LVGL就像一套多功能工具箱,能够从智能手表到工业面板的各种小屏幕上绘制精美的界面。

但与实体工具箱类似,并非所有项目都需要用到全部工具。假设我们正在开发一款配备基础小屏幕的简易设备,仅需几个按钮和文本显示。

此时我们希望设备尽可能高效运行,同时占用最少的内存和处理器资源。

这正是lv_conf.h的用武之地!可lv_conf.h视为整个LVGL库的"定制清单"或"设置菜单"

通过这个特殊文件,我们可以精确指定需要启用的功能(如特定按钮类型或高级绘图效果)以及需要禁用的功能。

通过这种配置,最终程序将针对特定设备进行极致优化,节省宝贵内存并提升运行效率。

什么是lv_conf.h

lv_conf.h是一个标准C头文件(扩展名为.h),包含大量LVGL配置参数。这些参数在C语言中通常称为""或"定义",其作用类似于功能开关或数值设定器。

例如某个配置项可能如下:

#define LV_USE_BUTTON 1

这行代码告知LVGL:"我们需要在项目中使用按钮!"其中1表示启用,0表示禁用。

配置文件的获取与设置

初次获取LVGL时并不会直接得到lv_conf.h文件,而是会看到lvgl/lv_conf_template.h文件。

这相当于包含所有可能选项的蓝图或默认清单。

要为项目配置LVGL,请按以下步骤操作:

  1. 复制模板文件:复制lvgl/lv_conf_template.h并重命名为lv_conf.h

    • 重要提示:将lv_conf.h置于lvgl文件夹同级目录,形成如下项目结构:
      项目目录/
      ├── lvgl/
      │   ├── src/
      │   └── ...
      └── lv_conf.h
      └── main.c
      └── ...
      
  2. 激活配置内容:打开新建的lv_conf.h文件,在文件顶部可见:

    #if 0 /* 将此值设为"1"以激活配置内容 */
    

    0改为1以激活文件内所有设置项:

    #if 1 /* 将此值设为"1"以激活配置内容 */
    

至此,lv_conf.h已准备就绪可供定制~

新手必备配置项

我们以构建简易内存优化型GUI(含按钮和文本)为目标,重点讲解几个关键配置项。

1. 屏幕色深(LV_COLOR_DEPTH

该参数决定每个像素颜色表示的位数。位数越多色彩越丰富,但内存占用也越高。

  • 16:常见于嵌入式显示设备(如RGB565格式),内存占用低于32位
  • 32:适用于高质量显示(如ARGB8888),内存需求较高

对于简易设备,选择16位可有效节省内存:

// 位于lv_conf.h
/*====================颜色设置*====================*//** 色深选项:1 (I1), 8 (L8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888) */
#define LV_COLOR_DEPTH 16 // 从默认的32或16修改为16以节省内存

2. LVGL内存分配(LV_MEM_SIZE

LVGL需要预分配内存来存储内部变量、绘图缓冲区和控件数据。

LV_MEM_SIZE定义了为LVGL保留的内存容量。

模板文件中默认值通常为(64 * 1024U)即64KB。对于小型设备,若功能简单可缩减至32KB或更低:

// 位于lv_conf.h
#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN/** 为lv_malloc()预留的可用内存大小(>= 2kB) */#define LV_MEM_SIZE (32 * 1024U) // 从64KB调整为32KB以节省内存
#endif

3. 控件启用/禁用(LV_USE_WIDGET_NAME

LVGL提供多种预制组件(称为"控件"),包括按钮、滑块、图表、日历等。

对于简易设备,仅需启用按钮和基础文本(标签)控件即可显著减小程序体积。

lv_conf.h中找到如下段落进行配置:

// 位于lv_conf.h
/*==================* 控件*================*/#define LV_USE_ANIMIMG    0 // 禁用
#define LV_USE_ARC        0 // 禁用#define LV_USE_BAR        0 // 禁用#define LV_USE_BUTTON     1 // 启用!#define LV_USE_BUTTONMATRIX  0 // 禁用#define LV_USE_CALENDAR   0 // 禁用(模板中为1)
// ... 更多控件配置 ...#define LV_USE_LABEL      1 // 启用!

将未使用的控件设为0后,编译器会完全忽略相关代码,显著减小最终程序体积。

4. 日志与调试(LV_USE_LOG, LV_USE_PERF_MONITOR, LV_USE_SYSMON

这些参数控制LVGL是否输出调试日志或性能监控信息。

开发阶段开启有助于调试,但正式发布时应关闭以优化代码体积和性能:

// 位于lv_conf.h
/*-------------* 日志系统*-----------*//** 启用日志模块 */
#define LV_USE_LOG 0 // 从1改为0以优化发布版本// ... 文件后续部分 ...
/** 1: 启用系统监控组件 */
#define LV_USE_SYSMON   0 // 从1改为0以优化发布版本
#if LV_USE_SYSMON// ... 相关设置 .../** 1: 显示CPU使用率和FPS计数 */#define LV_USE_PERF_MONITOR 0 // 从1改为0
#endif

lv_conf.h–条件编译

当编译LVGL项目(即将C代码转换为设备可执行程序)时,编译器会读取lv_conf.h配置。

每个#define指令相当于给编译器的特殊指令。当某功能被启用(如#define LV_USE_BUTTON 1),编译器会将LVGL库中所有按钮相关代码包含进最终程序。

若功能被禁用(如#define LV_USE_CALENDAR 0),编译器则完全跳过日历相关代码,相当于这些代码从未存在!

此过程称为**条件编译**,是精确适配硬件能力和项目需求的强大工具。

其工作原理可简化为:

在这里插入图片描述

在LVGL源代码中,可见包围代码块的#if#endif指令。例如按钮功能的实现代码:

// 在LVGL源文件中(如lv_button.c)
#include "lv_conf.h" // 包含定制化配置#if LV_USE_BUTTON // 仅当LV_USE_BUTTON为1时编译本段// ...// 按钮功能相关代码// ...void lv_button_create(lv_obj_t *parent) {// 创建按钮的代码}// ...
#endif // LV_USE_BUTTON结束

同理,被禁用功能的代码段:

// 在LVGL源文件中(如lv_calendar.c)
#include "lv_conf.h"#if LV_USE_CALENDAR // 当LV_USE_CALENDAR为0时跳过本段// ...// 日历控件相关代码// ...void lv_calendar_create(lv_obj_t *parent) {// 创建日历的代码}// ...
#endif

这种精妙的机制使LVGL具备极强的适应性,既能运行于资源有限的微型控制器,也能驾驭功能齐全的智能设备。

总结

我们已完成LVGL定制的第一步!理解lv_conf.h至关重要,因为它直接影响项目的体积、性能和可用功能。

通过精心选择组件调整内存参数,可以确保LVGL完美适配目标嵌入式系统——无论是简易显示器还是功能丰富的智能设备。

现在我们已经掌握如何配置LVGL本身,接下来让我们进入实际显示环节

下一章:显示屏(lv_display)


第二章:显示屏(lv_display)

欢迎回来!

在第一章:配置(lv_conf.h)中,我们学习了如何为特定设备裁剪优化LVGL。可lv_conf.h视为为工具箱选择合适工具的过程。但若没有可供绘制的画布,再好的工具箱又有何用?

**显示模块(lv_display)**正是为此而生!

设想我们已将物理屏幕连接到微控制器,LVGL需要全面了解该屏幕的信息:尺寸(分辨率)、色彩模式,以及最关键的部分——如何将LVGL内存中的精美画面传输至物理屏幕实现可视化。

lv_display对象如同物理屏幕的数字化身,负责处理LVGL绘图引擎与显示硬件之间的所有通信。若无此模块,LVGL将无从知晓绘制位置及可视化方法

什么是lv_display

lv_display(代码中以lv_display_t表示)是LVGL与物理屏幕交互的核心模块,主要管理:

  • 分辨率:屏幕像素尺寸(如320x240像素)
  • 色深:每个色彩使用的位数(如16位RGB565)
  • 绘图缓冲区:微控制器内存中的专用区域,作为LVGL绘制图形的临时画布
  • 刷新回调函数:开发者编写的关键函数,用于将缓冲区像素数据传送至物理显示硬件

LVGL支持多屏显示,但本章聚焦单屏基础配置。

显示屏初始设置

我们以320x240分辨率、16位色的常见屏幕为例,详解配置流程:

1. 创建显示对象

首先需向LVGL声明显示设备的存在:

#include "lvgl.h" // 必须包含LVGL主头文件// 定义显示屏分辨率
#define MY_DISP_HOR_RES 320
#define MY_DISP_VER_RES 240void setup_display() {// 1. 创建显示对象lv_display_t * my_display = lv_display_create(MY_DISP_HOR_RES, MY_DISP_VER_RES);// ... 后续配置将在此添加
}

lv_display_create()函数向LVGL声明了显示设备的分辨率,返回的my_display指针用于后续配置

2.配置绘图缓冲区

LVGL采用"预渲染-传输"机制,需在微控制器RAM中开辟绘图缓冲区:

  • 单缓冲区:LVGL完成绘制后等待传输,可能导致低刷新率下的画面撕裂
  • 双缓冲区:支持交替渲染与传输,建议RAM充足时采用

以下示例配置占屏幕1/10大小的单缓冲区:

#define LV_COLOR_DEPTH 16 // 需与lv_conf.h设置一致
#define MY_DISP_HOR_RES 320
#define MY_DISP_VER_RES 240// 根据色深计算每像素字节数
#define BYTES_PER_PIXEL (LV_COLOR_DEPTH / 8)// 静态内存中声明缓冲区(持久化)
static lv_color_t draw_buffer[MY_DISP_HOR_RES * MY_DISP_VER_RES / 10];void setup_display() {lv_display_t * my_display = lv_display_create(MY_DISP_HOR_RES, MY_DISP_VER_RES);// 2. 绑定绘图缓冲区lv_display_set_buffers(my_display, draw_buffer, NULL, sizeof(draw_buffer), LV_DISPLAY_RENDER_MODE_PARTIAL);
}
  • LV_DISPLAY_RENDER_MODE_PARTIAL启用局部渲染模式,仅更新变化区域以优化性能

3. 实现刷新回调函数

此为核心环节,需开发者根据显示硬件编写像素传输逻辑:

// 实际屏幕写入函数(需根据硬件实现)
void my_put_pixel_on_actual_screen(int32_t x, int32_t y, lv_color_t color) {// 示例:SPI屏可能需要通过协议发送坐标数据// 具体实现取决于显示控制器与通信接口
}// 3. 自定义刷新回调函数
void my_display_flush_callback(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) {lv_color_t * buf = (lv_color_t *)px_map; // 像素数据转换// 遍历待刷新区域for (int32_t y = area->y1; y <= area->y2; y++) {for (int32_t x = area->x1; x <= area->x2; x++) {my_put_pixel_on_actual_screen(x, y, *buf);buf++; // 移动至下一像素}}// 关键!通知LVGL刷新完成lv_display_flush_ready(disp);
}
  • area参数指定需更新的屏幕矩形区域
  • 完成像素传输后必须调用lv_display_flush_ready()释放缓冲区

4. 注册回调函数

将自定义回调绑定至显示对象:

void setup_display() 
{lv_display_t * my_display = lv_display_create(MY_DISP_HOR_RES, MY_DISP_VER_RES);lv_display_set_buffers(my_display, draw_buffer, NULL, sizeof(draw_buffer), LV_DISPLAY_RENDER_MODE_PARTIAL);// 4. 注册刷新回调lv_display_set_flush_cb(my_display, my_display_flush_callback);
}

至此,LVGL已完成显示系统的初始化,可进行图形渲染。

默认显示对象

首个通过lv_display_create()创建的显示对象会自动成为默认显示设备

多数LVGL控件创建函数将自动关联此默认显示。

多屏系统可通过lv_display_set_default()切换当前默认显示。

显示模块工作原理

显示模块的运作流程可通过以下时序图理解:

在这里插入图片描述

内部实现解析:

lv_display_create()会在内存中分配lv_display_t结构体,包含分辨率、缓冲区指针及回调函数等关键信息。

刷新定时器(refr_timer)会周期性地触发画面更新。

总结

本章完成了LVGL显示系统的配置,重点包括:

  • 显示对象的创建与属性设置
  • 绘图缓冲区的内存管理
  • 硬件相关的刷新回调实现
  • LVGL渲染管线的运作原理

至此,我们已搭建起GUI系统的显示基础,下一章将深入探讨如何构建交互界面元素。

下一章:控件(lv_obj)

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

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

相关文章

sqli-labs通关笔记-第32关 GET宽字符注入(单引号闭合 手工注入+脚本注入两种方法)

目录 一、宽字符注入 二、代码审计 1、代码审计 2、SQL注入安全性分析 三、渗透实战 1、进入靶场 2、id1探测 3、id%df-- 探测 4、手工注入 &#xff08;1&#xff09;获取列数 &#xff08;2&#xff09;获取回显位 &#xff08;3&#xff09;获取数据库名 &…

MySQL的创建管理表:

目录 基础知识&#xff1a; 一条数据存储的过程&#xff1a; 标识符命名规则&#xff1a; 创建和管理数据库&#xff1a; 创建数据库&#xff1a; 创建数据库&#xff1a; 创建数据库并指定字符集&#xff1a; 判断数据库是否存在&#xff0c;不存在则创建数据库&#…

Linux Vi常用指令总结

Vi&#xff08;及其改进版 Vim&#xff09;是 Linux 中常用的文本编辑器&#xff0c;虽然入门有一定门槛&#xff0c;但熟练掌握后效率极高。以下是常见指令分类整理&#xff1a;1. 模式切换 普通模式&#xff08;命令模式&#xff09;&#xff1a;启动后的默认模式&#xff0c…

解决远程连接云服务器mysql编号1130问题

连接云服务器mysql失败&#xff0c;可能是因为ip发生改变&#xff0c;被mysql拦截。我自己前后做了两件事。大家赶时间可直接从二开始&#xff0c;不放心的就从一开始到结束一、在云服务器实例中为当前ip配置安全组权限。1.找到当前服务器的实例&#xff0c;进入安全组。为其增…

大数据存储域——HDFS存储系统

摘要本文介绍了HDFS存储系统&#xff0c;包括其组件、工作机制、实战经验总结、使用场景以及与SpringBoot的实战示例和优化设计。HDFS由Client、NameNode、SecondaryNameNode、DataNode等组件构成&#xff0c;通过特定的工作机制实现文件的读取和写入。它适用于多种场景&#x…

jdk动态代理如何实现

口语化答案好的&#xff0c;面试官。jdk 的动态代理主要是依赖Proxy类 和InvocationHandler 接口。jdk 动态代理要求类必须有接口。在进行实现的时候&#xff0c;首先要定义接口&#xff0c;比如MyService&#xff0c;这个接口就是我们的正常功能的实现。但是希望在不更改MySer…

自然语言处理的相关概念与问题

目录 一、学科的产生与发展 1、什么是自然语言&#xff1f; 2、自然语言处理技术的诞生 二、技术挑战 三、基本方法 1、方法概述 理性主义方法 经验主义方法 2、传统的统计学习方法 3、深度学习方法 词向量表示 词向量学习 开源工具 四、应用举例 1、汉语分词 …

Anthropic MCP架构深度解析:下一代AI工具集成协议的设计哲学

本文深入剖析Anthropic提出的模型通信协议(MCP),揭示其如何重构AI与工具生态的交互范式,打造安全高效的智能体基础设施。 引言:AI工具集成的"巴别塔困境" 当前AI生态面临的核心挑战: #mermaid-svg-lSpYBxzxD5oiYwcL {font-family:"trebuchet ms",verd…

【注意】HCIE-Datacom华为数通考试,第四季度将变题!

最近&#xff0c;数据通信圈子可热闹坏啦&#xff01;好几个渠道都证实了&#xff0c;HCIE - Datacom实验考试马上要有大变化咯&#xff01; 这可不是啥小道消息&#xff0c;也不是那种试点的传言&#xff0c;而是从IE内部技术交流会上得到的确切消息。 这边联系了华为认证的好…

MySql 硬核解析系列 一 MySQL的锁机制

MySQL 的锁机制是其并发控制的核心,直接影响数据库的性能、一致性与可用性。本文将从底层原理、锁的分类、实现机制、锁的粒度、锁的兼容性、死锁处理、InnoDB 的行锁实现、MVCC 与锁的关系等多个维度,进行硬核、深度解析,适用于希望深入理解 MySQL 并发控制机制的开发者与 …

7.软件工程

软件生命周期软件生命周期什么是软件工程&#xff1f;以工程化的原则和方法来开发软件&#xff0c;其目的是提高软件生产率、提高软件质量、降低软件成本。软件工程3大组成部分&#xff1a;方法、工具、过程。什么是软件生命周期&#xff1a;经过开发、使用和维护&#xff0c;直…

C 语言结构体与 Java 类的异同点深度解析

在编程语言的发展历程中,C 语言的结构体与 Java 的类扮演着至关重要的角色。作为面向过程编程的经典代表,C 语言的结构体为数据封装提供了基础形式;而 Java 作为纯面向对象语言,类则是其核心语法结构。二者既存在一脉相承的设计思想,又因编程语言范式的差异呈现出显著区别…

C++、STL面试题总结(二)

1. 必须实现拷贝构造函数的场景 核心问题&#xff1a;默认拷贝构造的缺陷 C 默认的拷贝构造函数&#xff08;浅拷贝&#xff09;&#xff0c;会直接拷贝指针 / 引用成员的地址。若类包含引用成员或指向堆内存的指针&#xff0c;浅拷贝会导致 “多个对象共享同一份资源”&…

IntelliJ IDEA2024 错误‘http://start.spring.io/‘的初始化失败,请检查URL、网络和代理设置。

下载新版本的intellij idea2024创建项目时&#xff0c;服务器URL报错误http://start.spring.io/的初始化失败&#xff0c;请检查URL、网络和代理设置。错误消息&#xff1a;Cannot download http://start.spring.io/:Permission denied:getsockopt&#xff0c;具体如下图&#…

从零开始的云计算生活——第三十八天,避坑落井,Docker容器模块

一.故事背景 在综合使用了之前全部的知识完成项目之后&#xff0c;接下来将学习更简单的方法来对之前的命令进行使用&#xff0c;马上进入容器模块 二. Docker概述 Docker简介 Docker&#xff0c;翻译过来就是码头工人 Docker是一个开源的应用容器引擎&#xff0c;让开发者…

Python与自动化运维:构建智能IT基础设施的终极方案

Python与自动化运维:构建智能IT基础设施的终极方案 引言:运维革命的Python引擎 在DevOps理念席卷全球的今天,企业IT基础设施的复杂度呈指数级增长。某跨国银行的数据显示,采用Python构建的自动化运维体系使其服务器部署效率提升400%,故障响应时间缩短至原来的1/8。本文将…

HarmonyOS应用开发环境搭建以及快速入门介绍

下载并安装DevEco Studio&#xff0c;这是华为官方提供的HarmonyOS应用开发IDE。访问华为开发者联盟官网下载对应操作系统的版本。安装完成后&#xff0c;配置HarmonyOS SDK和必要的工具链。 确保计算机满足开发环境要求&#xff0c;包括Windows 10 64位或macOS 10.14及以上操…

RocketMQ与Kafka 消费者组的‌重平衡操作消息顺序性对比

RocketMQ 的重平衡机制本身不会直接影响消息顺序&#xff0c;但消费模式的选择和使用需注意以下细节&#xff1a;重平衡机制RocketMQ消费者组的重平衡策略是每隔20秒从Broker获取消费组的最新消费进度&#xff0c;并根据订阅信息重新分配消息队列。该策略主要影响消息拉取的均衡…

学习 Android(十四)NDK基础

学习 Android&#xff08;十四&#xff09;NDK基础 Android NDK 是一个工具集&#xff0c;可让我们使用 C 和 C 等语言以原生代码实现应用的各个部分。对于特定类型的应用&#xff0c;这可以帮助我们重复使用以这些语言编写的代码库。 接下来&#xff0c;我们将按照以下步骤进行…

宝塔(免费版9.2.0)的docker拉取仓库失败的加速方法

宝塔docker拉取仓库失败 完美加速方法_宝塔docker加速-CSDN博客 版本&#xff1a;免费版 9.2.0 https://docker.1ms.run 其他的试了很多 都不行 最后不要用宝塔的控制面板(很卡)&#xff0c;直接在linux中用命令行&#xff0c;效果就很好了。