历史上的今天
返回首页

历史上的今天

今天是:2024年09月16日(星期一)

2018年09月16日 | 对STM32中FATFS文件系统常用API函数的理解

2018-09-16 来源:eefocus

首先,第一次在CSDN上面开通博客,这也算是我的第一篇博文吧,写的不好的地方还请大家不吝赐教微笑,笔者现大二在校学生,之所以会选择在这里使用博客,是在一位嵌入式大虾的渲染下,和小伙伴一起分享学习的话,我相信可以学的更多。偷笑

废话不多说,进入主题。

首先,FATFS 是一个完全免费开源的 FAT 文件系统模块,专门为小型的嵌入式系统而设计的,使用标准的C语言编写,具有很强的独立性,可以轻松的移植到8位,16位,及其我正在用的32位ARM系列的STM32上面。即FATFS是可裁剪的文件系统。这点,尤为重要。

FATFS模块的层次结构图如下,这里,参考了部分正点原子的资料,感谢原子大大偷笑


其中底层接口,包括存储媒介读/写接口(disk I/O)和供给文件创建修改时间的实时时钟,需要我们根据平台和存储介质编写移植代码。
而中间层FATFS模块,实现了FAT 文件读/写协议。FATFS模块提供的是ff.c和ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。
最顶层是应用层,使用者无需理会FATFS复杂的FAT 协议和内部结构,只需要调用FATFS模块提供给用户的一系列应用API接口函数。

那么,下面就来介绍下 我对FATFS文件系统的常用API接口函数的一些理解。(以下是我直接在WPS里面写好的,故直接cp过来了大笑,往理解)

/* FRESULT f_open函数mode全部打开方式说明

---------------------------------------------------------------------------------

FA_READ           | 读模式,( 读写模式可同时生效)              

FA_WRITE          | 写模式,( 读写模式可同时生效)

FA_OPEN_EXISTING  | 默认打开方式

FA_OPEN_ALWAYS   | 打开文件,如果文件不存在,则创建一个新文件;

  | 用此种方式,可以用 f_lseek 在文件后追加数据

                  |

FA_CREATE_NEW   | 新建文件,如果文件已存在,则新建失败

FA_CREATE_ALWAYS  | 新建文件,如果文件已存在,覆盖旧文件   

                      |

---------------------------------------------------------------------------------

*/

 


/*---------------------------------------------------------------------------------

/①以下测试 f_write 通过程序写入数据 即通过程序新建txt文档且有数据

  res=f_open (&fil,"0:/写入.txt", FA_CREATE_ALWAYS|FA_WRITE); //新建文件和写操作

f_write (&fil, "This is a new file, the data is just written in!", 48, &bww);//前提是以写文件的形式打开文件


f_close(&fil);//关闭文件,必须和 f_open 函数成对出现,同下


res=f_open (&fil,"0:/写入.txt", FA_READ);

    

  f_read (&fil, buf,48,&bww);

f_close(&fil);//不论打开还是新建文件啊,一定记得关闭


LCD_ShowString(10,210,280,24,24,(u8 *)buf);//

①以下测试通过程序写入数据 即通过程序新建txt文档且有数据

--------------------------------------------------------------------------------- */

/*---------------------------------------------------------------------------------

②以下测试FRESULT f_lseek()移动文件指针,此函数在对已打开的文件进行读或写时,可以移动当前指针位置 即可以加入或者减去某些不需要的数据

 

     res=f_open (&fil,"0:/写入.txt", FA_WRITE);

 res = f_lseek (&fil , 25); ////指针指向第 25 个字节

 res = f_write (&fil , "40" ,2 , &bw);//2为表示写入数据为2字节

    // res = f_lseek (&fil , fil.fptr + 10); ////指针向前移动 10 个字节

 res = f_lseek (&fil , 28); ////指针指向第 28个字节

     res = f_write (&fil , "forward" ,8 , &bw);

    // res = f_lseek (&fil , fil.fptr - 20); ////指针向后移动 20 个字节

 res = f_lseek (&fil , 37); ////指针指向第 37 个字节

     res = f_write (&fil , "backward" , 9, &bw);//写入数据为9字节

     res = f_lseek (&fil , fil.fsize); ////指针指向文件末尾

     res = f_write (&fil , "end" ,3 , &bw);

     res = f_close ( &fil );

--------------------------------------------------------------------------------- */

