STM32F407之移植LVGL(8.4.0)

news2025/1/21 6:28:34

STM32F407之移植LVGL(8.4.0)

目录

概述

1 系统软硬件

1.1 软件版本信息

1.2 ST7796-LCD

1.3 MCU IO与LCD PIN对应关系

1.4 MCU IO与Touch PIN对应关系

2 认识LVGL

2.1 LVGL官网

2.2 下载V8.4.0

3 移植LVGL

3.1 硬件驱动实现

3.2 添加LVGL库文件

3.3 移植和硬件相关的代码

3.3.1 驱动接口相关文件介绍

 3.3.2 重定义接口函数

3.4 配置.h文件

3.5 Keil中配置源代码路径

3.6 编译配置 

4 lvgl的接口调用

4.1 主函数中调用LVGL接口

4.2  了解vgl-simulator

5 测试


源代码下载地址:

STM32F407之移植LVGL(8.4.0stm32-f407-lcd-lvgl-proj)资源-CSDN文库

概述

本文主要介绍在STM32F407移植lvgl-8.4.0的详细步骤,包括加载文件的方法,Keil中加载文件目录和路径,修改和LCD驱动层相关的接口,keil中配置编译参数,笔者使用NXP GUI builder设计了一个简单的案例,验证移植的代码是否可以正常运行。

1 系统软硬件

1.1 软件版本信息

软硬件信息版本信息
MCU类型STM32F407IGTx
KeilMDK ARM 5.38
调试工具:ST-Link V2

1.2 ST7796-LCD

LCD的PIN引脚功能介绍

序号模块引脚引脚说明
1VCC屏电源正
2GND屏电源地
3LCD_CS液晶屏片选控制信号,低电平有效
4LCD_RST液晶屏复位控制信号,低电平复位
5LCD_RS液晶屏命令/数据选择控制信号

高电平:数据,低电平:命令

6SDI(MOSI)SPI总线写数据信号(SD卡和液晶屏共用)
7SCKSPI总线时钟信号(SD卡和液晶屏共用)
8LED液晶屏背光控制信号(如需要控制,请接引脚,如不需要控制,可以不接)
9SDO(MISO)SPI总线读数据信号(SD卡和液晶屏共用)
10CTP_SCL电容触摸屏IIC总线时钟信号(无触摸屏的模块不需连接)
11CTP_RST电容触摸屏复位控制信号,低电平复位(无触摸屏的模块不需连接)
12CTP_SDA电容触摸屏IIC总线数据信号(无触摸屏的模块不需连接)
13CTP_INT电容触摸屏IIC总线触摸中断信号,产生触摸时,输入低电平到主控(无触摸屏的模块不需连接)
14SD_CSSD卡片选控制信号,低电平有效(不使用SD卡功能,可不接)

实体LCD Port对应关系如下图所示

1.3 MCU IO与LCD PIN对应关系

STM32 PIN引脚LCD PIN引脚
PB5-MOSIMOSI
PB4-MISOMISO
PB3-SCKSCK
PB6CS
PB9RST
PB8RS

1.4 MCU IO与Touch PIN对应关系

STM32 PIN引脚touch PIN引脚
PH4I2C-SCK
PH5I2C-SDA
PH10INIT
PH9RST

2 认识LVGL

2.1 LVGL官网

LVGL是最流行的免费和开源嵌入式图形库,可为任何MCU, MPU和显示类型创建漂亮的UI。基于这个特点,其可以在一般的MCU上都能运行的,本文选取芯片N32G457VEL7作为主控MCU,实现该UI库的移植。

官方网址:LVGL — Light and Versatile Embedded Graphics Library

https://lvgl.io/

登录网址后,可以看见如下页面,目前最新版本已经升级到 LVGL v8.4 and v9.1 are released!:

2.2 下载V8.4.0

软件下载链接如下:

https://github.com/lvgl/lvgl/releases/tag/v8.4.0

