LVGL配置FatFs文件系统,实现对STM32的SD卡数据读写

2024-08-25 03:44

本文主要是介绍LVGL配置FatFs文件系统,实现对STM32的SD卡数据读写,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

0、前言

        在前面两篇博客文章中,已经介绍了如何将LVGL移植到STM32平台和如何将FatFs R0.15文件系统移植到STM32上,因此本文对这些内容将不再重复讲解。如需下载对应的工程文件,请进入对应的文章,即可找到对应的资源下载包。

        LVGL移植到STM32 MCU平台详细经验笔记教程_lvgl移植stm32-CSDN博客

        FatFs R0.15文件系统移植到MCU平台详细笔记经验教程_fatfs移植教程-CSDN博客

        基于上面这两部分的内容基础上,本文开始将LVGL和FatFs联系起来实现LVGL的文件系统模块对SD卡中文件进行读写操作,在下一篇与LVGL相关的文章将介绍对各类图片文件的显示等操作。

1、LVGL文件系统

        LVGL 有一个文件系统模块,可为各种类型的文件系统驱动程序提供一个通用的抽象层接口

        LVGL 内置的文件系统模块支持以下文件系统:

①、FATFS (常用于单片机这类嵌入式设备)

②、STDIO (Linux 和 Windows 都可以使用的 C 标准函数接口,比如: fopen, fread)

③、POSIX (Linux 和 Windows 都可以使用的 POSIX 函数接口,比如:open, read)

④、WIN32 (Windows 使用 Win32 API 函数接口比如:CreateFileA, ReadFile)

⑤、MEMFS (从内存缓冲区读取文件)

⑥、LITTLEFS (一种为微控制器设计的小型故障安全文件系统)

⑦、Arduino ESP LITTLEFS(专为 Arduino ESP 设计的小型故障安全文件系统)

⑧、Arduino SD (允许读取和写入 SD 卡)

        但LVGL只是提供了上层使用的抽象接口桥梁,对于使用不同的文件系统,还是需要提供驱动程序和库。如如果需要开启不同的文件系统,需要在lv_conf.h将对应的宏定义打开并适当修改。

2、LVGL配置流程

(1)、lv_conf.h

        lv_conf.h 文件是 LVGL的系统配置文件,可以根据项目的具体需求对 LVGL 库进行定制,以优化性能、内存使用和功能集。如果要在LVGL中使用文件系统,也需要对lv_conf.h文件进行配置。

        打开lv_conf.h文件,找到 LV_USE_FS_FATFS 这个宏,并将这个宏的值修改为 1 ,此时LVGL的文件系统被开启了。再将SD卡的盘符,也就是 LV_FS_FATFS_LETTER 的值修改为 ‘0’

        LV_FS_FATFS_CACHE_SIZE 表示的是设置读缓冲区的大小,暂时先不用修改。

        注意: LV_FS_FATFS_LETTER 不能为 ‘0:’,或、‘\0’

/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/
#define LV_USE_FS_FATFS 1
#if LV_USE_FS_FATFS#define LV_FS_FATFS_LETTER '0'     /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/#define LV_FS_FATFS_CACHE_SIZE 0    /*>0 to cache this number of bytes in lv_fs_read()*/
#endif

(2)、lv_fs_fatfs.c

①、文件功能说明

        在LVGL的lv_fs_fatfs.c文件中,主要是基于FatFs提供的接口基础上,根据LVGL对文件的需要,重新实现了LVGL的文件系统驱动程序接口

        lv_fs_fatfs.c文件中提供的是LVGL文件系统与FatFs直接相关的适配接口,而FatFs文件系统则是与SD卡硬件相关的底层接口。

②、fs_init

        fs_init是一个空的函数,需要开发者自己实现的API的内容,在lv_fs_fatfs_init函数中被调用,主要实现的作用是初始化FatFs文件系统和SD卡存储设备及SD卡挂载。在本次移植中,选择了将FatFs文件系统初始化和SD卡初始化及SD卡挂载工作放到主函数中进行,博客读者们可以根据自己的习惯选择是否进行这个函数的使用操作。