/*---------------------------------------------------------------------------------

③以下测试FRESULT f_truncate()截断文件,此函数可以在将文件在当前指针处截断,也可以延长文件长度

 

      res = f_open (&fil ,"0:/写入.txt", FA_WRITE);//打开文件和写操作

      res = f_lseek (&fil , 60); ////指针指向第 60 个字节

      res = f_truncate (&fil ); ////将文件在此截断,在60字节以后的数据都会消失,即截断文件

      res = f_sync ( &fil ); ////关闭文件

 

-------------------------------------------------------------------------------- */

/*---------------------------------------------------------------------------------  

④刷新缓存信息FRESULT f_sync (FIL* FileObject )函数,* FileObject==指向文件对象结构体的指针

例如:res=f_sync(&fil);

函数说明:此函数功能兼容f_close,它与f_close的区别就是在执行后,当前文件是否有效.

          调用该函数后,当前文件仍然可读可写可查询.

使用方法:当文件长期处于写模式,如数据记录时,定期调用此函数,或者在写入数据后立即调用

          此函数,可以减少因为断电等意外情况带来的数据损失,有点WORD中后台定期保存的意思.

--------------------------------------------------------------------------------- */

/*---------------------------------------------------------------------------------   

⑤新建文件夹FRESULT f_mkdir (const TCHAR* DirName)函数,*DirName==指向将要创建的文件夹名的指针

函数说明:新建一个文件夹,

 

注意:文件名应符合 fatfs 标准,不能包含非法字符,

      文件名长度不能大于8,否则新建不成功

例:f_mkdir("new");//新建一个文件名为new的文件夹       

--------------------------------------------------------- */

/*---------------------------------------------------------------------------------   

⑥删除文件和文件夹FRESULT f_unlink()函数,*FileName : 指向文件或文件夹的名称的指针

函数说明:此函数可以删除一个文件或者文件夹

使用注意项:

           删除文件夹时:1.不能为当前文件夹

               2.不能为非空文件夹

删除文件时: 1.不能为已打开文件

                         2.不能为只读文件

例如:f_unlink("new");//删除“new”这个文件夹

      f_unlink("TEXT/写入.txt");//删除“TEXT”这个文件夹下的“写入”txt文本

删除文件的时候必须注意一点 此外的所有尾巴都必须是以png txt结束的

--------------------------------------------------------- */


/*---------------------------------------------------------------------------------   

⑦重命名\移动文件或文件夹FRESULT f_rename (const TCHAR* OldName,const TCHAR* NewName)

函数说明:此函数可以移动或者重命名一个文件或者文件夹

参数说明:*OldName : 指向旧文件名的指针

          *NewName : 指向新文件名的指针

使用注意项:

           1.此函数可以重命名 文件或者文件夹,而不论文件夹是否为空.

 2.此函数可以移动  文件或者文件夹,而不论文件夹是否为空.

例如:     res = f_rename("测试.txt","测试1.txt"); //重命名测试.txt文件,

           res = f_rename("测试1.txt","PAINT/测试2.txt");

 //将测试1.txt文件移动到文件夹PAINT中并重命名为测试2.txt

 

--------------------------------------------------------- */

