[正点原子]ESP32S3 RGB屏幕移植LVGL

article/2025/8/7 7:54:02

ESP32S3 RGB屏幕移植lvgl

    • 简介
    • 准备工作
    • 移植过程
      • 创建文件加
      • 修改配置
      • 修改适配文件
      • main函数
      • lvgl的图形化配置
    • 着重要注意的
      • 屏幕驱动的问题
    • 效果展示

简介

最近入手了 正点原子ESP32开发版准备学习LVGL,该板子支持RGB屏幕RGB565,之前买Linux开发板的时候有一块4,3寸的RGB屏幕,准备以此开始学习LVGL,参考了正点原子的移植方法,但是适配度不高,一个是屏幕大小不一样我的是480272 官方是800480 其次是触摸芯片读取不到数据

准备工作

首先是需要搭建ESP32-IDF的开发环境 这个已经很熟练了,本次是在树莓派4B上编译的,但是环境是官方脚本一键的,因此区别不大

  • LVGL8.3源代码
  • 正点原子开发例程 24_touch

移植过程

创建文件加

在components目录下将lvgl8.3的源码包放置在这里,解压,重命名为LVGL,然后在main目录下新建目录APP lvgl的驱动适配文件就在这里。

修改配置

在lvgl目录下 找到lv_conf_temple.h 重命名为lvgl_conf.h 在里面也把多余的内容去掉 if 0 改成if 1

在main/APP目录下新建文件lvgl_demo.c lvgl_demo.h

修改适配文件

在lvgl_demo.c中 拷贝移植文档中的内容