​ 下载完成代码后,解压代码,其文件结构如下:

文件夹examples:  应用实例代码,目录

文件夹src:    lvgl的源代码目录

头文件 lvgl.h: lvgl源代码引用文件

头文件lv_conf_template.h:  lvgl编译项目配置文件

3 移植LVGL

3.1 硬件驱动实现

在移植LVGL库之前,必须保证LCD驱动已经触摸屏的相关驱动程序已经实现,其实现案例,参考笔者文章:

FT6336触摸屏芯片驱动程序的实现(基于stm32f4)_ft6336跳屏-CSDN博客

基于STM32移植lvgl(V8.2)(SPI接口的LCD)_lvgl lcd-CSDN博客

3.2 添加LVGL库文件

1)lvgl-8.4.0\src\core

添加该目录下的所有.c文件到工程目录中,该目录下的文件包括:

2) lvgl-8.4.0\src\draw

该目录下的文件包括两部分,文件夹中的和绘图相关,文件一级目录的通用.c文件

2.1) 添加一级目录下的文件

添加如下文件到项目中

2.2)二级目录下的文件

这两个文件夹下的.c文件必须加载到项目中

 3)lvgl-8.4.0\src\extra

添加如下一级目录和二级目录下所有的.c文件至项目

4) lvgl-8.4.0\src\font

添加如下所有.c文件至项目

 5)lvgl-8.4.0\src\hal

添加如下所有.c文件至项目

6)lvgl-8.4.0\src\misc 

添加如下所有.c文件至项目

7)lvgl-8.4.0\src\widgets 

添加如下所有.c文件至项目

3.3 移植和硬件相关的代码

3.3.1 驱动接口相关文件介绍

\lvgl-8.4.0\examples\porting目录有3个.c文件

1)LCD显示相关接口函数库: lv_port_disp_template.c    

2)   触摸屏/按键相关函数库:   lv_port_indev_template.c

3)文件操作行管函数库:        lv_port_fs_template.c

 3.3.2 重定义接口函数

1)重写lv_port_disp_template.c  

将 lv_port_disp_template.c  添加到项目,重写干文件中的代码,具体如下:

/**
 * @file lv_port_disp_templ.c
 *
 */
 /* Includes ------------------------------------------------------------------*/
#include "lv_port_disp_template.h"
#include "lvgl.h"
#include "lcd_drv.h"

/* Private includes ----------------------------------------------------------*/
#define MY_DISP_HOR_RES             LCD_H
#define MY_DISP_VER_RES             LCD_W 

/* Private function prototypes -----------------------------------------------*/
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);


/* Private user code ---------------------------------------------------------*/
static void lcd_draw_fast_rgb_color(int16_t sx, int16_t sy,
                                    int16_t ex, int16_t ey, 
                                    uint16_t *color)
{
    LCD_drawfast_RGB_color(sx, sy, ex, ey, color);
}

static void disp_init(void)
{
    /*You code here*/
    LCD_Init();

    //LCD_direction(2);
    LCD_direction(1);
    LCD_Clear(WHITE);
}

void lv_port_disp_init(void)
{
    static lv_disp_drv_t disp_drv; 
    static lv_disp_draw_buf_t draw_buf_dsc_1;
    static lv_color_t buf_1[MY_DISP_VER_RES * 8]; 

    disp_init();
    
    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_VER_RES * 8);
 
    lv_disp_drv_init(&disp_drv);

    disp_drv.hor_res = lcddev.width;
    disp_drv.ver_res = lcddev.height;

    disp_drv.flush_cb = disp_flush;

    disp_drv.draw_buf = &draw_buf_dsc_1;

    lv_disp_drv_register(&disp_drv);
}


static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    lcd_draw_fast_rgb_color(area->x1, area->y1, area->x2, area->y2, (uint16_t *)color_p);
    lv_disp_flush_ready(disp_drv);
}

