目录

LVGL简介

LVGL特点

LVGL运行的硬件要求

LVGL相关网址

LVGL源码下载

LVGL移植需求

LVGL移植过程

添加源码

添加源码头文件路径

修改堆栈大小

C99的支持

修改工程

编译工程

更改lv_conf文件

更改lv_port_disp_template.c接口文件

修改 lv_conf.h

​​​​​​​显示实现

实验结果


​​​​​​​


LVGL简介

LittlevGL是一个免费的开源图形库,提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素、漂亮的视觉效果和低内存占用。

LVGL特点

  1. 强大的构建模组:按钮、图表、列表、滑块、图像等
  2. 先进的图形:动画、反锯齿、半透明、平滑滚动
  3. 多样的输入设备:触摸板、鼠标、键盘、编码器等
  4. 多显示器支持:支持同时使用多个TFT或单色显示器
  5. 多语言支持:格式文字编码
  6. 硬件无关:可用于任UTF-8意微控制器或显示器
  7. 可裁剪:用于小内存(64 KB FLASH,16 KB RAM)操作
  8. 外部支持:操作系统、外部存储以及GPU
  9. 单帧缓存:即可实现先进的图形效果
  10. C语言编写:以最大化兼容(C++ 兼容)
  11. 模拟器:无需嵌入式硬件就可以在电脑上开始GUI设计
  12. 文档:在线及离线
  13. 免费开源:基于MIT协议

LVGL运行的硬件要求

名称

最小值

推荐值

Arch

>= 16位的微控制器或处理器

Clock

> 16 MHz 时钟速度

Flash/ROM

> 64 kB

> 180 kB

Static RAM

~2 kB,取决于使用的功能和对象类型

Stack

> 2 kB

> 8 kB

Heap

> 4 KB

> 32 kB

Compiler

C99或以上

LVGL相关网址

  1. LVGL官网:LVGL - Light and Versatile Embedded Graphics Library
  2. LVGL代码库地址(Simulator、Source、Examples、Esp32、MicroPython):https://github.com/lvgl
  3. LVGL源码下载地址:https://github.com/lvgl/lvgl

LVGL源码下载

  1. 在源码链接中下载一份源码,LVGL已经更新迭代了很多个版本,这里我们选择8.0.1版本来移植。

注意:不同版本之间有很大的不同,尽量使用与本文相同的版本,否则不予解释。

3. 下载后得到如下目录结构

4. 源码各文件作用

  1. github:github的配置文件,忽略即可。
  2. docs:说明文档。
  3. examples:示例代码。
  4. scripts:配置脚本,Linux平台会用到,Windows忽略即可。
  5. src:源代码。
  6. tests:测试代码。
  7. zephyr:忽略即可。

LVGL移植需求

STM32工程,该工程应具备功能

  1. LCD显示(必备)
  2. TOUCH触摸(可选)
  3. DMA刷屏(可选)
  4. 内存管理(可选)
  5. 操作系统(可选)

注意:本示例中使用1.3寸TFTLCD,分辨率为240*240,使用SPI驱动。采用DMA双缓冲刷屏。

LVGL移植过程

添加源码

  1. 在工程目录下创建LVGL文件夹,如下图所示

2. 将LVGL的源码目录(lvgl-8.0.1\src)复制到工程中的LVGL目录中

3.  将LVGL的驱动接口文件目录(lvgl-8.0.1\examples\porting)复制到本工程中的LVGL文件夹中。其 中共六个文件,disp为显示接口驱动文件(LCD),fs为文件系统接口驱动文件(FATFS),indev为输入设备接口驱动文件(TOUCH)。

4. 将LVGL源码中(lvgl-8.0.1)的lv_conf_template.h更名为lv_conf.h,随后将其与lvgl.h一同拷贝到本地工程中的LVGL目录下。

完成后LVGL目录下的文件如下图所示:

5. 打开工程,在工程的目录结构中添加二个文件夹LVGL_SRC和LVGL_PORT,并把源码添加到其中。(可根据需要进行裁剪)。

添加src目录下的文件如下图:

添加porting目录文件如下图

lv_port_disp_template.c:显示接口文件

lv_port_indev_template.c:输入设备接口文件

本示例只使用lv_port_disp_template.c这个显示的模板。

添加源码头文件路径

修改堆栈大小

如果工程中没有内存管理,则需要修改启动文件中的堆栈。根据官方推荐我们可以把堆栈修改为4K,假如使用的功能比较多,还需要再适当增大。

C99的支持

