可裁剪意味着可以选择部分功能,减小占用的空间。
与Windows兼容意味着可以在电脑上直接读取文件。
文件名 |
功能 |
说明 |
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文件非常重要,我们需要根据存储介质来修改,是与硬件打交道的。
经验:
大部分的可移植的小系统或者应用,都是采用类似这种将与底层打交道的源码开发给用户编写,然后提供顶层配置文件供配置。不需要自己编写文件管理系统。
④ _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.h和diskio.c。FATFS模块的所有配置项都是存放在ffconf.h里面,我们可以通过配置里面的一些选项,来满足自己的需求是diskio.c硬件层,负责与底层硬件接口适配。
下面以接口函数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;
}