Fatfs

STM32进阶笔记——FATFS文件系统(上)_stm32 fatfs-CSDN博客

STM32进阶笔记——FATFS文件系统(下)_stm32 文件系统怎样获取文件大小-CSDN博客

STM32——FATFS文件基础知识_stm32 fatfs-CSDN博客

021 - STM32学习笔记 - Fatfs文件系统(三) - 细化与总结_fatfs遍历文件-CSDN博客

希望这几篇文章不会莫名消失吧。

Fatfs


在嵌入式系统中,对于数据的存储和管理至关重要。STMicroelectronics的STM32系列微控制器提供了丰富的外设和功能,使得与外部存储设备(如SD卡)进行交互变得更加简单高效。


了解FatFs文件系统


FatFs是一款用于嵌入式系统的开源文件系统库,支持FAT12、FAT16、FAT32格式的文件系统。它提供了一套简单易用的API,能够方便地在嵌入式系统中实现对SD卡等存储设备的文件操作。


FATFS文件系统特点

  • 1、Windows兼容的FAT文件系统(支持FAT12、FAT16和FAT32)
  • 2、与平台无关,移植简单。全C语言编写
  • 3、代码量少、效率高
  • 4、多种配置选项
  • 1)支持多卷(物理驱动器或分区,最多10卷)
  • 2)多个AHSI/OEM代码页包括DBCS
  • 3)支持长文件名、ANSI/OEM或Unicode
  • 4)支持RTOS
  • 5)支持多种扇区大小
  • 6)只读、最小化的API和I/O缓冲区等

FATFS模块的层次结构图

1、底层接口,包括存储媒介读或写接口(disk I/O)和供给文件创建修改时间的实时时钟,需要我们根据平台和存储介质编写移植代码。

2、中间层FATFS模块,实现了FAT文件读或写协议。FATFS模块提供的是ff.c和ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。

3、最顶层是应用层,使用者无需理会FATFS的内部结构和复杂的FAT协议,只需要调用FATFS模块提供给用户的一系列应用接口函数,如f_open  f_read  f_write和f_close等,就可以像在PC上读/写文件那样简单



大部分的可以移植的小系统或者应用,都是采用类似这种将与底层打交道的源码开发给用户编写,然后提供顶层配置文件供配置

diakio.c和diskio.h是硬件层

ff.c和ff.h是FATFS的文件系统层和文件系统的API层。


FATFS移植步骤

FATFS模块在移植的时候,一般只需要修改2个文件,即ffconf.h和diskio.c。FATFS模块的所有配置项都是存放在ffconf.h里面,可以通过配置里面的一些选项来满足自己的要求。disk.c是硬件层,负责与底层硬件接口适配。

1、数据类型:在integer.h里面去定义好的数据类型。需要了解用的编译器的数据类型,并根据编译器定义好数据类型。

为支持简体中文长文件名称需要添加ff_convert和ff_wtoupper 函数,实际这两个已经在cc936.c 文件中实现,我们只要直接把cc936.c文件添加到工程中就可以。

2、配置:通过ffconf.h配置FTAFS的相关功能,以满足需要。

FatFs 文件系统与底层介质的驱动分离开来,对底层介质的操作都要交给用户去实现,它仅仅是 提供了一个函数接口而已。

表FatFs移植需要用户支持函数为FatFs移植时用户必须支持的函数。 通过表FatFs 移植需要用户支持函数我们可以清晰知道很多函数是在一定条件下才需要添加的, 只有前三个函数是必须添加的。我们完全可以根据实际需求选择实现用到的函数。

前三个函数是实现读文件最基本需求。接下来三个函数是实现创建文件、修改文件需要的。为实 现格式化功能,需要在disk_ioctl添加两个获取物理设备信息选项。我们一般只要实现前面六个 函数就可以了,已经足够满足大部分功能。


  disk_initalize函数


disk_status函数


disk_write函数


disk_ioctl函数


get_fattime函数