/* END of this file */




2)重写lv_port_indev_template.c  

将 lv_port_indev_template.c  添加到项目,重写干文件中的代码,具体如下:

/**
 * @file lv_port_indev_templ.c
 *
 */

 /*Copy this file as "lv_port_indev.c" and set this value to "1" to enable content*/
 
/*********************
 *      INCLUDES
 *********************/
#include "lv_port_indev_template.h"
#include "lvgl.h"
#include "usr_touch.h"


/* 触摸屏 */
static void touchpad_init(void);
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y);


lv_indev_t * indev_touchpad;      // 触摸屏
stru_pos st_Pos;

/**
 * @brief       初始化并注册输入设备
 * @param       无
 * @retval      无
 */
void lv_port_indev_init(void)
{
    static lv_indev_drv_t indev_drv;

    /*------------------
    * 触摸屏
    * -----------------*/

    /* 初始化触摸屏(如果有) */
    touchpad_init();

    /* 注册触摸屏输入设备 */
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touchpad_read;
    indev_touchpad = lv_indev_drv_register(&indev_drv);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/*------------------
 * 触摸屏
 * -----------------*/

/**
 * @brief       初始化触摸屏
 * @param       无
 * @retval      无
 */
static void touchpad_init(void)
{
    usr_touchInit();
}

/**
 * @brief       图形库的触摸屏读取回调函数
 * @param       indev_drv   : 触摸屏设备
 *   @arg       data        : 输入设备数据结构体
 * @retval      无
 */
static 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);
        data->state = LV_INDEV_STATE_PR;
    } 
    else
    {
        data->state = LV_INDEV_STATE_REL;
    }

    /* 设置最后按下的坐标 */
    data->point.x = last_x;
    data->point.y = last_y;
}

/**
 * @brief       获取触摸屏设备的状态
 * @param       无
 * @retval      返回触摸屏设备是否被按下
 */
static bool touchpad_is_pressed(void)
{
    usr_ScanTouchProcess( &st_Pos );
    if( st_Pos.status_bit.tpDown ){
        st_Pos.status_bit.tpDown = 0;
        return true;
    }

    return false;
}

/**
 * @brief       在触摸屏被按下的时候读取 x、y 坐标
 * @param       x   : x坐标的指针
 *   @arg       y   : y坐标的指针
 * @retval      无
 */
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    /*Your code comes here*/
    (*x) = st_Pos.xpox[0];
    (*y) = st_Pos.ypox[0];
}

/* End of this file */

3.4 配置.h文件

在lvgl-8.4.0根目录下有两个.h文件,其分别为:

头文件 lvgl.h: lvgl源代码引用文件

头文件lv_conf_template.h:  lvgl编译项目配置文件

 修改lv_conf_template.h    -----> lv_conf.h

 实际项目中的文件名称如下:

3.5 Keil中配置源代码路径

在keil中将lvgl源代码的路径配置到项目中,方便编译。其具体配置如下:

3.6 编译配置 

lvgl中有许多浮点型的运算,使用Keil编译时会产生许多warning 信息,为了避免在编译log中看见这些warning message,需要在编译项中填写如下信息:

--diag_suppress=68 --diag_suppress=111 --diag_suppress=188 --diag_suppress=223 --diag_suppress=546  --diag_suppress=1295

4 lvgl的接口调用

4.1 主函数中调用LVGL接口

笔者使用FreeRTOS管理MCU的资源,在Task中调用LVGL接口的方法如下:

代码30行: lvgl库函数接口

代码31行: lvgl 显示屏接口

代码32行: 触摸功能接口

 代码125行: 初始化lvgl接口

 代码127行: 初始化lvgl和LCD之间的显示器接口

 代码129行: 初始化lvgl和触摸功能接口

 代码131行: 调用lvgl UI测试程序

while(1)循环中的函数

 代码136行: lvgl tick 函数

 代码138行: lvgl task函数,触发屏幕刷新和读取触摸功能数据