/******************************************************************************************************* @file        lvgl_demo.c* @author      正点原子团队(ALIENTEK)* @version     V1.0* @date        2023-12-01* @brief       LVGL V8移植 实验* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 ESP32-S3 开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com******************************************************************************************************/#include "lvgl_demo.h"const esp_timer_create_args_t lvgl_tick_timer_args={.callback = &increase_lvgl_tick,.name = "lvgl_tick",
};
esp_timer_handle_t lvgl_tick_timer = NULL;/**
* @brief 初始化并注册显示设备
* @param 无
* @retval 无
*/void lv_port_disp_init(void)
{// void *buf1 = NULL;// void *buf2 = NULL;/* 初始化显示设备LCD */lcd_init(); /* RGB 屏初始化 */rgblcd_display_dir(1); /* 设置横屏 */lcd_show_string(10, 40,  240, 32, 32, "ESP32-S3", RED);char tmp[32];sprintf(tmp,"%ld-%ld",lcddev.width,lcddev.height);lcd_show_string(10, 80,  240, 32, 32, tmp, RED);/*-----------------------------* 创建一个绘图缓冲区*----------------------------*//*** LVGL 需要一个缓冲区用来绘制小部件* 随后,这个缓冲区的内容会通过显示设备的 'flush_cb'(显示设备刷新函数) 复制到显示设备上* 这个缓冲区的大小需要大于显示设备一行的大小** 这里有3种缓冲配置:* 1. 单缓冲区:*      LVGL 会将显示设备的内容绘制到这里,并将他写入显示设备。** 2. 双缓冲区:*      LVGL 会将显示设备的内容绘制到其中一个缓冲区,并将他写入显示设备。*      需要使用 DMA 将要显示在显示设备的内容写入缓冲区。*      当数据从第一个缓冲区发送时,它将使 LVGL 能够将屏幕的下一部分绘制到另一个缓冲区。*      这样使得渲染和刷新可以并行执行。** 3. 全尺寸双缓冲区*      设置两个屏幕大小的全尺寸缓冲区,并且设置 disp_drv.full_refresh = 1。*      这样,LVGL将始终以 'flush_cb' 的形式提供整个渲染屏幕,您只需更改帧缓冲区的地址。*//* 创建一个绘图缓冲区 *///buf1 = heap_caps_malloc(ltdcdev.width * 10 * sizeof(lv_color_t), MALLOC_CAP_8BIT);/* 初始化显示缓冲区 */static lv_color_t buf_1[480*32];  static lv_disp_draw_buf_t disp_buf;                                 /* 保存显示缓冲区信息的结构体 */lv_disp_draw_buf_init(&disp_buf, buf_1, NULL, lcddev.width * 10);  /* 初始化显示缓冲区 *///lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*//* 在LVGL中注册显示设备 */static lv_disp_drv_t disp_drv;      /* 显示设备的描述符(HAL要注册的显示驱动程序、与显示交互并处理与图形相关的结构体、回调函数) */lv_disp_drv_init(&disp_drv);        /* 初始化显示设备 *//* 设置显示设备的分辨率 * 这里为了适配正点原子的多款屏幕,采用了动态获取的方式,* 在实际项目中,通常所使用的屏幕大小是固定的,因此可以直接设置为屏幕的大小 */disp_drv.hor_res = lcddev.width;disp_drv.ver_res = lcddev.height;/* 用来将缓冲区的内容复制到显示设备 */disp_drv.flush_cb = lvgl_disp_flush_cb;/* 设置显示缓冲区 */disp_drv.draw_buf = &disp_buf;/* 注册显示设备 */lv_disp_drv_register(&disp_drv);
}volatile bool disp_flush_enabled = true;/* Enable updating the screen (the flushing process) when disp_flush() is called by LVGL*/
void disp_enable_update(void)
{disp_flush_enabled = true;
}/**
* @brief 将内部缓冲区的内容刷新到显示屏上的特定区域
* @note 可以使用 DMA 或者任何硬件在后台加速执行这个操作
* 但是,需要在刷新完成后调用函数 'lv_disp_flush_ready()'
* @param disp_drv : 显示设备
* @param area : 要刷新的区域,包含了填充矩形的对角坐标
* @param color_map : 颜色数组
* @retval 无
*/
static void lvgl_disp_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area,
lv_color_t *color_map)
{esp_lcd_panel_handle_t panel_handle=(esp_lcd_panel_handle_t)drv->user_data;/* 特定区域打点 */lcd_color_fill(area->x1, area->y1, area->x2,area->y2,(uint16_t *) color_map);/* 重要!!! 通知图形库,已经刷新完毕了 */lv_disp_flush_ready(drv);
}
#if 1
/**
* @brief 初始化并注册输入设备
* @param 无正点原子 LVGL 开发教程
10
LVGL 开发指南
* @retval 无
*/
void lv_port_indev_init(void)
{/* 初始化触摸屏 *///tp_init();tp_dev.init();/* 初始化输入设备 */static lv_indev_drv_t indev_drv;lv_indev_drv_init(&indev_drv);/* 配置输入设备类型 */indev_drv.type = LV_INDEV_TYPE_POINTER;/* 设置输入设备读取回调函数 */indev_drv.read_cb = touchpad_read;/* 在 LVGL 中注册驱动程序,并保存创建的输入设备对象 */lv_indev_t *indev_touchpad;indev_touchpad = lv_indev_drv_register(&indev_drv);
}
/**
* @brief 获取触摸屏设备的状态
* @param 无
* @retval 返回触摸屏设备是否被按下
*/
static bool touchpad_is_pressed(void)
{tp_dev.scan(0); /* 触摸按键扫描 */if (tp_dev.sta & TP_PRES_DOWN){return true;}return false;
}
/**
* @brief 在触摸屏被按下的时候读取 x、 y 坐标
* @param x : x 坐标的指针
* @param y : y 坐标的指针
* @retval 无正点原子 LVGL 开发教程
11
LVGL 开发指南
*/
static void touchpad_get_xy(lv_coord_t *x, lv_coord_t *y)
{(*x) = tp_dev.x[0];(*y) = tp_dev.y[0];
}
/**
* @brief 图形库的触摸屏读取回调函数
* @param indev_drv : 触摸屏设备
* @param data : 输入设备数据结构体
* @retval 无
*/
void touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{static lv_coord_t last_x = 0;static lv_coord_t last_y = 0;/* 保存按下的坐标和状态 */if(touchpad_is_pressed()){touchpad_get_xy(&last_x, &last_y); /* 在触摸屏被按下的时候读取 x、 y 坐标 */data->state = LV_INDEV_STATE_PR;}else{data->state = LV_INDEV_STATE_REL;}/* 设置最后按下的坐标 */data->point.x = last_x;data->point.y = last_y;
}
#endifvoid lvgl_ex_label(void)
{lv_obj_t *bj = lv_obj_create(lv_scr_act());lv_obj_set_size(bj,200,200);lv_obj_set_align(bj,LV_ALIGN_CENTER);lv_obj_set_style_bg_color(bj,lv_color_hex(0xFF0000),LV_STATE_DEFAULT);lv_obj_t *switch_1 = lv_switch_create(bj);lv_obj_set_size(switch_1,60,30);lv_obj_set_align(switch_1,LV_ALIGN_CENTER);}/**
* @brief lvgl_demo 入口函数
* @param 无
* @retval 无
*/
void lvgl_demo(void)
{lv_init(); /* 初始化 LVGL 图形库 */lv_port_disp_init(); /* lvgl 显示接口初始化,放在 lv_init()的后面 */lv_port_indev_init(); /* lvgl 输入接口初始化,放在 lv_init()的后面 *//* 为 LVGL 提供时基单元 */ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, 1 * 1000));/* 官方 demo,需要在 SDK Configuration 中开启对应 Demo *///lvgl_ex_label();// lv_demo_benchmark();lv_demo_music();while (1){lv_timer_handler(); /* LVGL 计时器 */vTaskDelay(pdMS_TO_TICKS(10)); /* 延时 10 毫秒 */}
}
/**
* @brief 告诉 LVGL 运行时间
* @param arg : 传入参数(未用到)
* @retval 无
*/
static void increase_lvgl_tick(void *arg)
{ /* 告诉 LVGL 已经过了多少毫秒 */lv_tick_inc(1);
}
在lvgl_demo.h中 加入一下内容
/** @Author: Nsouther nsouther@163.com* @Date: 2025-05-28 11:13:01* @LastEditors: Nsouther nsouther@163.com* @LastEditTime: 2025-05-30 11:01:01* @FilePath: /esp-idf/Myproject/23_rgb/main/APP/lvgl_demo.h* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE*/
#ifndef __LVGL_DEMO_H
#define __LVGL_DEMO_H#include "esp_timer.h"
#include "lvgl.h"
#include "demos/lv_demos.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "lcd.h"
#include "rgblcd.h"
#include "gt9xxx.h"
#include "touch.h"/* 函数声明 */
void lvgl_demo(void);
void disp_enable_update(void);
/* lvgl_demo 入口函数 */
void lv_port_disp_init(void);
/* 初始化并注册显示设备 */
void lv_port_indev_init(void);
/* 初始化并注册输入设备 */
void touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
/* 图形库的触摸屏读取回调函数 */
static void increase_lvgl_tick(void *arg);
/* 告诉 LVGL 运行时间 */
static void lvgl_disp_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area,
lv_color_t *color_map); /* 将内部缓冲区的内容刷新到显示屏上的特定区域 */
#endif
我们在这里主要做了如下修改

