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

LVGL移植和图片显示

最近闲来无事,偶尔刷到了移植LVGL的教程,今天肝完了机械原理又移植完LVGL库,真是收获满满的一天,先接一杯水去。

回来了,发个朋友圈高级一下,好困。

lvgl v8.3移植及组件使用_lvgl界面编辑器-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_45209978/article/details/127374115?spm=1001.2014.3001.5506LVGL - Light and Versatile Embedded Graphics Libraryicon-default.png?t=N7T8https://lvgl.io/tools/imageconverter以上的两个网址分别为野火霸天虎移植LVGL的教程,第二个是一个图片转C代码的一个在线网址。

具体步骤大概就是,我总结一下。

获取LVGL源码

先从github获取lvgl的源码


地址:GitHub - lvgl/lvgl: Embedded graphics library to create beautiful UIs for any MCU, MPU and display type.
这里选择v8.3下载

这是压缩包中含有的所有文件,接下来根据个人意愿进行修改。

删掉多余的东西 , 只保留以下部分。

为什么把其他的删掉,因为它们不包含我们需要的.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,


把所有的c文件加入到项目中

对的,就是所有。并且需要在

这个页面把所有的文件文件夹位置添加进去,(md,累死我了)。

在添加完所有文件之后就相当于移植进去了LVGL库。

根据实际情况修改   #include "lvgl\lvgl.h"    或者    #include "lvgl.h".

(  看编译器是否能找到文件位置  )

之后编译,一般有错就是xxx函数未定义,那肯定就是添加c文件的时候落东西了。

直到没有错误,一堆警告为止。(doghead)


工程文件修改

这里搬运一下大佬的。

1.启动文件

注意在启动文件中修改堆、栈大小,建议各设置 8kB 空间:(大一些也没关系)


2.lvgl

在做这个之前最好先了解一下你的屏幕是怎么驱动的,然后再做下面的工作。

1.先打开 lv_conf.h

  • 第27行,根据屏幕颜色数据类型修改
  • 第52行,指定lvgl的动态内存可用大小
  • 第96行,每英寸的像素,根据自己屏幕尺寸和像素算一下就好
  • 第258行,开启style初始化断言

其他的浏览一下即可,用到的时候再去深究。

打开 lv_port_disp_template.h,将开头的 #if 0 条件编译取消 ,把0改成1
打开 lv_port_disp_template.c,将开头的 #if 0 条件编译取消,把0改成1,设置一下屏幕宽和高的像素。

#define MY_DISP_HOR_RES    480
#define MY_DISP_VER_RES    800

2.看下面的 void lv_port_disp_init(void)

LVGL缓冲区的图像写入有三种方式

  • 第一种:一个缓冲区,默认存10行图像
  • 第二种:两个缓冲区,默认每个缓冲区存10行图像
  • 第三种:两个缓冲区,每个缓冲区存一整个屏幕的图像


这里我们用第二种,把第一种和第三种注释掉即可。

第二种是为存在DMA之类的数据传送机制的硬件设计的,可以把传送缓冲区的内容交给DMA处理,而cpu去执行其他工作(比如渲染),这里我暂时没用DMA,这样的话效果和第一种是一样的。(注:缓冲区大小为屏幕的1/10效果会比较好,这里为了节约一点RAM没有改大小)

也要记得把下面的  &draw_buf_dsc_1  改成  &draw_buf_dsc_2 。

void lv_port_disp_init(void)
{/*-------------------------* Initialize your display* -----------------------*/disp_init();/*-----------------------------* Create a buffer for drawing*----------------------------*//*** LVGL requires a buffer where it internally draws the widgets.* Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.* The buffer has to be greater than 1 display row** There are 3 buffering configurations:* 1. Create ONE buffer:*      LVGL will draw the display's content here and writes it to your display** 2. Create TWO buffer:*      LVGL will draw the display's content to a buffer and writes it your display.*      You should use DMA to write the buffer's content to the display.*      It will enable LVGL to draw the next part of the screen to the other buffer while*      the data is being sent form the first buffer. It makes rendering and flushing parallel.** 3. Double buffering*      Set 2 screens sized buffers and set disp_drv.full_refresh = 1.*      This way LVGL will always provide the whole rendered screen in `flush_cb`*      and you only need to change the frame buffer's address.*//* Example for 1) */
//    static lv_disp_draw_buf_t draw_buf_dsc_1;
//    static lv_color_t buf_1[MY_DISP_HOR_RES * 10];                          /*A buffer for 10 rows*/
//    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*//* Example for 2) */static lv_disp_draw_buf_t draw_buf_dsc_2;static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10];                        /*A buffer for 10 rows*/static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10];                        /*An other buffer for 10 rows*/lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*//* Example for 3) also set disp_drv.full_refresh = 1 below*/
//    static lv_disp_draw_buf_t draw_buf_dsc_3;
//    static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES];            /*A screen sized buffer*/
//    static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES];            /*Another screen sized buffer*/
//    lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2,
//                          MY_DISP_VER_RES * LV_VER_RES_MAX);   /*Initialize the display buffer*//*-----------------------------------* Register the display in LVGL*----------------------------------*/static lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/lv_disp_drv_init(&disp_drv);                    /*Basic initialization*//*Set up the functions to access to your display*//*Set the resolution of the display*/disp_drv.hor_res = MY_DISP_HOR_RES;disp_drv.ver_res = MY_DISP_VER_RES;/*Used to copy the buffer's content to the display*/disp_drv.flush_cb = disp_flush;/*Set a display buffer*/disp_drv.draw_buf = &draw_buf_dsc_2;/*Required for Example 3)*///disp_drv.full_refresh = 1;/* Fill a memory array with a color if you have GPU.* Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.* But if you have a different GPU you can use with this callback.*///disp_drv.gpu_fill_cb = gpu_fill;/*Finally register the driver*/lv_disp_drv_register(&disp_drv);
}

