STM32F407之移植LVGL(8.4.0)

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运行结果如下:

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

gma 2 教程(三)坐标参考系统:4.内置单位和子午线

安装 gma:pip install gma 内置单位 gma内置单位主要包括地理坐标系的角度单位和投影坐标系的线性单位两大类。 角度单位 内置常用的角度单位(在crs.AngularUnits下)名称及值见下表: 内置角度单位中文名值(弧度&…

C盘臃肿怎么办?用这招给C盘彻底瘦身!C盘专清!

随着大家使用电脑的时间越来越长,电脑积累的垃圾就越来越多,特别是作为C盘的核心部位。C盘承载了整个系统运行的框架,各种软件运行的临时数据存储等作用,慢慢的就变得臃肿起来了。 当C盘被垃圾堆得越来越多的时候,我们…

NPDP含金量、考试内容、报考要求、适合人群?

01.NPDP核心价值解读 NPDP认证的核心价值在于整合产品开发管理的理论与实践,包含新产品开发策略、研发流程管理、市场研究、销规划、团队管理、项目管理等等,理论体系和知识内容穿插在产品发展的全过程。 对于职场打工人来说,拥有NPDP证书证…

2024年通信安全员ABC证证考试题库及通信安全员ABC证试题解析

题库来源:安全生产模拟考试一点通公众号小程序 2024年通信安全员ABC证证考试题库及通信安全员ABC证试题解析是安全生产模拟考试一点通结合(安监局)特种作业人员操作证考试大纲和(质检局)特种设备作业人员上岗证考试大…

阿里云PAI大模型评测最佳实践

作者:施晨、之用、南茵、求伯、一耘、临在 背景信息 内容简介 在大模型时代,随着模型效果的显著提升,模型评测的重要性日益凸显。科学、高效的模型评测,不仅能帮助开发者有效地衡量和对比不同模型的性能,更能指导他…

shell脚本监控docker容器和supervisor 运行情况

1.ASR服务 需求: 在ASR服务器中 docker 以下操作中 忽略容器名字叫 nls-cloud-mongodb 的容器 在ASR服务器中 docker ps 查看正在运行的容器 docker stats -a --no-stream 可以监控容器所占资源 确认是否有pid且不等于0 docker inspect -f “{{.RestartCount}}” 容器名称 可…

Apple Watch开发入门知识,还是很有必要的

随着现在 Apple 生态圈的发展,越来越多的 App 会把自己的简化版从 iOS 迁移至 WatchOS(支付宝、微信、手Q、头条、QQ音乐、网易云音乐等等,都有Watch版App)。官方开发文档:Setting up a watchOS project | Apple Devel…

专业和学校到底怎么选,兴趣和知名度到底哪个重要?

前言 2024高考已经落下帷幕,再过不久就到了激动人心的查分和填报志愿的时刻,在那天到来,小伙伴们就要根据自己的分数选取院校和专业,接下来我就以参加22年(破防年)河南高考的大二生来讲述一下我自己对于如何选取院校和专业的看法以…

人生的乐趣,在于对真知的追求

子曰:朝闻道,夕死可矣! 孔子说:早上听到关于世界的真理,哪怕晚上就die了都可以。 这句话很有力量而经常被人引用,表达出我们如何看待沉重的肉身和精神世界。 我们的生活目的:道。 —— 要了解…

六西格玛培训新选择,老字号品质有保障!

在追求企业卓越与完美的道路上,六西格玛管理无疑是一个被广泛认可与采纳的方法论。六西格玛不仅仅是一种管理策略,更是一种文化和哲学,它强调通过数据驱动和持续改进来减少流程中的缺陷,提升客户满意度,并最终实现企业…

爬虫学习。。。。

爬虫的概念: 爬虫是一种自动化信息采集程序或脚本,用于从互联网上抓取信息。 它通过模拟浏览器请求站点的行为,获取资源后分析并提取有用数据,这些数据可以是HTML代码、JSON数据或二进制数据(如图片、视频&#xff09…

ffmpeg封装和解封装介绍-(8)解封装和封装重构

头文件&#xff1a; xformat.h #pragma once/// 封装和解封装基类#include <mutex> struct AVFormatContext; struct AVCodecParameters; struct AVPacket; struct XRational {int num; ///< Numeratorint den; ///< Denominator }; class XFormat { public:/// &…

AI绘画Stable Diffusion 全屋室内设计大模型,给我惊呆了!

大家好&#xff0c;我是设计师阿威 今天让我们一起进入到AI在室内设计方面的创作&#xff0c;同时我也向大家推荐一款来自老陈的室内设计大模型——室内设计全屋大模型。该模型在衣帽间、新中式客厅卧室、轻奢客厅卧室、儿童房间、厨房、浴室等室内效果图方面有着不错的效果。 …

数组和文本三剑客

数组&#xff1a; 数组的定义&#xff1a;在集合当中指定多个元素&#xff0c;元素的类型&#xff1a;整数&#xff0c;字符串&#xff0c;浮点数。 数组的作用&#xff1a;可以一次性的定义多个元素&#xff0c;可以为变量赋值提供便利。 数组的定义方法&#xff1a; 数组…

CarService的构成和初始化分析

以下分析&#xff0c;基于安卓13的AAOS。 代码构成 packages/services/Car CarService相关代码&#xff0c;主要是在这个目录下 frameworks/opt/car/services 主要是carservice启动相关。 其它目录&#xff1a;audio_policy_configuration.xml和car_audio_configuration.xm…

国际期货行情相关术语

1&#xff09;合约&#xff1a;期货行情表提供了期货交易的相关信息 &#xff0c;行情表中每一个期货合约都有合约代码&#xff08;由期货合约交易代码和合约到期月份组成&#xff09;来标识。 &#xff08;2&#xff09;开盘价&#xff1a;当日某一期货合约交易开始前五分钟集…

聊聊分布式集群的基本概念

在当前主流的分布式架构中,各种各样的集群技术几乎成了任何想要提升系统稳定性和处理能力的团队的必备技能。虽然各种中间件和系统都有让人看似眼花缭乱的集群实现方案,但其背后仍然逃不过一些核心的技术概念,我会结合几个我比较熟悉的中间件,简单聊一下我对集群的理解: …

ARM架构简明教程

目录 一、ARM架构 1、RISC指令集 2、ARM架构数据类型的约定 2.1 ARM-v7架构数据类型的约定 2.2 ARM-v8架构数据类型的约定 3、CPU内部寄存器 4、特殊寄存器 4.1 SP寄存器 4.2 LR寄存器 4.3 PC寄存器 二、汇编 1、汇编指令&#xff08;常用&#xff09; 2、C函数的…

nextjs(持续学习中)

return ( <p className{${lusitana.className} text-xl text-gray-800 md:text-3xl md:leading-normal}> Welcome to Acme. This is the example for the{’ } Next.js Learn Course , brought to you by Vercel. ); } 在顶级 /public 文件夹下提供静态资产 **默认 /…

通过视频网站传播的RecordBreaker窃密木马分析

1 攻击活动概览 近期&#xff0c;安天CERT监测到通过视频网站进行传播的攻击活动。攻击者窃取订阅者数量超过10万的视频创作者账号&#xff0c;发布与破解版热门软件相关的演示视频&#xff0c;诱导受害者下载RecordBreaker窃密木马。 RecordBreaker窃密木马是Raccoon…