LVGL移植到STM32 MCU平台详细经验笔记教程

2024-05-24 01:28

本文主要是介绍LVGL移植到STM32 MCU平台详细经验笔记教程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、前言

在之前的一篇文章LVGL在VSCode中安装模拟器,已经对LVGL进行了较为详细的介绍,本文将着重讲解如何移植适配LVGL,让这款图形化GUI库在STM32或其它类型的嵌入式MCU设备上运行起来。

LVGL在VScode中安装模拟器运行配置笔记教程_vscode lvgl-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_49337111/article/details/136536375?spm=1001.2014.3001.5502

本文所使用的目标硬件设备为STM32F407VET6,LVGL版本为8.3。

提醒:LVGL移植时除了LCD液晶显示触摸屏的引脚初始化和硬件平台有关外,只有一个LVGL的心跳会和硬件平台及对应的库有关。因此本文的移植教程,适用于各类嵌入式MCU平台,标准库及HAL库等。

2、LVGL源码下载及加入工程

2.1 下载LVGL源码

进入LVGL的仓库,选择如图所示的v8.3分支下载。

项目目录预览 - lvgl - GitCodeicon-default.png?t=N7T8https://gitcode.com/lvgl/lvgl/tree/release%2Fv8.3?init=initRepo

2.2 LVGL工程结构完善

①、解压下载的LVGL库压缩包,复制如下图所示被选中的文件,(demosexamplessrclv_conf_template.hlvgl.h),其余的其它的文件可以根据需要进行选择是否去除。

将选中的文件复制到项目工程文件目录下的LVGL文件夹下,(没有则手动创建LVGL文件夹)。

②、如下图所示为移植LVGL工程时,所需要的文件。

③、将examples目录下的,porting文件夹复制到LVGL目录下,examples下其它文件可以直接删除。

④、修改文件名

为了标准化,规范化,将如下图所示,将porting文件夹中的所有文件文件名去除 template,并在其对应的.c或.h文件中,将include包含了这些文件的代码进行修改。

将如下图所示的lv_conf_template.h的文件名修改为lv_conf.h,并将各文件中,include包含的文件名进行修改。

3、LVGL移植到MCU工程中

3.1、在工程中新建文件夹

LVGL_SRC             //存放LVGL的源码文件

LVGL_PORTING    //存放LVGL的移植文件

LVGL_APP             //存放LVGL的用户APP文件

LVGL_DEMO         //存放LVGL的Demo文件

3.2、将LVGL库文件加入到工程

添加LVGL源文件,将LVGL/src目录下的core、draw、font、hal、misc、widgets、extra文件夹下的所有文件全部添加进LVGL_SRC组中,如果文件夹内还有子文件夹,则需依次打开,将全部的.c源文件加入到工程中。

将LVGL/porting目录下的全部源文件加入到LVGL_PORTING组中

添加LVGL头文件

3.3、勾选C99模式和取消微库

3.4、编译整个工程

将全部的LVGL源文件和头文件正常加入到工程中,编译整个工程时,应该是没有错误的。如果存在报错,请检查未加入LVGL库时,工程编译是否存在错误。是否存在文件及头文件路径未加入工程。

4、LVGL显示屏移植适配

在完成上述操作后,就可以开始对显示屏进行移植适配操作。

4.1、修改lv_port_disp.c文件

打开lv_port_disp.c文件,并开启如图所示的宏定义

注释掉lv_port_disp.c文件中的这一部分内容,后面有需要再添加、修改

    //注释掉lv_port_disp.c文件中的这一部分内容,后面有需要再添加、修改/* 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*/

找到lv_pory_disp.c文件中的disp_flush 函数,注释掉如下图中框选中的内容,添加自己屏幕对应的像素填充函数,或者根据屏幕实际情况进行修改

//在指定区域内填充指定颜色块
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//color:要填充的颜色
void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)
{  u16 height,width;u16 i,j;width=ex-sx+1;             //得到填充的宽度height=ey-sy+1;            //高度for(i=0;i<height;i++){setCursor(sx,sy+i);           //设置光标位置      LCD->LCD_REG = 0x2C;        //开始写入GRAMfor(j=0;j<width;j++){    LCD->LCD_RAM=color[i*width+j];    //写入数据 }}          
}

4.2、修改lv_port_disp.h文件

打开lv_port_disp.h文件,并开启如下图所示的宏定义

#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
将图中的红框内的代码全部删除,换成
#include "lvgl.h"'

4.3、修改lv_conf.h文件

打开lv_conf.h文件,开启宏定义并加入屏幕分辨率信息

