的使用STM32中使用FATFS文件系统的指南

 可裁剪意味着可以选择部分功能,减小占用的空间。

与Windows兼容意味着可以在电脑上直接读取文件。 


底层接口,
包括存储媒介读/写接口(
disk I/O
)和供给文件创建修改时间的实时时钟

需要我们
根据平台和存储介质
编写移植代码


中间层
FATFS
模块,
实现了
FAT
文件读/写协议。
FATFS
模块提供的是
ff.c

ff.h
。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。


最顶层是应用层,
使用者无需理会
FATFS
的内部结构和复杂的
FAT
协议,只需要调用
FATFS
模块提供给用户的一系列应用接口函数,如
f_open

f_read

f_write

f_close
等,就可以像在
PC
上读/写文件那样简单。

文件名

功能

说明

ffconf.h

FATFS模块配置文件

 需要根据需求来配置参数。

ff.h

FATFS和应用模块公用的包含文件

 不需要修改

ff.c

FATFS模块源码

 不需要修改

diskio.h

FATFS和disk I/O模块公用的包含文件

 不需要修改

diskio.c

FATFS和disk I/O模块接口层文件

与平台相关的代码,需要用户根据存储介质来编写函数。

interger.h

数据类型定义

与编译器有关。

option文件夹

可选的外部功能(比如支持中文等)

汉字实验把字库放到SPI FLASH需要修改

 diskio.c文件非常重要,我们需要根据存储介质来修改,是与硬件打交道的。

经验:

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


_FS_TINY

这个选项在
R0.07
版本中开始出现,之前的版本都是以独立的
C
文件出现(
FATFS

Tiny FATFS
),有了这个选项之后,两者整合在一起了,使用起来更方便。我们使用
FATFS
,所以把这个选项定义为
0
即可。


_FS_READONLY

这个用来配置是不是只读,本章我们需要读写都用,所以这里设置为
0
即可。


_USE_STRFUNC
。这个用来设置是否支持字符串类操作,比如
f_putc

f_puts
等,本章我们需要用到,故设置这里为
1

④ _USE_MKFS。这个用来定时是否使能格式化,本章需要用到,所以设     置这里为1。

⑤ _USE_FASTSEEK。这个用来使能快速定位,我们设置为1,使能快速定位。

⑥ _USE_LABEL。这个用来设置是否支持磁盘盘符(磁盘名字)读取与设置。我们设置为1,使能,就可以通过相关函数来读取和设置磁盘的名字了。

⑦_CODE_PAGE。这个用于设置语言类型,包括很多选项(见FATFS官网说明),我们这里设置为936,即简体中文(GBK码,需要c936.c文件支持,该文件在option文件夹)。

⑧_USE_LFN。该选项用于设置是否支持长文件名(还需要_CODE_PAGE支持),取值范围为0~3。0,表示不支持长文件名,1~3是支持长文件名,但是存储地方不一样,我们选择使用3,通过ff_memalloc函数来动态分配长文件名的存储区域。

⑨_VOLUMES。用于设置FATFS支持的逻辑设备数目,我们设置为3的话,即支持3个设备(磁盘)。

⑩_MAX_SS。扇区缓冲的最大值,一般设置为512。

diskio.c和diskio.h是硬件层。

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

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

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

②配置:通过ffconf.h配置FATFS的相关功能,以满足你的需要。

③函数编写:打开diskio.c,进行底层驱动编写,一般需要编写6个接口函数

 

 下面以接口函数disk_read 为例子

//读扇区
//drv:磁盘编号0~9
//*buff:数据接收缓冲首地址
//sector:扇区地址
//count:需要读取的扇区数
DRESULT disk_read (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE *buff,		/* Data buffer to store read data */
	DWORD sector,	/* Sector address (LBA) */
	UINT count		/* Number of sectors to read (1..128) */
)
{
	u8 res=0; 
    if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误		 	 
	switch(pdrv)
	{
		case SD_CARD://SD卡
			res=SD_ReadDisk(buff,sector,count);	 
		 	if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
			{
				SD_SPI_SpeedLow();
				SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
				SD_SPI_SpeedHigh();
			}
			break;
		case EX_FLASH://外部flash
			for(;count>0;count--)
			{
				SPI_Flash_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
				sector++;
				buff+=FLASH_SECTOR_SIZE;
			}
			res=0;
			break;
		default:
			res=1; 
	}
   //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值
    if(res==0x00)return RES_OK;	 
    else return RES_ERROR;	   
}

f_mount -注册/注销一个工作区域(Work Area)
f_open -打开/创建一个文件
f_close -关闭一个文件
f_read -读文件
f _write-写文件
f _lseek -移动文件读/写指针
f_truncate -截断文件
f sync – 冲洗缓冲数据 Flush Cached Data
f_forward 直接转移文件数据到一个数据
f_stat-获取文件状态
f_opendir -打开一个目录

正点原子自己写了一个exfuns.c的文件用来实现部分文件操作,如下图的f_typetell所示。同时写了fattester文件来封装FSTFS文件管理系统的开放函数,fattester.h文件如下。

//报告文件的类型
//fname:文件名
//返回值:0XFF,表示无法识别的文件类型编号.
//		 其他,高四位表示所属大类,低四位表示所属小类.
u8 f_typetell(u8 *fname)
{
	u8 tbuf[5];
	u8 *attr='\0';//后缀名
	u8 i=0,j;
	while(i<250)
	{
		i++;
		if(*fname=='\0')break;//偏移到了最后了.
		fname++;
	}
	if(i==250)return 0XFF;//错误的字符串.
 	for(i=0;i<5;i++)//得到后缀名
	{
		fname--;
		if(*fname=='.')
		{
			fname++;
			attr=fname;
			break;
		}
  	}
	strcpy((char *)tbuf,(const char*)attr);//copy
 	for(i=0;i<4;i++)tbuf[i]=char_upper(tbuf[i]);//全部变为大写 
	for(i=0;i<6;i++)
	{
		for(j=0;j<13;j++)
		{
			if(*FILE_TYPE_TBL[i][j]==0)break;//此组已经没有可对比的成员了.
			if(strcmp((const char *)FILE_TYPE_TBL[i][j],(const char *)tbuf)==0)//找到了
			{
				return (i<<4)|j;
			}
		}
	}
	return 0XFF;//没找到		 			   
}	 

mf_showfree 函数用来显示剩余SD卡的容量

//显示剩余容量
//drv:盘符
//返回值:剩余容量(字节)
u32 mf_showfree(u8 *drv)
{
	FATFS *fs1;
	u8 res;
    u32 fre_clust=0, fre_sect=0, tot_sect=0;
    //得到磁盘信息及空闲簇数量
    res = f_getfree((const TCHAR*)drv,(DWORD*)&fre_clust, &fs1);
    if(res==0)
	{											   
	    tot_sect = (fs1->n_fatent - 2) * fs1->csize;//得到总扇区数
	    fre_sect = fre_clust * fs1->csize;			//得到空闲扇区数	   
#if _MAX_SS!=512
		tot_sect*=fs1->ssize/512;
		fre_sect*=fs1->ssize/512;
#endif	  
		if(tot_sect<20480)//总容量小于10M
		{
		    /* Print free space in unit of KB (assuming 512 bytes/sector) */
		    printf("\r\n磁盘总容量:%d KB\r\n"
		           "可用空间:%d KB\r\n",
		           tot_sect>>1,fre_sect>>1);
		}else
		{
		    /* Print free space in unit of KB (assuming 512 bytes/sector) */
		    printf("\r\n磁盘总容量:%d MB\r\n"
		           "可用空间:%d MB\r\n",
		           tot_sect>>11,fre_sect>>11);
		}
	}
	return fre_sect;
}		    

 exfuns.c中的exf_getfree提供了类似的功能

//得到磁盘剩余容量
//drv:磁盘编号("0:"/"1:")
//total:总容量	 (单位KB)
//free:剩余容量	 (单位KB)
//返回值:0,正常.其他,错误代码
u8 exf_getfree(u8 *drv,u32 *total,u32 *free)
{
	FATFS *fs1;
	u8 res;
    u32 fre_clust=0, fre_sect=0, tot_sect=0;
    //得到磁盘信息及空闲簇数量
    res =(u32)f_getfree((const TCHAR*)drv, (DWORD*)&fre_clust, &fs1);
    if(res==0)
	{											   
	    tot_sect=(fs1->n_fatent-2)*fs1->csize;	//得到总扇区数
	    fre_sect=fre_clust*fs1->csize;			//得到空闲扇区数	   
#if _MAX_SS!=512				  				//扇区大小不是512字节,则转换为512字节
		tot_sect*=fs1->ssize/512;
		fre_sect*=fs1->ssize/512;
#endif	  
		*total=tot_sect>>1;	//单位为KB
		*free=fre_sect>>1;	//单位为KB 
 	}
	return res;
}		   

 

物联沃分享整理
物联沃-IOTWORD物联网 » 的使用STM32中使用FATFS文件系统的指南

发表评论