3、函数编写:打开diskio.c进行底层驱动编写,一般需要编写6个接口函数底层设备驱动函数是存放在diskio.c文件,我们的目的就是把diskio.c中的函数接口与SPIFlash芯 片驱动连接起来。总共有五个函数,分别为设备状态获取(disk_status)、设备初始化(disk_initialize)、 扇区读取(disk_read)、扇区写入(disk_write)、其他控制(disk_ioctl)。

4.  f fconf.h 文件是 FatFs 功能配置文件,我们可以对文件内容进行修改,使得FatFs更符合我们的要 求。

ffconf.h 对每个配置选项都做了详细的使用情况说明。下面只列出修改的配置,其他配置采 用默认即可。

  • 1) _USE_MKFS:格式化功能选择,为使用FatFs格式化功能,需要把它设置为1。
  • 2) _CODE_PAGE:语言功能选择,并要求把相关语言文件添加到工程宏。为支持简体中文文件名 需要使用“936”,正如在图添加FatFS文件到工程的操作,我们已经把cc936.c文件添加到工程 中。 3) _USE_LFN:长文件名支持,默认不支持长文件名,这里配置为2,支持长文件名,并指定使 用栈空间为缓冲区。
  • 4) _VOLUMES:指定物理设备数量,这里设置为2,包括预留SD卡和SPIFlash芯片。
  • 5) _MIN_SS 、_MAX_SS:指定扇区大小的最小值和最大值。SD卡扇区大小一般都为512字节, SPI Flash 芯片扇区大小一般设置为4096字节,所以需要把_MAX_SS改为4096。
  • 6)_USE_STRFUNC。这个用来设置是否支持字符串类操作,比如f_putc,f_puts等。

FATFS开放函数

f_mount-注册/注销一个工作区域(Work Area)

f_open-打开/创建一个文件  

f_close-关闭一个文件

f_read-读文件

f_write-写文件

f_Iseek-移动文件读/写指针

f_truncate-截断文件

f_sync-冲洗缓冲数据Flush Cached Data

f_forward-直接转移文件数据到一个数据流

f_stat-获取文件状态

f_opendir-打开一个目录

f_closedir-关闭一个已经打开的目录

f_readdir-读取目录条目

f_mkdir-创建一个目录

f_unlink-删除一个文件或目录

f_chmod-改变属性(Attribute)

f_utime-改变时间戳(Timestamp)

f_rename-重命名/移动一个文件或文件夹

f_chdir-改变当前目录

f_chdrive-改变当前驱动器

f_getcwd-获取当前工作目录

f_getfree-获取空闲簇Get Free Clusters

f_getlabel-Get volume label

f_setlabel-Set Volume label

f_mkfs-Divide a physical drive

f_gets-读取一个字符串

f_putc-写一个字符

f_puts-写一个字符串

f_printf-写一个格式化的字符串        f_printf函数是格式化写入函数,需要把ffconf.h文件中的                                                                    _USE_STRFUNC配置为1才支持。 f_printf函数用法类似C库                                                            函数printf函数,只是它将数据直接写入到文件中。

f_tell-获取当前读/写指针

f_eof-测试文件结束

f_size-获取文件大小

f_error-测试文件上的错误

程序细化

获取FLASH空间信息

static FRESULT miscellaneous(void)
{
    FATFS *fs;
    DWORD fre_clust,fre_sect,tot_sect;
    printf("\r\n--------------------获取设备信息--------------------\r\n");
    /* 获取卷3的设备信息 */
    res = f_getfree("3:",&fre_clust,&fs);
    if(res)
    {
        printf("\r\n未获取到设备信息!\r\n");
        return res;
    }
    /* 计算得到的总的扇区个数和空扇区个数 */
    tot_sect = (fs->n_fatent -2) * fs->csize;
    fre_sect = fre_clust * fs->csize;
    /* 打印信息(4096字节/扇区) */
    printf("》设备总空间:%10lu KB。\n》可用空间::%10lu KB。\n",tot_sect*4 , fre_sect*4);
    return res;
}