加入了LCD屏幕的初始化 在LCD屏幕初始化中获取了屏幕的大小 宽度和高度

这个是主要的函数,调用了lvgl的画点函数

其次是时基函数 提供时间基准 初始化了一个定时器 1000us 1ms

main函数

main函数比较简单,主要就是初始化了一些外设,然后跳转到lvgl的初始化中去了


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "led.h"
#include "lcd.h"
#include "rgblcd.h"#include "xl9555.h"
#include "lvgl_demo.h"
#include "myiic.h"
#include "lvgl.h"
//i2c_obj_t i2c0_master;void app_main(void)
{esp_err_t ret;ret = nvs_flash_init(); /* 初始化 NVS */if (ret==ESP_ERR_NVS_NO_FREE_PAGES || ret==ESP_ERR_NVS_NEW_VERSION_FOUND){ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}myiic_init();               /* IIC初始化 */xl9555_init();              /* XL9555初始化 */lvgl_demo(); /* 运行 LVGL 例程 */
}

在lvgl_demo()中初始化了lvgl的驱动 以及显示 触摸的驱动 最后运行一个音乐界面来演示效果

lvgl的图形化配置

在调用lvgl前 首先需要将其注册成组件 在esp_lvgl的CMakeLists.txt中增加下面一行,表示增加lvgl的组件

set(EXTRA_COMPONENT_DIRS ${EXTRA_COMPONENT_DIRS} components/LVGL)

执行idf.py menuconig ->Component Config->LVGL configuration->Demos->Music player demo

LVGL configuration->Font usage 使能12 14 16号字体 其余的暂时不用动

着重要注意的

大部分教程都是这样的 但是在移植过程中出现了绿屏条纹 以及触摸驱动提示接受到了空恢复的问题(i2c)

绿屏问题是驱动的程序有问题,使用23_rbg可以驱动 但是lvgl就不行了 24_touch 里增加了ESP-IDF的官方驱动接口,所以驱动效果好一点,因此使用24的例程,其次i2c接口总是提示收到空数据,实际上是I2C的地址不对,