4.2  了解vgl-simulator

使用NXP公司提供的GUI builder 工具可以设计基于LVGL库的UI,关于该软件的使用方法请参考原文:

基于GUI Guider(V1.7.2)搭建lvgl UI设计和仿真环境-CSDN博客

这里主要介使用GUI builder 生成的lvgl-simulator Projrcy是如何代用lvgl接口的

  代码73行: 初始化lvgl

  代码86行: 初始化用户UI和lvgl之间的接口

  代码87行:加载用户UI

  代码102行: lvgl 刷新UI和数据,处理和按键相关的操作函数

  代码167行: lvgl 刷新UI和数据的tick函数,这里可以设置刷新频率

5 测试

编译代码,由于lvgl支持图片和多种字体功能,如果设计比较复杂的UI,其代码量一般比较大的。建议使用flash和RAM较大的MCU。

下载到板卡中,lvgl运行结果如下:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1837766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初识es(elasticsearch)

初识elasticsearch 什么是elasticsearch?: 一个开源的分部署搜索引擎、可以用来实现搜索、日志统计、分析、系统监控等功能。 什么是文档和词条? 每一条数据就是一个文档对文档中的内容进行分词,得到的词语就是词条 什么是正向…

【设计文档】软件详细设计说明书案例文档(word直接套用)