文件定位操作

	printf("\r\n--------------------文件定位操作--------------------\r\n");
    res = f_open(&fp,"3:FatFs文件系统测试例程.txt",FA_OPEN_EXISTING | FA_READ );
    if(res == FR_OK)
    {
        res = f_lseek(&fp,fp.fsize/2);					//使用文件结构体的成员属性fsize获取文件大小,将文件指针定位到文件内容的中间
        //res = f_lseek(&fp,f_size(&fp)/2);				//使用f_size()获取文件大小,将文件指针定位到文件内容的中间	
        printf("\r\n文件打开成功,准备读取数据!\r\n");
        res = f_read(&fp,&readBuffer,sizeof(readBuffer),&fnum);
        if(res==FR_OK)
        {
            printf("》文件读取成功,读到字节数据:%d\r\n",fnum);
            printf("》读取得的文件数据为:\r\n%s \r\n", readBuffer);	
        }
        else
        {
            printf("!!文件读取失败:(%d)\n",res);
        }	
        f_close(&fp);        
    }
    else
    {
        printf("\r\n文件打开失败,失败代码 = %d\r\n",res);
    }

创建目录及重命名

printf("\r\n--------------------目录创建和重命名--------------------\r\n");
res = f_opendir(&dir,"3:Hello");
if(res != FR_OK)
{
    printf("\r\n不存在该目录,将创建新的Hello文件夹\r\n");
    res = f_mkdir("3:Hello");               //如果目录不存在,则创建目录
}
else
{
    printf("\r\n存在该目录,关闭目录并删除!\r\n");
    res = f_closedir(&dir);
    f_unlink("3:Hello/testdir.txt");
}
if(res == FR_OK)
{
    printf("\r\n将FatFs文件系统测试例程.txt复制到Hello下,并重命名为testdir.txt\r\n");
    res = f_rename("3:FatFs文件系统测试例程.txt","3:Hello/testdir.txt");
}
readFile(&fp,"3:Hello/testdir.txt");


文件/文件夹信息获取

static FRESULT file_check(const TCHAR *path)
{
    FILINFO fInfo;
    /* 获取文件信息 */
    res = f_stat(path,&fInfo);
    if(res == FR_OK)
    {
        printf("“%s”文件信息:\n",path);
        printf("》文件大小:%ld(字节)\n",fInfo.fsize);
        printf("》时间戳:%u/%02u/%02u,%02u:%02u\n",(fInfo.fdate >> 9)+1980,fInfo.fdate >> 5&15,fInfo.fdate & 31,fInfo.ftime>>11,fInfo.ftime >>5 &63);
        printf("》属性:%c%c%c%c%c\n\n",
        (fInfo.fattrib & AM_DIR)?'D':'-',                //目录
        (fInfo.fattrib & AM_RDO)?'R':'-',                //只读文件
        (fInfo.fattrib & AM_HID)?'H':'-',                //隐藏文件
        (fInfo.fattrib & AM_SYS)?'S':'-',                //系统文件
        (fInfo.fattrib & AM_ARC)?'A':'-');               //档案文件
    }
    elsec
    {
        printf("\r\n文件打开失败,失败代码 = %d\r\n",res);
    }
    return res;
}
res = file_check("3:Hello/testdir.txt");

在主函数中调用函数


文件遍历

static FRESULT Scan_files(char *path)
{
    FRESULT res;
    FILINFO fInfo;
    DIR dir;
    int i;
    char *fn;  
#if _USE_LFN					//如果使用长文件名
    static char lfn[_MAX_LFN*2+1];
    fInfo.lfname = lfn;
    fInfo.lfsize = sizeof(lfn);
#endif
    res = f_opendir(&dir,path);				//打开目录
    if(res == FR_OK)
    {
        i = strlen(path);
        for(;;)
        {
            res = f_readdir(&dir,&fInfo);			 //读取目录下的内容,再读会自动读到下一个文件
            if(res != FR_OK||fInfo.fname[0] == 0)
                break;
#if _USE_LFN
            /*这里其实不用看的,我们之前已经启用长文件名了,但是需要注意的
            是,虽然启用了长文件名,当存储文件名不够13个字节时,文件系统仍
            然会将文件名存储到fname中,只有文件名超过13时,才会存储到lfname中*/
            fn = *fInfo.lfname ? fInfo.lfname:fInfo.fname;	
#else
            fn = fInfo.name;
#endif
            if(*fn == '.')            //如果遇到点,则表示当前目录,跳过即可
                continue;
            if(fInfo.fattrib & AM_DIR)			//遇到目录时,递归调用
            {
                sprintf(&path[i],"/%s",fn);		//将获取到的文件名合成为完整文件名(即包含卷标和目录名的)
                res = Scan_files(path);                //递归遍历
                path[i] = 0;
                if(res != FR_OK) 				//如果打开失败,跳出循环
                    break;
            }
            else
            {
                printf("%s/%s\r\n",path,fn);
            }
        }
    }
    return res;
}

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

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