3.屏幕初始化

/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{/*You code here*/NT35510_Init ();
}

4.刷新缓冲区

/*Flush the content of the internal buffer the specific area on the display*You can use DMA or any hardware acceleration to do this operation in the background but*'lv_disp_flush_ready()' has to be called when finished.*/
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{if(disp_flush_enabled) {uint32_t width = area->x2 - area->x1 + 1;uint32_t height = area->y2 - area->y1 + 1;NT35510_OpenWindow(area->x1,area->y1,width,height);NT35510_Write_Cmd ( CMD_SetPixel );	for(uint32_t i = 0;i < width * height;i++){NT35510_Write_Data ( color_p->full );color_p++;}//        /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*///        int32_t x;
//        int32_t y;
//        for(y = area->y1; y <= area->y2; y++) {
//            for(x = area->x1; x <= area->x2; x++) {
//                /*Put a pixel to the display. For example:*/
//                /*put_px(x, y, *color_p)*/
//                color_p++;
//            }
//        }}/*IMPORTANT!!!*Inform the graphics library that you are ready with the flushing*/lv_disp_flush_ready(disp_drv);
}

5.接下来修改main函数

int main ( void )
{LED_GPIO_Config();NT35510_Init ();  TIM7_Configuration();DEBUG_USART_Config();lv_init();lv_port_disp_init();lv_obj_t* btn = lv_btn_create(lv_scr_act()); lv_obj_set_pos(btn, 100, 100);lv_obj_set_size(btn, 120, 50);lv_obj_t* label = lv_label_create(btn);lv_label_set_text(label, "Button");lv_obj_center(label);//	GTP_Init_Panel();while ( 1 ){lv_timer_handler();}
}

6.在周期位1s定时器中断里添加函数给lvgl做时钟

void  BASIC_TIM7_IRQHandler (void)
{if ( TIM_GetITStatus( BASIC_TIM7, TIM_IT_Update) != RESET ){lv_tick_inc(1);TIM_ClearITPendingBit(BASIC_TIM7, TIM_IT_Update);}
}

上述的有些操作调用了其他文件的函数,记得要包含相应函数的头文件,

比如SysTick_Handler()调用了lv_tick_inc(),那么在stm32f4xx_it.c开头要 加上#include “lvgl/lvgl.h”


效果如图所示

图片显示

1.首先准备一张英文名字的图片(不能是数字或者字母)

之后在在线转换网站中


2.按图所示进行设置之后输入图片,生成C代码


3.把C文件加入到工程中

图片文件不能太大,要不然单片机的flash放不下(也许可以放在sd卡中)。


4.将以下代码放到main函数中。

	lv_obj_t * bg_top;LV_IMG_DECLARE(nahida);bg_top = lv_img_create(lv_scr_act());lv_img_set_src(bg_top, &nahida );

就可以对图片进行显示。效果如下:

相关文章:

  • 聚焦新版综合编程能力面试考查汇总
  • Vue18-列表渲染
  • 零基础直接上手java跨平台桌面程序,使用javafx(四)用Apache POI读取excel文件。
  • 【Jenkins+K8s】持续集成与交付 (二十):K8s集群通过Deployment方式部署安装Jenkins
  • 三高系统的架构设计方案:高并发、高可用、高性能
  • WebSphere面试题精选和参考答案(3万字长文)
  • 1789. 员工的直属部门
  • 「前端+鸿蒙」鸿蒙应用开发-TS接口-语法多态
  • 生成式人工智能重置:从初期热潮到战略扩展
  • STM32 ST-LINK Utility的下载安装使用说明如下:
  • 【ai】pycharm远程ssh开发
  • 步态控制之足旋转点(Foot Rotation Indicator, FRI)
  • FFmpeg开发笔记(三十六)Linux环境安装SRS实现视频直播推流
  • 实验五、IPv4地址的子网划分,第1部分《计算机网络》
  • 在AWS上运行的EKS Elastic Kubernetes Service 创建集群Cluster,Node group, Nodes
  • 【译】理解JavaScript:new 关键字
  • ➹使用webpack配置多页面应用(MPA)
  • Babel配置的不完全指南
  • input的行数自动增减
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • JDK9: 集成 Jshell 和 Maven 项目.
  • mac修复ab及siege安装
  • Mybatis初体验
  • Windows Containers 大冒险: 容器网络
  • 从伪并行的 Python 多线程说起
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 如何实现 font-size 的响应式
  • 使用 Docker 部署 Spring Boot项目
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • # AI产品经理的自我修养:既懂用户,更懂技术!
  • ######## golang各章节终篇索引 ########
  • #HarmonyOS:基础语法
  • #Z0458. 树的中心2
  • $(selector).each()和$.each()的区别
  • $jQuery 重写Alert样式方法
  • (cljs/run-at (JSVM. :browser) 搭建刚好可用的开发环境!)
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (六)软件测试分工
  • (四)activit5.23.0修复跟踪高亮显示BUG
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (转)iOS字体
  • (转)Oracle存储过程编写经验和优化措施
  • (转)编辑寄语:因为爱心,所以美丽
  • ***监测系统的构建(chkrootkit )
  • *算法训练(leetcode)第三十九天 | 115. 不同的子序列、583. 两个字符串的删除操作、72. 编辑距离
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .NET Project Open Day(2011.11.13)
  • .Net Winform开发笔记(一)
  • .NET 跨平台图形库 SkiaSharp 基础应用
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .net项目IIS、VS 附加进程调试
  • @Transactional 竟也能解决分布式事务?
  • [20161101]rman备份与数据文件变化7.txt