//设置屏幕的分辨率---需根据屏幕的实际情况进行修改
//注意、特别提醒:屏幕有横屏显示和竖屏显示之分,请仔细检查屏幕到底是横屏显示,还是竖屏显示,否则后面可能会出现显示界面不完整,或者显示有问题。
//如果遇到显示不全、有问题,可以尝试,将分辨率数据调换一下
#define MY_DISP_HOR_RES  240
#define MY_DISP_VER_RES  320

4.4、添加LVGL心跳

创建一个单片机1ms定时器,并在定时器的中断处理函数中加入LVGL心跳。创建和单片机型号和对应的库有关,请根据实际的目标平台进行修改处理,下面以STM32F4的标准库为例:

①、timer.c
#include "Timer.h"/*** @brief  定时器2配置(1ms触发一次定时器中断)* @param  NONE* @retval NONE*/
void TIM2_Init(void)
{       /** 使能相关时钟 **/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);          // 使能定时器时钟 /** 配置TIM2中断优先级 **/NVIC_InitTypeDef NVIC_InitStructure;                          // 声明优先级配置结构体NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;               // 中断通道来源        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;      // 抢占优先级      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;              // 子优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;               // 使能通道NVIC_Init(&NVIC_InitStructure);                               // 配置写入寄存器/** 配置所用TIM的时基 **/TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;               // 声明时基配置结构体TIM_TimeBaseStructure.TIM_Prescaler = 84-1;                  // 分频; 把接口时钟分频后给计数器使用, 即多少个接口脉冲,才产生一次计数器脉冲; 简单理解:计算每一计数器脉冲的时长;TIM_TimeBaseStructure.TIM_Period = 1000-1;                    // ARR, 自动重载值; 多少个计数器脉冲作为一周期; 注意:TIM2和5是32位的,其它TIM是16位的;TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;         // 采样时钟分频TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;     // 计数方式    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);               // 初始化定时器,把配置写入寄存器//t = (arr+1) * (psc+1) / Freq//t = (84-1+1) * (1000-1+1) / 84 000 000//t = 0.001
s/** 配置中断 **/TIM_ClearFlag(TIM2, TIM_FLAG_Update);                         // 清除定时器更新中断标志位TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);                      // 开启定时器更新中断/** 使能定时器 **/TIM_Cmd(TIM2, ENABLE);                                          // 使能定时器            
}// 中断服务函数
void  TIM2_IRQHandler (void)
{if ( TIM_GetITStatus( TIM2, TIM_IT_Update) != RESET ) {    lv_tick_inc(1);          //定时器中加入LVGL心跳TIM_ClearITPendingBit(TIM2 , TIM_IT_Update);           }             
}
②、timer.h
#ifndef __TIMER_H
#define __TIMER_H#include "stm32f4xx.h"#include "lvgl.h"void TIM2_Init(void);
void  TIM2_IRQHandler (void);#endif

4.5、测试LVGL的显示功能

如下所示为测试LVGL移植功能的main.c,根据实际情况进行修改

#include "stm32f4xx.h"
#include "led.h"
#include "USART.h"
#include "Timer.h"
#include "LCD_ILI9341.h"
#include "XPT2046.h"#include "lvgl.h"
#include "lv_port_disp.h"/*** LVGL专业点灯Demo*/
void lv_example_led_1(void)
{/*Create a LED and switch it OFF*/lv_obj_t * led1  = lv_led_create(lv_scr_act());lv_obj_align(led1, LV_ALIGN_CENTER, -80, 0);lv_led_off(led1);/*Copy the previous LED and set a brightness*/lv_obj_t * led2  = lv_led_create(lv_scr_act());lv_obj_align(led2, LV_ALIGN_CENTER, 0, 0);lv_led_set_brightness(led2, 150);lv_led_set_color(led2, lv_palette_main(LV_PALETTE_RED));/*Copy the previous LED and switch it ON*/lv_obj_t * led3  = lv_led_create(lv_scr_act());lv_obj_align(led3, LV_ALIGN_CENTER, 80, 0);lv_led_on(led3);
}int main(void)                                         
{    //其它外设初始化代码             NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      // 设置系统中断优先级分组2USART1_Init(115200);                                 // USART1 初始化,用于与串口软件通信; TX-PA9、RX-PA10, 115200-8-N-1,中断发送、接收TIM2_Init();                                               Led_Init();                                          // LED 初始化LED_RED_ON;                                            LED_BLUE_ON;W25Q128_Init ();                                     // 外部Flash 初始化,其内部存储有汉字字模数据//显示屏、触摸屏初始化代码                       LCD_Init();                                          // LCD 初始化;XPT2046_Init(xLCD.width , xLCD.height, xLCD.dir);    // 触摸 初始化XPT2046_Cmd(ENABLE);                                 // 触摸使能:打开//LVGL初始化lv_init();lv_port_disp_init();//LVGL测试Demo                                        lv_example_led_1();while (1)                                            // while函数死循环,不能让main函数运行结束,否则会产生硬件错误{                                                  lv_task_handler();                               //LVGL事物处理,必须加到循环中}
}

LVGL移植正常,显示效果。

4.6、屏幕异常显示说明

程序编译下载到开发板后,如果出现有数据显示,但显示不正常,需要着重检查以下2个方面:

①、检查屏幕的显示方向,是横屏显示还是竖屏显示,可以和店家或厂家沟通咨询;

②、LVGL调用的屏幕数据刷新部分是否正常,即disp_flush函数的内容。

博主此前就是没有弄清楚显示屏的横屏、竖屏,导致程序烧录后,出现如下所示的显示不全。

如果可以查看到显示屏驱动源码,并且有设置屏幕显示方向的接口,那么也可以直接修改屏幕的显示方向。

注意:修改了屏幕的显示方向时,如果有用到触摸屏,也要一同修改触摸屏的方向!!!

5、LVGL触摸屏移植适配

5.1、修改lv_port_indev.h文件

打开lv_port_indev.h文件,开启该文件的宏定义,并包含触摸屏相关的头文件

5.2、修改lv_port_indev.c文件

①、打开lv_port_indev.c文件

如下图所示,开启该文件的宏定义,并修改包含的头文件为最新的文件名

②、修改lv_port_indev_init函数

因为本次移植,仅有一个触摸屏作为输入设备,因此直接屏蔽掉了Mouse、Keypad、Encoder和Button这些输入设备的配置代码。

③、修改LVGL触摸屏触摸和获取触摸坐标函数

打开LCD触摸屏板级驱动文件,添加触摸标志位,并查找获取LCD触摸屏坐标的方式。不同的触摸屏的驱动程序编写方式不同,可以咨询厂家或板级驱动文件开发者,如何获取触摸屏的坐标位置信息等。

通过查看触摸屏的驱动程序确定了触摸屏获取触摸坐标的接口

打开LVGL的输入设备文件lv_port_indev.c,根据实际情况修改touchpad_is_pressed()和touchpad_get_xy()函数。

5.3、修改定时器中断处理函数

打开上面移植LCD触摸屏时的定时器处理函数,在定时器的中断处理函数中,添加触摸屏的触摸扫描检测函数。

这个部分的操作,根据实际情况进行处理,有的触摸屏有单独的中断函数进行触控扫描操作

5.4、LVGL触摸测试

①、添加LVGL触摸Demo到工程

完成如下所示的操作后,还需要将该头文件包含到路径中

②、修改lv_cong.h

打开lv_conf.h文件,找到LV_USE_DEMO_KEYPAD_AND_ENCODER这个宏定义,并将其值改为1,以开启该宏定义

③、触摸测试

包含相应的触摸屏头文件及在代码中添加触摸屏初始化及demo调用的函数

#include "stm32f4xx.h"
#include "led.h"
#include "USART.h"
#include "Timer.h"
#include "LCD_ILI9341.h"
#include "XPT2046.h"#include "lvgl.h"
#include "lv_conf.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"#include "lv_demo_keypad_encoder.h"/*** LVGL专业点灯Demo*/
void lv_example_led_1(void)
{/*Create a LED and switch it OFF*/lv_obj_t * led1  = lv_led_create(lv_scr_act());lv_obj_align(led1, LV_ALIGN_CENTER, -80, 0);lv_led_off(led1);/*Copy the previous LED and set a brightness*/lv_obj_t * led2  = lv_led_create(lv_scr_act());lv_obj_align(led2, LV_ALIGN_CENTER, 0, 0);lv_led_set_brightness(led2, 150);lv_led_set_color(led2, lv_palette_main(LV_PALETTE_RED));/*Copy the previous LED and switch it ON*/lv_obj_t * led3  = lv_led_create(lv_scr_act());lv_obj_align(led3, LV_ALIGN_CENTER, 80, 0);lv_led_on(led3);
}int main(void)                                         
{           NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      // 设置系统中断优先级分组2USART1_Init(115200);                                 // USART1 初始化,用于与串口软件通信; TX-PA9、RX-PA10, 115200-8-N-1,中断发送、接收TIM2_Init();                                               Led_Init();                                          // LED 初始化LED_RED_ON;                                            LED_BLUE_ON;W25Q128_Init ();                                     // 外部Flash 初始化,其内部存储有汉字字模数据LCD_Init();                                          // LCD 初始化;XPT2046_Init(xLCD.width , xLCD.height, xLCD.dir);    // 触摸 初始化XPT2046_Cmd(ENABLE);                                 // 触摸使能:打开LCD_Fill (0, 0, 240, 320, BLACK);                    // 整个背景填充白色LCD_String(15, 8, " LVGL移植测试 ", 24, BLACK, WHITE); // 本函数,可显示中英文字符串; 函数内自动选择font.h中的ASCII字模、Flash中的汉字字模; Flash中已存在放较为完成的汉字字模数据,四字字号,12号、16号、24号、32号,约6M大小lv_init();lv_port_disp_init();lv_port_indev_init();//lv_example_led_1();lv_demo_keypad_encoder();while (1)                                            // while函数死循环,不能让main函数运行结束,否则会产生硬件错误{                                                  lv_task_handler();                //LVGL事物处理}
}

最后提醒:如果移植过程中,出现内存大小报错,需要检查使用的MDK工程是否已经激活了;

如果烧录下载后,程序运行不起来,可以尝试修改启动文件中的,堆空间、栈空间的大小,检查芯片是否满足官方的移植性能要求。

本次移植Demo的程序源码已上传至资源下载区:【免费】LVGL移植到STM32MCU平台通用程序源码资源-CSDN文库icon-default.png?t=N7T8https://download.csdn.net/download/weixin_49337111/89346775?spm=1001.2014.3001.5503

这篇关于LVGL移植到STM32 MCU平台详细经验笔记教程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/996981

相关文章

Python设置Cookie永不超时的详细指南

《Python设置Cookie永不超时的详细指南》Cookie是一种存储在用户浏览器中的小型数据片段,用于记录用户的登录状态、偏好设置等信息,下面小编就来和大家详细讲讲Python如何设置Cookie... 目录一、Cookie的作用与重要性二、Cookie过期的原因三、实现Cookie永不超时的方法(一)

SpringBoot整合liteflow的详细过程

《SpringBoot整合liteflow的详细过程》:本文主要介绍SpringBoot整合liteflow的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋...  liteflow 是什么? 能做什么?总之一句话:能帮你规范写代码逻辑 ,编排并解耦业务逻辑,代码

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

Java Web实现类似Excel表格锁定功能实战教程

《JavaWeb实现类似Excel表格锁定功能实战教程》本文将详细介绍通过创建特定div元素并利用CSS布局和JavaScript事件监听来实现类似Excel的锁定行和列效果的方法,感兴趣的朋友跟随... 目录1. 模拟Excel表格锁定功能2. 创建3个div元素实现表格锁定2.1 div元素布局设计2.

HTML img标签和超链接标签详细介绍

《HTMLimg标签和超链接标签详细介绍》:本文主要介绍了HTML中img标签的使用,包括src属性(指定图片路径)、相对/绝对路径区别、alt替代文本、title提示、宽高控制及边框设置等,详细内容请阅读本文,希望能对你有所帮助... 目录img 标签src 属性alt 属性title 属性width/h

SpringBoot连接Redis集群教程

《SpringBoot连接Redis集群教程》:本文主要介绍SpringBoot连接Redis集群教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 依赖2. 修改配置文件3. 创建RedisClusterConfig4. 测试总结1. 依赖 <de

CSS3打造的现代交互式登录界面详细实现过程

《CSS3打造的现代交互式登录界面详细实现过程》本文介绍CSS3和jQuery在登录界面设计中的应用,涵盖动画、选择器、自定义字体及盒模型技术,提升界面美观与交互性,同时优化性能和可访问性,感兴趣的朋... 目录1. css3用户登录界面设计概述1.1 用户界面设计的重要性1.2 CSS3的新特性与优势1.

CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比

《CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比》CSS中的position属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布... css 中的 position 属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布局和层叠关

在Windows上使用qemu安装ubuntu24.04服务器的详细指南

《在Windows上使用qemu安装ubuntu24.04服务器的详细指南》本文介绍了在Windows上使用QEMU安装Ubuntu24.04的全流程:安装QEMU、准备ISO镜像、创建虚拟磁盘、配置... 目录1. 安装QEMU环境2. 准备Ubuntu 24.04镜像3. 启动QEMU安装Ubuntu4