相关文章

IDEA配置Java远程调试,以CVE-2024-4956为例

背景 学习代码审计,看到一些Java的漏洞,想要动手调试,复现漏洞搭建环境可以使用docker快速创建,了解到Java可以远程调试,本文记录学习Java远程调试环境搭建的过程。 远程调试的原理 如下图(图源&#xf…

无人值守设备远程运维,几个关键问题如何解决?

商用无人值守设备承载着很多企业的一线业务,它们分布广泛且数量众多,企业如何对这类设备实施有效的运维管理是一个重要的课题。 面对这一问题,很多企业选择了引入远程运维方案,以远程桌面为基础工具实施远程运维管理,…

安卓玩机搞机技巧综合资源----电脑控制手机 投屏操控的软件工具操作步骤解析【二十二】

接上篇 安卓玩机搞机技巧综合资源------如何提取手机分区 小米机型代码分享等等 【一】 安卓玩机搞机技巧综合资源------开机英文提示解决dm-verity corruption your device is corrupt. 设备内部报错 AB分区等等【二】 安卓玩机搞机技巧综合资源------EROFS分区格式 小米红…

1、Tomcat整体架构

1、Tomcat整体架构 Tomcat介绍Tomcat概述Tomcat目录结构web应用部署的三种方式 Tomcat整体架构分析Tomcat架构图Tomcat核心组件Server 组件Service组件连接器Connector组件容器Container组件结合Server.xml理解Tomcat架构请求定位 Servlet 的过程 Tomcat架构设计精髓Connector高…

netty LengthFieldBasedFrameDecoder 根据动态长度分包粘包

如下数据格式 在方法: // Integer.MAX_VALUE, // maxFrameLength: 最大允许的帧长度// 4, // lengthFieldOffset: 长度字段在帧中的偏移量,这里是在帧头之后// 4, // lengthFieldLength: 长度字段的长度,4字节表示32位整数// 0, // …

常见4种时间管理方法及实施步骤(收藏版)

有效的时间管理方法,不仅能够保证项目按时交付,还能提高开发效率,减少成本超支和质量风险。如果缺乏明确的时间规划,可能会导致任务延误;容易造成资源分配不当,导致整体效率低下和成本增加。 因此有效的时间…

go语言实现微信扫码登录,涵盖微信登录超详细流程并附带时序图

微信扫码登录 1. 简述:此文章目的主要是web网站进行微信扫码登录2. 微信登录过程时序图3. 全部微信登录组成元素3.1. 微信扫码登录后端总共只需要两个接口,3.2. 微信登录的各个对象:3.3. 微信登录的主要参数: 4. 流程解释&#xf…

基于Android Studio 垃圾分类助手App--原创

一、高质量源码(非开源,白嫖低价勿扰) 关注公众号:《编程乐学》 后台回复:24060301 二、项目演示视频 基于Android Studio 垃圾分类助手App--原创 三、开发环境 四、设计与实现 1.启动页 1.设置延迟三秒后执行 runna…

HDL-A/1-110VAC-2电流继电器 JOSEF约瑟 导轨安装

一. 应用 HDL系列电流继电器是静态型,不带方向性的、瞬动、交流电流继电器。可用于电力系统输电线,电机过负荷和短路保护中,作为启动元件。 继电器对短路电流中的直流分量不敏感,因此可用于要求哲态超小的线路中,改继电器由集成…

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图(五)

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图(五) 参考 目录 文章目录 SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图(五)1、设置sping.beaninfo.ignore属性2、…

一文带你搞懂单模光纤和多模光纤的区别

单模光纤和多模光纤的区别及常见疑问解答 随着网络技术的飞跃,光纤因其高速传输与大容量特性,成为通信领域的佼佼者。光纤主要分为单模与多模,两者在几何与传输特性上迥异,实际应用中表现显著不同。本文将深入剖析两者的差异与应用…

记一次黑群晖折腾的过程

Tips: 建议先完整看完这篇文章,理解大致流程后再上手操作,其中有一些注意点需要事先了解 安装黑群晖的教程网上很多,我是参考了这篇: https://post.smzdm.com/p/am3epen4/前言在上一盘文章中组装了一台黑群晖&#…

Docker基础篇之将本地镜像发布到私有库

文章目录 1. Docker Registry简介2. 将本地镜像推送到私有库 1. Docker Registry简介 Docker Registry是官方提供的工具,可以用于构建私有镜像仓库。 2. 将本地镜像推送到私有库 下载Docker Registry docker pull registry现在我们可以从镜像中看到下载的Regist…

数据持久化第七课-URL重写与Ajax

数据持久化第七课-URL重写与Ajax 一.预习笔记 1.URL重写(对网页地址进行保护) 首先编写module,实现对网络地址的处理 其次就是module的配置 最后验证url重写技术 2.Ajax数据交互 编写后端响应数据 处理跨域的配置问题 运行项目得到后端响应数据的地址 编写前端ajax进行数据请…

基于VGG16的猫狗数据集分类

目录 1. 作者介绍2. VGG16介绍2.1 背景介绍2.2 VGG16 结构 3. Cat VS Dog数据集介绍4. 实验过程4.1 数据集处理4.2 训练部分设置4.3 训练结果4.4 问题分析4.5 单张图片测试 5.完整训练代码与权重参考文献 1. 作者介绍 孙思伟,男,西安工程大学电子信息学…

Accelerate 笔记:保存与加载文件

保存和加载模型、优化器、随机数生成器和 GradScaler 使用 save_state() 将上述所有内容保存到一个文件夹位置使用 load_state() 加载之前通过 save_state() 保存的状态通过使用 register_for_checkpointing(),可以注册自定义对象以便自动从前两个函数中存储或加载 …

epoll源码分析

epoll源码分析 主要数据结构epoll_create()函数实现ep_alloc():初始化结构初始化eventpoll epoll_ctl()函数实现ep_insert回调函数的实现ep_ptable_queue_proc函数ep_poll_callback epoll_wait函数SYSCALL_DEFINE4(epoll_wait, ...)ep_pollep_send_events 主要数据结…

百度/迅雷/夸克,网盘免费加速,已破!

哈喽,各位小伙伴们好,我是给大家带来各类黑科技与前沿资讯的小武。 之前给大家安利了百度网盘及迅雷的加速方法,详细方法及获取参考之前文章: 刚刚!度盘、某雷已破!速度50M/s! 本次主要介绍夸…

基于DeepLabv3+实现图像分割

目录 1. 作者介绍2. DeepLabv3算法2.1 DeepLabv3算法介绍2.2 DeepLabv3模型结构 3. 实验过程基于DeepLabv3实现图像分割3.1 VOC数据集介绍3.2 代码实现3.3 问题分析 4. 参考连接 1. 作者介绍 吴天禧,女,西安工程大学电子信息学院,2023级研究…

派派派森02

目录 1.容器 1.列表 2.元组 3.字符串 3.序列 4.集合 5.字典 2.数据容器通用操作 • max最大元素 • min最小元素 • 容器的通用转换功能 • 通用排序功能 3.字符串大小比较 4.函数中多个返回值 5.函数参数多种传递方式 1.位置参数 2.关键字参数 3.缺省参数 …