③、lv_fs_fatfs_init

        lv_fs_fatfs_init函数的作用是初始化文件系统,并注册驱动回调函数。该函数在lv_extra_init中被调用,并且调用的条件是 LV_USE_FS_FATFS != '\0' ,因此需要开启文件系统的使用,lv_conf.h文件中必须对LV_USE_FS_FATFS的参数值进行修改。而lv_extra_init又被lv_init函数调用,因此,对LVGL的文件系统进行修改适配完后,不需要再次去手动调用lv_fs_fatfs_init初始化操作。

(3)、lv_fs.c

①、文件全局说明

        如果说FatFs提供的是文件系统的底层接口,那么lv_fs_fatfs_init提供的就是LVGL文件系统与FatFs衔接的中间件驱动程序接口,而lv_fs则是真正的LVGL文件系统的上层抽象接口

        lv_fs是LVGL中与文件系统相关的源代码文件,它包含了实现 LVGL 文件系统抽象层的函数和数据结构。这些函数和数据结构允许 LVGL 与不同的文件系统驱动程序进行交互,例如FatFs、STDIO、POSIX及WIN32等。这个文件的存在,简化了开发者在LVGL中对文件的操作,统一了不同文件系统在LVGL中的使用,提高了程序代码的跨平台,可移植性。

        在lv_fs.c这个文件中,提供了LVGL的:

1、文件系统驱动程序的注册和初始化函数。

2、文件和目录操作的函数,如打开、关闭、读取、写入、删除等。

3、文件系统相关的错误处理和状态检查。

②、lv_fs_open

        lv_fs_open是LVGL中用于打开文件的接口。它是 LVGL 文件系统抽象层的一部分,允许 LVGL 与不同的文件系统驱动程序进行交互。

/*** 打开文件* @param file_p    指向要打开的文件的指针* @param path      要打开的文件的路径 (e.g. S:/folder/file.txt)* @param mode      要打开文件的模式读: FS_MODE_RD, 写: FS_MODE_WR, 读写: FS_MODE_RD | FS_MODE_WR* @return          打开成功:LV_FS_RES_OK,失败返回其它lv_fs_res_t的错误码 */
lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode);//API使用示范
lv_fs_file_t f;
lv_fs_res_t res;
res = lv_fs_open(&f, "0:/folder/text.txt", LV_FS_MODE_WR|LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) 
{printf("lv_fs_open failed!\r\n");while(1);
}
printf("lv_fs_open success!\r\n");

        注意:打开文件时,必须要输入文件所在的盘符和路径,比如,文件存储在MCU的SD卡的folder路径下,文件名为test.txt。此时,打开的路径为 0:/folder/text.txt

③、lv_fs_close

        lv_fs_close用于关闭之前使用 lv_fs_open 函数打开的文件。

/*** 关闭已经打开的文件* @param file_p    指向要关闭的文件的指针* @return          打开成功:LV_FS_RES_OK,失败返回其它lv_fs_res_t的错误码 */
lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p);//API使用示范
lv_fs_file_t f;
lv_fs_res_t res;//假设已经打开了文件...res = lv_fs_close(&f);
if (res != LV_FS_RES_OK) 
{printf("lv_fs_close failed!\r\n");while(1);
}
④、lv_fs_write

        lv_fs_write用于将数据写入到文件中。

/*** 数据写入到文件中* @param file_p    指向要写入的文件变量指针* @param buf       指向包含要写入文件的字节数据的缓冲区的指针* @param btw       要写入的字节数(Bytes To Write)* @param bw        一个指向无符号32位整数的指针,用于存储实际写入的字节数(Bytes Written),可填入NULL* @return          打开成功:LV_FS_RES_OK,失败返回其它lv_fs_res_t的错误码 */
lv_fs_res_t lv_fs_write(lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw);//API使用示范
uint8_t write_buf[64] = "This is a lvgl fatfs test program!";
uint32_t write_pos = 0;
res = lv_fs_write(&f, write_buf, strlen((char *)write_buf), &write_pos);
if (res != LV_FS_RES_OK)
{printf("lv_fs_write failed!\r\n");while(1);
}
⑤、lv_fs_read

        lv_fs_read用于从文件中读取数据。