屏幕驱动的问题

运行时总是报错 说不能被整除,实际上是这个地方给错了,源码给的是48020 实际上是48034 刚好被整除,因此这是一个需要修修改的点

经过上面的修改 可以显示图像 但是触摸不行,调试触摸驱动 提示读取不到数据,后来才知道是gtx触摸芯片的i2c地址错误,源码给的是0x14 但是实际上是0x5D

效果展示


http://www.hkcw.cn/article/cCHrgVDsgM.shtml

相关文章

移动安全Android——客户端静态安全

一、反编译保护 测试工具 Jadx GitHub - skylot/jadx: Dex to Java decompiler PKID [下载]PKID-APP查壳工具-Android安全-看雪-安全社区|安全招聘|kanxue.com 测试流程 &#xff08;1&#xff09;通过Jadx对客户端APK文件进行反编译&#xff0c;观察是否进行代码混淆 &…

支持功能安全ASIL-B的矩阵管理芯片IS32LT3365,助力ADB大灯系统轻松实现功能安全等级

随着自动驾驶技术的快速发展&#xff0c;汽车前灯智能化也越来越高。自适应远光灯 (ADB) 作为一种智能照明系统&#xff0c;在提升驾驶安全性和舒适性方面发挥着重要作用。ADB 系统通过摄像头和传感器获取前方道路信息&#xff0c;例如来车的位置、距离和速度&#xff0c;并根据…

Python训练营打卡Day40

DAY 40 训练和测试的规范写法 知识点回顾&#xff1a; 1.彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中 2.展平操作&#xff1a;除第一个维度batchsize外全部展平 3.dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 作…

晨控CK-FR03与汇川H5U系列PLC配置MODBUS TCP通讯连接操作手册

晨控CK-FR03与汇川H5U系列PLC配置MODBUS TCP通讯连接操作手册 CK-FR03-TCP是一款基于射频识别技术的高频RFID标签读卡器&#xff0c;读卡器工作频率为13.56MHZ&#xff0c;支持对I-CODE 2、I-CODE SLI等符合ISO15693国际标准协议格式标签的读取。 读卡器同时支持标准工业通讯协…

二叉树实验

引言 在数据结构的学习过程中&#xff0c;二叉树作为一种典型的非线性结构&#xff0c;其构造和操作方式具有高度的层次性和结构性。而递归正是处理这种结构最自然的方式之一。关于二叉树的基本结构如下图所示&#xff1a; 递归的本质是函数调用自身的过程&#xff0c;这恰好…

【空间光学系统与集成微纳光子学系统简介】

空间光学系统 空间光学系统指用于太空探测、遥感、通信等领域的光学仪器&#xff0c;通常具备高分辨率、轻量化、抗辐射等特性。主要应用包括&#xff1a; 天文观测&#xff1a;如哈勃望远镜、詹姆斯韦伯太空望远镜&#xff08;JWST&#xff09;&#xff0c;利用大口径主镜收集…

开发一款IIS自动检测修复工具

目录 实现的功能 技术栈与依赖 DLL 实现细节 变量 初始化操作 自定义cpu阈值 检测IIS应用程序池 获取自定义阈值 获取某个应用程序池的占用率 获取性能计数器实例名 Kill 并重新启动应用池 写入日志到 Log 目录&#xff0c;并显示在文本框中 实际运行效果 此工具可…

网络编程4-epoll

select底层原理 fd_set底层使用位图标记每个文件标识符有没有被使用&#xff0c;位图在c语言里靠数组实现。 select 流程 在用户态空间里&#xff08;栈、堆、数据段&#xff09;申请一个fd_set将fd_set从用户态拷贝到内核态&#xff08;在后面操作系统轮询会使用到&#xff09…

SOC-ESP32S3部分:19-ADC模数转换

飞书文档https://x509p6c8to.feishu.cn/wiki/XycAwmO6Niitdtka1RAcclYfnvf ESP32-S3 集成了两个 12 位 SAR ADC&#xff0c;共支持 20 个模拟通道输入。 SAR ADC 管脚通过 IO MUX 与 GPIO1 ~ GPIO20、RTC_GPIO1 ~ RTC_GPIO20、触摸传感器接口、UART 接口、SPI 接口、以及 USB…

默克微生物培养基选择指南