LVGL的源码需要C99的支持,否则编译无法通过。

修改工程

编译工程

出现错误:

双击错误定位到错误位置发现,该代码包含的头文件路径层级错误,根据目录层级修改。(原来是../../lv_conf,更改为../ lv_conf)

更改lv_conf文件

lv_conf的条件编译没有打开,去到此文件下打开该文件修改保存即可。

再次编译,已没有错误。

​​​​​​​更改lv_port_disp_template.c接口文件

1. 默认lv_port_disp_template.c和lv_port_disp_template.h的条件编译是关闭的,我们需要把他打开并修改包含目录层级。

把头文件更改如下:

2. 更改lv_port_disp_templ.c 文件中lv_port_disp_init驱动函数。此函数提供了三种写缓存方式,保留其中一种即可,本示例采用方式二。更改如下。

3.  更改屏的大小。

4. 添加DMA实现代码,并在disp_init函数中调用DMA的初始化函数(如果不使用DMA,disp_flush函数中只需要保留LCD_Color_Fill、lv_disp_flush_ready这两个函数即可)。注意添加需要的头文件。如#include "lcd.h"

1)添加一个全局变量static lv_disp_drv_t *disp_drv_p;

2)把以下代码添加到lv_port_disp_template.c

/*********************************************************************************************************
* 函 数 名 : DisPlay_SPI_DMA_Init
* 功能说明 : SPI3 DMA1初始化
* 形    参 : 无
* 返 回 值 : 无
* 备    注 : DMA1_Stream7搬运显示数据到SPI3的DR寄存器
*********************************************************************************************************/
static void DisPlay_SPI_DMA_Init()
{DMA_InitTypeDef  DMA_InitStructure = {0};NVIC_InitTypeDef NVIC_InitStruct  = {0};RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); //DMA1时钟使能DMA_DeInit(DMA1_Stream7);while(DMA_GetCmdStatus(DMA1_Stream7) != DISABLE) {}  //等待DMA可配置/* 配置 DMA Stream */DMA_InitStructure.DMA_Channel               = DMA_Channel_0;                //通道选择DMA_InitStructure.DMA_PeripheralBaseAddr  = (unsigned int)&SPI3->DR;       //DMA外设地址DMA_InitStructure.DMA_Memory0BaseAddr      = (unsigned int)buf_2_1;        //DMA 存储器0地址DMA_InitStructure.DMA_DIR                   = DMA_DIR_MemoryToPeripheral;   //存储器到外设模式DMA_InitStructure.DMA_BufferSize          = sizeof(buf_2_2);              //数据传输量DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;    //外设非增量模式DMA_InitStructure.DMA_MemoryInc            = DMA_MemoryInc_Enable;         //存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize   = DMA_PeripheralDataSize_Byte;  //外设数据长度:8位DMA_InitStructure.DMA_MemoryDataSize         = DMA_MemoryDataSize_Byte;      //存储器数据长度:8位DMA_InitStructure.DMA_Mode                  = DMA_Mode_Normal;              //使用普通模式DMA_InitStructure.DMA_Priority              = DMA_Priority_High;            //中等优先级DMA_InitStructure.DMA_FIFOMode               = DMA_FIFOMode_Disable;         //不使用fifoDMA_InitStructure.DMA_FIFOThreshold        = DMA_FIFOThreshold_Full;       //fifo全容量DMA_InitStructure.DMA_MemoryBurst          = DMA_MemoryBurst_Single;       //存储器突发单次传输DMA_InitStructure.DMA_PeripheralBurst        = DMA_PeripheralBurst_Single;   //外设突发单次传输DMA_Init(DMA1_Stream7, &DMA_InitStructure);                                   //初始化DMA StreamSPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE); // SPI3使能DMA发送NVIC_InitStruct.NVIC_IRQChannel = DMA1_Stream7_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStruct);DMA_ITConfig(DMA1_Stream7, DMA_IT_TC, ENABLE);DMA_Cmd(DMA1_Stream7, DISABLE);
}
/*********************************************************************************************************
* 函 数 名 : DisPlay_SPI_DMA_Enable
* 功能说明 : 配置DMA并启动一次传输
* 形    参 : buf:需要搬运的数据的指针;size:搬运的数据量
* 返 回 值 : 无
* 备    注 : 无
*********************************************************************************************************/
void DisPlay_SPI_DMA_Enable(void *buf, unsigned int size)
{DMA1_Stream7->CR &= ~(0x01);while((DMA1_Stream7->CR&0X1)){}DMA1_Stream7->M0AR = (unsigned int)buf;DMA1_Stream7->NDTR = size;DMA1_Stream7->CR |= (0x01);
}
/*********************************************************************************************************
* 函 数 名 : DMA1_Stream7_IRQHandler
* 功能说明 : DMA1_Stream7发送完成中断
* 形    参 : 无
* 返 回 值 : 无
* 备    注 : 无
*********************************************************************************************************/
void DMA1_Stream7_IRQHandler(void)
{if(DMA_GetITStatus(DMA1_Stream7, DMA_IT_TCIF7) != RESET)//if(DMA1->HISR & (1<<27)){DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF7);//DMA1->HIFCR |= (1<<27);LCD_CS = 1;SPI3->DR;    lv_disp_flush_ready(disp_drv_p);    /* tell lvgl that flushing is done */}
}