/*** 从文件中读取数据* @param file_p    指向要写入的文件变量指针* @param buf       指向一个缓冲区的指针,用于存储从文件中读取的字节数据* @param btr       要读取的字节数(Bytes To Read)* @param br        一个指向无符号32位整数的指针,用于存储实际读取的字节数(Bytes Read),可填入NULL* @return          打开成功:LV_FS_RES_OK,失败返回其它lv_fs_res_t的错误码 */
lv_fs_res_t lv_fs_read(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br);//API使用示范
uint32_t read_num;
uint8_t read_buf[64] = {0};
res = lv_fs_read(&f, read_buf, 64, &read_num);
if(res != LV_FS_RES_OK) 
{printf("lv_fs_read failed!\r\n");while(1);
}

3、LVGL文件读写

(1)、写文件

void LVGL_FatFs_Demo(void)
{while(SD_Init()){LED_RED_ON;delay_ms(500);LED_RED_OFF;delay_ms(500);}res_sd = f_mount(&fs,"0:", 1);//!!!非常重要,一定要挂载if (res_sd != FR_OK) {printf("SD Mount FatFs Failed! %d\r\n",res_sd);while (1);} else {printf("SD Mount FatFs Success!\r\n");}lv_init();          // lvgl系统初始化lv_port_disp_init();  // lvgl显示接口初始化,放在lv_init()的后面lv_port_indev_init(); // lvgl输入接口初始化,放在lv_init()的后面lv_fs_file_t f;lv_fs_res_t res;res = lv_fs_open(&f, "0:LVGL_FatFs.txt", LV_FS_MODE_WR|LV_FS_MODE_RD);if(res != LV_FS_RES_OK) {printf("lv_fs_open failed!\r\n");while(1);}printf("lv_fs_open success!\r\n");printf("lvgl write file test...\r\n");uint8_t write_buf[64] = "This is a lvgl fatfs test program!";uint32_t write_pos = 0;res = lv_fs_write(&f, write_buf, strlen((char *)write_buf), &write_pos);if (res != LV_FS_RES_OK){printf("lv_fs_write failed!\r\n");while(1);}printf("lv_fs_write success!\r\n");lv_fs_close(&f);
}

        LVGL文件系统写数据测试结果,将SD卡插入到PC中,可以看到创建的文件,及写入的数据。

(2)、读文件

void LVGL_FatFs_Demo(void)
{while(SD_Init()){LED_RED_ON;delay_ms(500);LED_RED_OFF;delay_ms(500);}res_sd = f_mount(&fs,"0:", 1);if (res_sd != FR_OK) {printf("SD Mount FatFs Failed! %d\r\n",res_sd);while (1);} else {printf("SD Mount FatFs Success!\r\n");}lv_init();          // lvgl系统初始化lv_port_disp_init();  // lvgl显示接口初始化,放在lv_init()的后面lv_port_indev_init(); // lvgl输入接口初始化,放在lv_init()的后面lv_fs_file_t f;lv_fs_res_t res;res = lv_fs_open(&f, "0:LVGL_FatFs.txt", LV_FS_MODE_WR|LV_FS_MODE_RD);if(res != LV_FS_RES_OK) {printf("lv_fs_open failed!\r\n");while(1);}printf("lv_fs_open success!\r\n");printf("lvgl read file test...\r\n");uint32_t read_num;uint8_t read_buf[64] = {0};res = lv_fs_read(&f, read_buf, 64, &read_num);if(res != LV_FS_RES_OK) {printf("lv_fs_read failed!\r\n");while(1);}printf("read data:");for(int i=0; i<64; i++){printf("%c", read_buf[i]);}printf("\r\n");lv_fs_close(&f);
}

        通过串口输出的信息可以看到,文件中的内容被LVGL成功读取出来了。

这篇关于LVGL配置FatFs文件系统,实现对STM32的SD卡数据读写的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2