微生物学研究需要能在实验室提供各种不同种类的细菌、酵母或病毒。诸如发酵、蛋白质和疫苗生产的大规模过程需要大量处于生理活性状态的细菌。因此&#xff0c;针对各种应用需要有能提供适当的生化环境并保持微生物所有特征的合适的营养培养基。 任何微生物培养基都应包括营养…

移动安全Android——解决APP抓包证书无效问题

问题 通过Burpsuite和ProxyPin进行代理抓包Android APP的时候发现虽然已经正确添加了用户证书&#xff0c;但是还是会出现SSL握手错误&#xff0c;证书无效问题。这是因为Android 7 以上版本APP默认不信任用户证书&#xff0c;只信任系统证书&#xff0c;所以需要将用户证书移动…

【数据库】数据库恢复技术

数据库恢复技术 实现恢复的核心是使用冗余&#xff0c;也就是根据冗余数据重建不正确数据。 事务 事务是一个数据库操作序列&#xff0c;是一个不可分割的工作单位&#xff0c;是恢复和并发的基本单位。 在关系数据库中&#xff0c;一个事务是一条或多条SQL语句&#xff0c…

【学习笔记】深度学习-梯度概念

一、定义 梯度向量不仅表示函数变化的速度&#xff0c;还表示函数增长最快的方向 二、【问】为什么说它表示方向&#xff1f; 三、【问】那在深度学习梯度下降的时候&#xff0c;还要判断梯度是正是负来更新参数吗&#xff1f; 假设某个参数是 w&#xff0c;损失函数对它的…

【ROS2实体机械臂驱动】rokae xCoreSDK Python测试使用

【ROS2实体机械臂驱动】rokae xCoreSDK Python测试使用 文章目录 前言正文配置环境下载源码配置环境变量测试运行修改点说明实际运行情况 参考 前言 本文用来记录 xCoreSDK-Python的调用使用1。 正文 配置环境 配置开发环境&#xff0c;这里使用conda做python环境管理&…

深入浅出网络分析与故障检测工具

目录 网络故障检测工具&#xff1a;别只靠“Ping 不通” 实战组合拳&#xff1a;分析 检测 问题闭环 四、选择工具的几个建议 五、总结&#xff1a;工具是手段&#xff0c;思维才是核心 在如今这个“数据就是生命线”的时代&#xff0c;网络的稳定性和性能直接决定着企业…

使用Haproxy搭建Web群集

目录 1&#xff0c;Haproxy简介 1&#xff0c;核心功能与特点 二&#xff0c;搭建haproxy群集 1&#xff0c;准备工作 2&#xff0c;修改haproxy的配置文件 3&#xff0c;准备网站 4&#xff0c;配置日志 5&#xff0c;验证 1&#xff0c;Haproxy简介 HAProxy 是一款高…

Elasticsearch的写入流程介绍

Elasticsearch 的写入流程是一个涉及 分布式协调、分片路由、数据同步和副本更新 的复杂过程,其设计目标是确保数据一致性、可靠性和高性能。以下是写入流程的详细解析: 一、写入流程总览 二、详细步骤解析 1. 客户端请求路由 请求入口:客户端(如 Java 客户端、REST API)…

记录一次apisix上cros配置跨域失败的问题

安全要求不允许跨域请求&#xff0c;但是业务侧由于涉及多个域名&#xff0c;并且需要共享cookie&#xff0c;所以需要配置跨域。 在apisix上配置了cors如下。 结果安全漏扫还是识别到了跨域请求的漏洞。 调试了cors.lua的插件脚本&#xff0c;发现apisix上是如果不在allowOri…

VSCode无法转到定义python源码(ctrl加单击不跳转)

已经尝试的方案&#xff1a; 1.确保对应python环境正确激活 在 VSCode 中&#xff0c;打开命令面板&#xff08;CtrlShiftP&#xff09;&#xff0c;输入并选择 Python: Select Interpreter&#xff0c;然后从列表中选择正确的 Python 解释器。 2.重新卸载Python插件再重新安装…

会议室钥匙总丢失?换预约功能的智能门锁更安全

在企业日常运营中&#xff0c;会议室作为重要的沟通与协作场所&#xff0c;其管理效率与安全性直接影响着企业的运作顺畅度。然而&#xff0c;传统会议室管理方式中钥匙丢失、管理不便等问题频发&#xff0c;给企业带来了不少困扰。近期&#xff0c;某企业引入了启辰智慧预约系…