一、 关于本文档 (一) 编写目的 (二) 预期读者 二、 项目概要 (一) 建设背景 (二) 建设目标 (三) 建设内容 三、 总体设计 (一&#xff0…

MySQL中的客户端选项(四)

用于连接到服务器的传输协议。当其他连接参数通常导致使用的协议不是您想要的协议时,它很有用。 不缓存每个查询的结果,而是实时地打印每一行,如果输出被挂起,这可能会减慢服务器的速度。有了这个选项,mysql就不会使用…

QT基础 - 窗口弹窗

目录 零. 窗口简介 一. 普通窗口 二. 无边框窗口 三. 顶层窗口 四. 模态对话框 五. 非模态对话框 六. 消息对话框 七. 文件对话框 八. 颜色对话框 九. 进度对话框 十. 总结 零. 窗口简介 在 Qt中,普通窗口是指程序的整体界面,可以包含标题栏、…

GIS设计与开发课程设计(三)

环境:Windows10专业版 ArcGIS10.2 ArcEngine10.2 Visual Studio 2019 因每个人电脑版本和软件版本不同,运行的结果可能不同 系列文章: GIS设计与开发课程设计(一) GIS设计与开发课程设计(二)…

SpringMVC系列三: Postman(接口测试工具)

接口测试工具 💞Postman(接口测试工具)Postman介绍Postman是什么Postman相关资源Postman安装Postman快速入门Postman完成Controller层测试其它说明 💞课后作业 上一讲, 我们学习的是SpringMVC系列二: 请求方式介绍 现在打开springmvc项目 &#x1f49e…

公司面试题总结(六)

31.说一说 webpack 的构建流程是什么? ⚫ 初始化流程: ◼ 从配置文件和 Shell 语句中读取与合并参数 ◼ 初始化需要使用的插件和配置插件等执行环境所需要的参数 ⚫ 编译构建流程: ◼ 从 Entry 发出,针对每个 Module 串行…

本地部署Ollama+qwen本地大语言模型Web交互界面

什么是 Ollama WebUI? Ollama WebUI 已经更名为 Open WebUI. Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 WebUI,旨在完全离线操作。它支持各种 LLM 运行程序,包括 Ollama 和 OpenAI 兼容的 API。 Ollama WebUI 是一个革命性的 L…

酷开会员 | 酷开系统将艺术、回忆与浪漫融入生活

随着审美观念的改变以及技术的提升,消费者对家用电视的需求已不局限于单纯的功能性,外观设计带来的美感与视觉效果也愈发成为消费者关注的焦点。在画质和功能逐步完善的当下,电视中的壁纸模式,则能让其更好地融入家居环境&#xf…

深度学习入门5——为什么神经网络可以学习?

在理解神经网络的可学习性之前,需要先从数学中的导数、数值微分、偏导数、梯度等概念入手,从而理解为什么神经网络具备学习能力。 1.数值微分的定义 先从导数出发理解什么是梯度。某一点的导数直观理解就是在该点的切线的斜率。在数学中导数表示某个瞬…

AI智能盒子助力打造垃圾发电AI应用标杆!

垃圾焚烧发电作为一种新型的垃圾处理方式,能将其转化为电能,实现资源的再利用,成为实现节能环保的重要方式之一。为有效落实环境、安全、健康及社会责任管理体系,知名垃圾发电投资运营商光大环保能源致力于广泛利用科技&#xff0…

ubuntu永久换镜像源详细方法

1.查看ubuntu的版本,不同的版本对应的不同的镜像源(下面会讲到,先按步骤操作即可) cat /etc/issue 2.先备份一个,防止更改错误 cp /etc/apt/sources.list /etc/apt/sources.list.backup 3.备份好之后删除原有的sour…

Linux系统之mtr命令的基本使用

Linux系统之mtr命令的基本使用 一、mtr命令介绍二、mtr命令使用帮助2.1 mtr命令的帮助信息2.2 mtr帮助信息解释 三、安装mtr工具四、mtr命令的基本使用4.1 直接使用4.2 设定ping次数4.3 禁用DNS解析4.4 显示IP地址4.5 调整间隔 五、总结 一、mtr命令介绍 mtr命令是一个网络诊断…

Vulnhub——AI: WEB: 1

渗透复现 (1)目录扫描爆破出隐藏页面info.php和传参页面,泄露网站绝对路径并且存在SQL注入点 (2)已知网站绝对路径,存在SQL注入点,尝试OS-shell写入 (3)OS-shell写入后…

MySQL----redo log重做日志原理及流程

重做日志 redo log:重做日志,用于记录事务操作的变化,确保事务的持久性。redo log是在事务开始后就开始记录,不管事务是否提交都会记录下来,在异常发生时(如数据持久化过程中掉电),…

【AI学习】LLaMA 系列模型的进化(一)

一直对LLaMA 名下的各个模型关系搞不清楚,什么羊驼、考拉的,不知所以。幸好看到两篇综述,有个大致了解,以及SEBASTIAN RASCHKA对LLaMa 3的介绍。做一个记录。 一、文章《Large Language Models: A Survey》中对LLaMa的介绍 论文…

【博士每天一篇文献-算法】Memory aware synapses_ Learning what (not) to forget

阅读时间:2023-12-13 1 介绍 年份:2018 作者:Rahaf Aljundi,丰田汽车欧洲公司研究员;阿卜杜拉国王科技大学(KAUST)助理教授;Marcus Rohrbach德国达姆施塔特工业大学多模式可靠人工智能教授 会议: Proceedings of the European c…

【串口通信-USART】

串口通信 前言一、串行通信和并行通信二、波特率三、USRAT如何实现USART 四、通信的时候共地五、奇偶校验位总结 前言 大三上时候的笔记⇨32入门-串口通信-发送和接收数据🌟更加偏向32部分的吧。 大三上左右的时候写过串口通信的笔记,那时候虽然青涩啥也…

结硬寨:联想服务器的向前之路

曾国藩曾经将自己的战略思想,总结为“结硬寨,打呆仗”。 这种稳健的策略,往往在真实的产业发展中能收获奇效。我们喜欢听颠覆性的产业创新,却往往忽视稳扎稳打,把每一个优势聚集起来形成整体优势,可能才是市…

AI大模型的战场:通用大模型VS垂直大模型,谁会赢?

人不走空 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌赋:斯是陋室,惟吾德馨 目录 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌…