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

相关文章

[职场] 护理专业简历怎么写 #经验分享#微信

护理专业简历怎么写   很多想成为一名护理方面的从业者,但是又不知道应该怎么制作一份简历,现在这里分享了一份护理方面的简历模板供大家参考。   蓝山山   年龄:24   号码:12345678910   地址:上海市 邮箱:jianli@jianli.com   教育背景   时间:2011-09到2015-06   学校:蓝山大学   专业:护理学   学历:本科

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

AssetBundle学习笔记

AssetBundle是unity自定义的资源格式,通过调用引擎的资源打包接口对资源进行打包成.assetbundle格式的资源包。本文介绍了AssetBundle的生成,使用,加载,卸载以及Unity资源更新的一个基本步骤。 目录 1.定义: 2.AssetBundle的生成: 1)设置AssetBundle包的属性——通过编辑器界面 补充:分组策略 2)调用引擎接口API

VMware9.0详细安装

双击VMware-workstation-full-9.0.0-812388.exe文件: 直接点Next; 这里,我选择了Typical(标准安装)。 因为服务器上只要C盘,所以我选择安装在C盘下的vmware文件夹下面,然后点击Next; 这里我把√取消了,每次启动不检查更新。然后Next; 点击Next; 创建快捷方式等,点击Next; 继续Cont

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据6.FALSH编程时间,擦写次数7.I/O高低电平电压表格8.外设接口

《offer来了》第二章学习笔记

1.集合 Java四种集合:List、Queue、Set和Map 1.1.List:可重复 有序的Collection ArrayList: 基于数组实现,增删慢,查询快,线程不安全 Vector: 基于数组实现,增删慢,查询快,线程安全 LinkedList: 基于双向链实现,增删快,查询慢,线程不安全 1.2.Queue:队列 ArrayBlockingQueue:

[职场] 公务员的利弊分析 #知识分享#经验分享#其他

公务员的利弊分析     公务员作为一种稳定的职业选择,一直备受人们的关注。然而,就像任何其他职业一样,公务员职位也有其利与弊。本文将对公务员的利弊进行分析,帮助读者更好地了解这一职业的特点。 利: 1. 稳定的职业:公务员职位通常具有较高的稳定性,一旦进入公务员队伍,往往可以享受到稳定的工作环境和薪资待遇。这对于那些追求稳定的人来说,是一个很大的优势。 2. 薪资福利优厚:公务员的薪资和

(超详细)YOLOV7改进-Soft-NMS(支持多种IoU变种选择)

1.在until/general.py文件最后加上下面代码 2.在general.py里面找到这代码,修改这两个地方 3.之后直接运行即可

springboot家政服务管理平台 LW +PPT+源码+讲解

3系统的可行性研究及需求分析 3.1可行性研究 3.1.1技术可行性分析 经过大学四年的学习,已经掌握了JAVA、Mysql数据库等方面的编程技巧和方法,对于这些技术该有的软硬件配置也是齐全的,能够满足开发的需要。 本家政服务管理平台采用的是Mysql作为数据库,可以绝对地保证用户数据的安全;可以与Mysql数据库进行无缝连接。 所以,家政服务管理平台在技术上是可以实施的。 3.1

Java注解详细总结

什么是注解?         Java注解是代码中的特殊标记,比如@Override、@Test等,作用是:让其他程序根据注解信息决定怎么执行该程序。         注解不光可以用在方法上,还可以用在类上、变量上、构造器上等位置。 自定义注解  现在我们自定义一个MyTest注解 public @interface MyTest{String aaa();boolean bbb()