5. 在disp_init函数中调用DMA的初始化函数。

6. 修改disp_flush函数如下

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{unsigned int size = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2;disp_drv_p = disp_drv;LCD_Address_Set(area->x1, area->y1, area->x2, area->y2+1); LCD_CS = 0;DisPlay_SPI_DMA_Enable(color_p, size);
}

lv_port_disp_templ.c 文件最终更改后如下:


#if 1
#include "lv_port_disp_template.h"
#include "lcd.h"#define MY_DISP_HOR_RES 240  //屏的大小
#define MY_DISP_VER_RES 240
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_VER_RES * 10];                        /*An other buffer for 10 rows*/static lv_disp_drv_t *disp_drv_p;static void disp_init(void);static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);/*********************************************************************************************************
* 函 数 名 : DisPlay_SPI_DMA_Init
* 功能说明 : SPI3 DMA1初始化
* 形    参 : 无
* 返 回 值 : 无
* 备    注 : DMA1_Stream7搬运显示数据到SPI3的DR寄存器
*********************************************************************************************************/
static void DisPlay_SPI_DMA_Init()
{DMA_InitTypeDef  DMA_InitStructure = {0};NVIC_InitTypeDef NVIC_InitStruct  = {0};RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); //DMA1时钟使能DMA_DeInit(DMA1_Stream7);while(DMA_GetCmdStatus(DMA1_Stream7) != DISABLE) {}  //等待DMA可配置/* 配置 DMA Stream */DMA_InitStructure.DMA_Channel               = DMA_Channel_0;                //通道选择DMA_InitStructure.DMA_PeripheralBaseAddr  = (unsigned int)&SPI3->DR;       //DMA外设地址DMA_InitStructure.DMA_Memory0BaseAddr      = (unsigned int)buf_2_1;        //DMA 存储器0地址DMA_InitStructure.DMA_DIR                   = DMA_DIR_MemoryToPeripheral;   //存储器到外设模式DMA_InitStructure.DMA_BufferSize          = sizeof(buf_2_2);              //数据传输量DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;    //外设非增量模式DMA_InitStructure.DMA_MemoryInc            = DMA_MemoryInc_Enable;         //存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize   = DMA_PeripheralDataSize_Byte;  //外设数据长度:8位DMA_InitStructure.DMA_MemoryDataSize         = DMA_MemoryDataSize_Byte;      //存储器数据长度:8位DMA_InitStructure.DMA_Mode                  = DMA_Mode_Normal;              //使用普通模式DMA_InitStructure.DMA_Priority              = DMA_Priority_High;            //中等优先级DMA_InitStructure.DMA_FIFOMode               = DMA_FIFOMode_Disable;         //不使用fifoDMA_InitStructure.DMA_FIFOThreshold        = DMA_FIFOThreshold_Full;       //fifo全容量DMA_InitStructure.DMA_MemoryBurst          = DMA_MemoryBurst_Single;       //存储器突发单次传输DMA_InitStructure.DMA_PeripheralBurst        = DMA_PeripheralBurst_Single;   //外设突发单次传输DMA_Init(DMA1_Stream7, &DMA_InitStructure);                                   //初始化DMA StreamSPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE); // SPI3使能DMA发送NVIC_InitStruct.NVIC_IRQChannel = DMA1_Stream7_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStruct);DMA_ITConfig(DMA1_Stream7, DMA_IT_TC, ENABLE);DMA_Cmd(DMA1_Stream7, DISABLE);
}
/*********************************************************************************************************
* 函 数 名 : DisPlay_SPI_DMA_Enable
* 功能说明 : 配置DMA并启动一次传输
* 形    参 : buf:需要搬运的数据的指针;size:搬运的数据量
* 返 回 值 : 无
* 备    注 : 无
*********************************************************************************************************/
void DisPlay_SPI_DMA_Enable(void *buf, unsigned int size)
{DMA1_Stream7->CR &= ~(0x01);while((DMA1_Stream7->CR&0X1)){}DMA1_Stream7->M0AR = (unsigned int)buf;DMA1_Stream7->NDTR = size;DMA1_Stream7->CR |= (0x01);
}
/*********************************************************************************************************
* 函 数 名 : DMA1_Stream7_IRQHandler
* 功能说明 : DMA1_Stream7发送完成中断
* 形    参 : 无
* 返 回 值 : 无
* 备    注 : 无
*********************************************************************************************************/
void DMA1_Stream7_IRQHandler(void)
{if(DMA_GetITStatus(DMA1_Stream7, DMA_IT_TCIF7) != RESET)//if(DMA1->HISR & (1<<27)){DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF7);//DMA1->HIFCR |= (1<<27);LCD_CS = 1;SPI3->DR;    lv_disp_flush_ready(disp_drv_p);    /* tell lvgl that flushing is done */}
}void lv_port_disp_init(void)
{disp_init();static lv_disp_draw_buf_t draw_buf_dsc_2;lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10);   static lv_disp_drv_t disp_drv;  lv_disp_drv_init(&disp_drv);   disp_drv.hor_res = MY_DISP_HOR_RES;disp_drv.ver_res = MY_DISP_VER_RES;disp_drv.flush_cb = disp_flush;disp_drv.draw_buf = &draw_buf_dsc_2;lv_disp_drv_register(&disp_drv);
}static void disp_init(void)
{/*You code here*/DisPlay_SPI_DMA_Init();
}static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{unsigned int size = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2;disp_drv_p = disp_drv;LCD_Address_Set(area->x1, area->y1, area->x2, area->y2+1); LCD_CS = 0;DisPlay_SPI_DMA_Enable(color_p, size);
}#else
typedef int keep_pedantic_happy;
#endif