/*---------------------------------------------------------------------------------   

⑧获取文件信息 FRESULT f_stat(const TCHAR* FileName,FILINFO* FileInfo)

函数说明:此函数可以获取文件的最近修改时间,属性等信息,获取的信息存储在fileninfo结构体中

参数说明:*FileName: 指向文件名的指针

          *FileInfo: 指向保存文件信息的结构体的指针 类型必须为FileInfo

使用注意项:

           1.如果目标是文件夹,获取的大小为0.

 2.此函数对根目录无效.

 3.时间和日期均为两字节,存储格式如下:

 a) 日期:

                    i. bit15…bit9: 年 计算后的十进制数应该加上1980

                    ii. bit8 … bit5: 月

                    iii. bit4 … bit0: 日

           b) 时间:

                    i. bit15… bit11 : 时

                    ii. bit10… bit5 : 分

                    iii. bit4 … bit0 : 秒 算出的十进制数应 *2

举例:

         i. 日期: 0000001 0001 00001, 表示 1981 年 1 月 1 日

         ii.时间: 00001  000001 00001,表示 1 点 1 分 2 秒

 

 

举例:   res = f_stat("TEXT/写入.txt", &filinfo); //读取 folder 目录下 newname.txt 文件的信息

if( res )

printf("newname.txt err : %d\r\n", res);//没读取文件信息成功

else

{

printf("newname.txt size : %lu\r\n",filinfo.fsize);//读取文件的长度,即占多少字节

printf("fdate : %d\r\n",filinfo.fdate); //读取文件的最近修改日期 转化为2进制,

printf("ftime : %d\r\n",filinfo.ftime);//读取文件的最近修改时间,转化为2进制

printf("fattrib : %d\r\n",filinfo.fattrib);//显示文件的属性,即什么文件


//#define AM_RDO 0x01 //只读文件

//#define AM_HID 0x02 //隐藏文件

//#define AM_SYS 0x04 //系统文件

//#define AM_VOL 0x08 //卷标文件

//#define AM_LFN 0x0F //

//#define AM_DIR 0x10 //程序目录

//#define AM_ARC 0x20 //存档文件

//#define AM_MASK 0x3F //

}

--------------------------------------------------------- */


 

/*---------------------------------------------------------------------------------   

⑨改变文件属性:FRESULT f_chmod (const TCHAR* FileName,BYTE Attribute,BYTE AttributeMask)

函数说明:

          1. 此函数可以修改文件或文件夹的属性

          2. 可修改的属性只能是以下一种或几种的组合,对其它属性无效

AM_RDO //只读文件

AM_ARC //存档文件

AM_SYS //系统文件

AM_HID //隐藏文件

参数说明:  

a) *Filename:指向文件或文件夹的名称的指针

b) Attribute:要置位的属性,即需要将文件或者文件夹属性改成什么

c) AttributeMask:需要改变的属性(包括要置位的和要清除的属性),即包含原属性和需要更改的属性

使用方法:

a) Attribute 须为 AttributeMask 的子集

b) 函数对 AttributeMask 中的属性集合进行处理,若属性包含在 Attribute中,则置位,否则清除



举例: 对文件 TEXT/写入.txt,置位 HID 和 SYS 属性,取消 ARC和 RDO 属性

         res = f_chmod("TEXT/写入.txt", AM_HID | AM_SYS, AM_ARC | AM_RDO | AM_HID |AM_SYS);

         if( res )

 printf("err :%d\r\n", res);

 else

 {

 res = f_stat("TEXT/写入.txt", &filinfo);

   printf("fattrib : %d\r\n",filinfo.fattrib);//

         }

--------------------------------------------------------- */

         