修改 lv_conf.h

根据需求修改lv_conf.h中的宏定义

  1. LV_COLOR_DEPTH:屏幕的色彩深度,支持1bit、8bit、16bit、32bit。
  2. LV_COLOR_16_SWAP:字节交换,DMA刷屏的时候需要置1。
  3. LV_MEM_SIZE:GUI可支配的内存空间,根据使用的功能调节。
  4. LV_FONT_MONTSERRAT_*:字体大小,太小会很模糊。

如果需要更改默认字体大小,则把相应的宏设置为1.

​​​​​​​显示实现

1. 配置一个定时器为LVGL提供1ms的时钟心跳,该定时器的中断服务函数中调用lv_tick_inc(1);即可。本示例使用基本定时器7.

2. 主程序中循环调用lv_task_handler函数处理事件

3. 编写显示程序

#include "lvgl.h"
#include "lv_port_disp_template.h"
void Lvgl_Lable_Demo(void)
{lv_obj_t *scr = lv_scr_act();lv_obj_t * label1 = lv_label_create(scr);lv_label_set_long_mode(label1, LV_LABEL_LONG_WRAP);    lv_label_set_recolor(label1, true);                      lv_label_set_text(label1, "#0000ff Re-color# #ff00ff words# #ff0000 of a# label, align the lines to the center ""XYD NN.");  lv_obj_set_width(label1, 150);  lv_obj_set_style_text_align(label1, LV_TEXT_ALIGN_CENTER, 0);   lv_obj_align(label1, LV_ALIGN_CENTER, 0, -40);  lv_obj_t * label2 = lv_label_create(scr);lv_label_set_long_mode(label2, LV_LABEL_LONG_SCROLL_CIRCULAR);     lv_obj_set_width(label2, 150);  lv_label_set_text(label2, "My Name is Chenxingxing. "); lv_obj_align(label2, LV_ALIGN_CENTER, 0, 40);
}

4. main函数调用

int main()
{…..Lcd_Init();lv_init();                       // 初始化lvgllv_port_disp_init();              // 显示初始化Lvgl_Lable_Demo();….while(1){lv_task_handler();Delay_Ms(1);}
}

实验结果