/*---------------------------------------------------------------------------------   

⑩改变文件时间戳FRESULT f_utime (TCHAR* FileName,FILINFO* TimeDate)

函数说明:

1. 此函数可以更改文件的最近修改时间

参数说明:

a) Filename :指向文件的指针

b) Timedate :指向文件信息结构体的指针

 

使用方法: 在这个函数里,可以我们可以写入常规的日期时间,然后此函数按日期存储格式(见上)将数据整合后调用 f_utime.

FRESULT set_timestamp ( char *obj,int year, int month, int mday, int hour, int min, int sec);//

{

FILINFO fno;

fno.fdate = (WORD)(((year - 1980) * 512U) | month * 32U | mday);

fno.ftime = (WORD)(hour * 2048U | min * 32U | sec / 2U);

return f_utime(obj, &fno);


res = set_timestamp("123.txt",2001,06,05,02,03,34);//修改 123.txt 时间

printf("%d\r\n",res);


此例没有通过,没有找到FRESULT set_timestamp();这个函数原型 委屈

---------------------------------------------------------

好了,以上就是我对于FATFS文件系统常用API函数的一些理解,希望可以帮到一些朋友快速了解


推荐阅读

史海拾趣

Fedco_Batteries公司的发展小趣事

在快速发展的同时,Fedco_Batteries始终关注社会责任。公司积极参与公益事业,捐款捐物支持灾区重建、教育扶贫等项目。同时,公司还注重环保和可持续发展,致力于研发环保型电池产品,减少对环境的影响。这种关注社会责任的企业精神,让Fedco_Batteries在社会上树立了良好的形象。

GMT(致新科技)公司的发展小趣事
如果电源正常,应检查时间控制芯片或MCU是否工作正常。可以使用万用表等工具测量其供电电压、输出信号等是否正常。
B&K Precision公司的发展小趣事

为了进一步拓展国际市场,B&K Precision在全球范围内设立了多个分公司和办事处。其中,2012年在中国设立的分公司百科中国仪器有限公司是一个重要的战略布局。这一举措不仅加强了公司在亚洲市场的地位,也为各地客户提供了更为迅速和便捷的售后服务保障。同时,通过与国际知名企业的合作与交流,B&K Precision不断吸收先进的技术和管理经验,为公司的持续发展注入了新的动力。

以上五个故事,展现了B&K Precision公司从车库起步到成为全球电子测量领域领导者的发展历程。通过不断创新和拓展业务,公司成功应对了市场变化和挑战,成为了电子行业中的佼佼者。

Ford Aerospace & Communications Corp公司的发展小趣事

随着航空业的逐渐发展,福特汽车公司意识到航空通信技术的重要性。在20世纪30年代,福特开始投资研发航空无线电通信系统,旨在提高飞行中的通信效率和安全性。这一举措不仅促进了福特在航空技术领域的进一步拓展,也为后来的航空通信标准制定提供了参考。

GE公司的发展小趣事

随着航空业的逐渐发展,福特汽车公司意识到航空通信技术的重要性。在20世纪30年代,福特开始投资研发航空无线电通信系统,旨在提高飞行中的通信效率和安全性。这一举措不仅促进了福特在航空技术领域的进一步拓展,也为后来的航空通信标准制定提供了参考。

Amphenol Thermometrics公司的发展小趣事

在汽车制造领域,福特一直是技术创新的领导者。20世纪60年代,福特开始将电子设备集成到汽车中,包括车载电话、导航系统以及早期的娱乐系统。这些创新不仅提升了驾驶的便捷性和舒适性,也预示着未来汽车电子化、智能化的趋势。虽然这些技术并不直接属于航空通信范畴,但它们展示了福特在电子技术应用方面的前瞻性和实力。

问答坊 | AI 解惑

求助

谁晓得人机交互界面的设计需要学点什么知识…

查看全部问答>

纳闷:按说A/D前面不加低通滤波

按说A/D前面不加低通滤波,因为采样造成的混叠会使情况“很糟”, 但事实上似乎没那么严重。各位是否都加所谓的抗混叠滤波?…

查看全部问答>

8051f320上位机编写?

1.怎么向8051f320的usb口发送信号? 我是指pc端的软件编写。 320是会被识别为hid类吗? 用到的api主要有哪些呢?vb vc 的都行啊 最好是vb 2。我要用320实现usb信号转变成串口信号的功能,主要为了解决笔记本缺少com口的问题。方法是从usb接受数据 ...…

查看全部问答>

wavecomeq2403 端口问题

Q2403模块的SPK1P,SPK1N,MIC1P,MIC1N各在板面上的什么位置? 或者说,话筒和听筒的位置在哪里?…

查看全部问答>

关于散热片面积的计算问题

MC34063的电路,基本上确定了一些必要的参数,比如开关频率,和输出电流等等,可以开始做了。 在选中功率三极管的时候,想起了关于散热片的问题。        在功率散热器件的PDF中给出的耗散功率一般是加装了散热片的数 ...…

查看全部问答>

SPI通讯

我用VET6的SPI1操作一个加速度芯片,读字节总是0x00,但用同样的代码操作SPI2,FLASH IC确可以。不知道是什么原因。请问大家是怎么用SPI1的啊? SPI的设置我反复修改,结果还是不行。但是在优易特的STM32开发板上操作FLASH确可以。 具体代码如 ...…

查看全部问答>

altium designer 10的一些问题

ALTIUM DESIGNER 10 原理图 PCB用 SMART PDF 转出来的PDF只显示实际原理图与PCB的左上角一部分,而这个文件AD9转成PDF都是正常的,各位大侠何解    还有AD10 封装属性对话框太大了,长下两部分都无法显示,我是在笔记本上用,分辨率 ...…

查看全部问答>

急,怎么用595芯片驱动一个四位的数码管

本帖最后由 paulhyde 于 2014-9-15 09:28 编辑 …

查看全部问答>