LVGL V0.01版本移植到STM32F4相关推荐

  1. 开源证券交易撮合引擎 jOpenExchg V0.01 预览版

    项目名称:Java Open Exchange Project (jOpenExchg / jopenexchg) 项目当前版本:V0.01 项目简介: 基于GPL Licence的Java的开源证券 ...

  2. Node.js v0.10版本发布

    Node.js研发团队发布了node.js v0.10版本,它是个基于Javascript.用于构建高性能异步服务器的平台.该版本主要更新如下:更易于使用的数据流处理模块,通过域更好地处理错误,此外还 ...

  3. Nacos发布 v0.2 版本,无缝支持 Spring Cloud 微服务生态及高可用集群模式

    2019独角兽企业重金招聘Python工程师标准>>> 近日,阿里巴巴新开源项目Nacos 发布了 v0.2 版本,该版本开始支持完整的Spring生态技术栈,这包括 Spring ...

  4. linux运维面板_phpstudy linux web面板(小皮面板)V0.2版本正式发布

    小皮面板是什么? 小皮面板,是由phpStudy官方团队针对Linux服务器开发推出的一款服务器环境搭建以及管理工具. 可以通过Web端方便.快速的搭建和管理服务器环境,并加入了强大的安全防护功能,提 ...

  5. 开源开放 | 图数据交互可视化分析框架 InteractiveGraph v0.3 版本发布

    图数据交互可视化分析框架 InteractiveGraph 日前发布 v0.3 版本,下载地址:https://github.com/grapheco/InteractiveGraph/release ...

  6. 巨高兴,自己的“万能数据库查询分析器”中英文 3.01版本 已经在国内6大软件下载网站发布

    几个月前开始构思,寻思着从"万能数据库查询分析器"中英文 3.01 版本开始起,一方面,去除原来试用31天的时间限制,用户永久试用:另一方面,尝试提供免费注册的方式,只要用户协助完 ...

  7. php 开发 web面板,phpstudy linux web面板(小皮面板)V0.2版本正式发布

    小皮面板是什么? 小皮面板,是由phpStudy官方团队针对Linux服务器开发推出的一款服务器环境搭建以及管理工具. 可以通过Web端方便.快速的搭建和管理服务器环境,并加入了强大的安全防护功能,提 ...

  8. 图数据交互可视化分析框架InteractiveGraph v0.3版本发布

    图数据交互可视化分析框架 InteractiveGraph日前发布v0.3版本,下载地址:https://github.com/grapheco/InteractiveGraph/releases/t ...

  9. 2012 12 02 FL2440开发板的U-boot-2010.09版本移植(二)片上系统SoC初始化移植

    -------------------------------------------------------- 在"<2012 10 02> FL2440开发板的U-boot- ...

最新文章

  1. 2020年春季学期信号与系统课程作业参考答案-第十四次作业
  2. android studio 插件开发 FindByTag插件 局部情况下取代ButterKnife插件
  3. jQuery遍历之next()、nextAll()方法使用实例
  4. PE关于导入表(IAT)知识复习
  5. uefi多linux系统启动盘,DIY制作无需格BIOS+UEFI双启动U盘工具|支持syslinux+grub+boomgr+grub2多启动...
  6. cmake 编译安装方法
  7. Linux文本处理tr命令笔记
  8. 对 app_offline.htm 的几点错误认识
  9. Zookeeper - zookeeper安装与配置
  10. [转帖]从 2G 到 5G,手机上网话语权的三次改变
  11. 五子棋软件测试自学,初学者如何从零开始自学五子棋
  12. 可视化html css布局,一个开源可视化布局项目,在线生成纯css布局,可阅读的代码...
  13. 2022软件测试技能 Apache JMeter 性能测试从入门到精通
  14. 怎么注册quora?
  15. python列表输出序号_Python中打印列表的序号和内容
  16. SCI投稿:MDPI旗下期刊Mathematics投稿经历
  17. MacBook重启之后,外接显示器不亮的解决方法
  18. 建筑群子系统的设计步骤
  19. Ext js 4 全选和反选
  20. Java如何实现定时任务?

热门文章

  1. 动规(11)-踩方格
  2. 几何变换详解:平移、缩放、旋转
  3. Syscall的实现
  4. 【微信小程序+echarts点亮中国地图】微信小程序echarts中国地图点亮功能
  5. python os.urandom()函数和十六进制\xhh的一些认识
  6. 吐血整理一个月——终于把所有Python库整理齐了.....
  7. java编程电话号码查询_java课程设计电话号码查询系统(15页)-原创力文档
  8. AG9311/AG9310 Type-C转HDMI设计方案|替代AG9310/AG9311芯片|GSV2201可完全替代兼容AG9310/AG9311
  9. 从0开始建设saas - 系统对接中的问题整理
  10. Python基本数据类型--列表