本帖最后由 petp 于 2014-11-14 16:32 编辑
***************
学习背景
***************
FATFS是开发板上最常用的文件系统,流行的STM32开发板基本都采用FATFS;增强型51开发板也会用文件系统,FATFS和 znFAT都有。相较而言,FATFS的应用更广,但是缺少介绍的书籍,而znFAT有比较详尽的介绍,所以用来FAT入门还是不错的,不过znFAT的例程是少的可怜。
文件系统一般都是移植好的(直接复制,改些接口参数就好用了),所以从应用角度看,没有必要为了偶尔一次的应用而学习FAT。所以学习FAT,可能就是用文件系统的频率比较高,或者感兴趣。
******************
文件诞生的环境
首先看一下 的FAT32 文件系统整体结构。
这样看,有些枯燥,更改一下形式,
这些扇区、表、簇等结构的定义,要熟悉,才能继续,
MBR DBR 和 FSINFO 的大小都是一个扇区,而保留扇区是若干扇区组成,FAT表也是由若干扇区(与SD容量正相关)组成,簇一般是8个扇区。与示意图的比例不一致,示意图重点在于表明相互联系。
************************************
先看MBR (对于 《znFAT》的第五章)
《znFAT》首先利用WinHex 软件查看 SD卡 的0扇区(即MBR)。
我自己也模仿了一下,
测试报告:
总计容量: 3,904,897,024 字节 = 3.6 GB
柱面数: 474
磁头数: 255
扇区/磁道: 63
字节/扇区: 512
总计扇区数: 7,626,752
剩余扇区: 11,942 扇区
SMART: 函数不正确。
分区 1
扇区2,048 - 7,626,751
分区表: 扇区0
文件系统: FAT32
名称: 系统
总计容量: 3,903,848,448 字节 = 3.6 GB
总计扇区数: 7,624,704
可用扇区: 7,608,320
第一数据扇区: 16,384
字节/扇区: 512
字节/簇: 4,096
剩余簇: 951,038 = 100% 空闲
总计簇: 951,040
FAT1 = FAT2
于是,配合 znFAT 的两个结构体,就可以理解 MBR的内容了。
结构体都是用的 UINT8,不只这两个结构用UINT8,大部分znFAT的结构都使用UINT8 变量。原因是因为 大端和小端变换。
所以,MBR使用了两个结构体表达,MBR结构体 代表了 整个扇区,DPT_Item 代表 了其中的 分区记录。
怎样读取,书上给了部分代码示意,其实MBR的作用主要是引出 DBR,所以在 znFAT 只 初始化时出现。
*****************************
更重要的DBR (对于第六章)
DBR重要的原因是母凭子贵,它有BPB
可以看出,BPB 包含可以用来定位的信息(相对计算)
在初始化函数中,涉及到的计算大多和BPB有关,例如:
要找到FAT表,找到首目录,都需要 BPB 中的数据来定位。
书上除了使用WinHex 分析外,还讲了利用这些知识识别 假U 盘。
书上的DBR结构体代码主要是示意,用来理解DBR还是适合的。
不过,要注意:
UINT32 BPB_Sector_No; //DBR(BPB)所在扇区号
UINT32 Total_SizeKB; //磁盘的总容量,单位为KB
UINT32 BytesPerSector; //每个扇区的字节数
可以利用MBR计算出
UINT32 FATsectors; //FAT表所占扇区数
UINT32 SectorsPerClust; //每簇的扇区数
UINT32 FirstFATSector; //第一个FAT表所在扇区
UINT32 FirstDirSector; //第一个目录所在扇区
可以利用 BPB 计算出
UINT32 FSINFO_Sec; //FSINFO扇区所在的扇区 UINT32Free_nCluster; //空闲簇的个数 UINT32Next_Free_Cluster; //下一空簇 FSINFO的信息还要利用 FSINFO 扇区才行。
先不加入FSINFO,初始化函数就可以写出来了,
struct znFAT_Init_Args *pInit_Args; //初始化参数结构体指针,用以指向某一存储设备的初始化参数集合
UINT8 znFAT_Init(void)
{
struct DBR *pdbr;
znFAT_Device_Read_Sector(MBR_SECTOR,znFAT_Buffer);
if(znFAT_Buffer[0]!=DBR_MARK) //检测0扇区是否为DBR扇区
{
pInit_Args->BPB_Sector_No=Bytes2Value(((((struct MBR *)(znFAT_Buffer))->Part[0]).StartLBA),4);
}
else
{
pInit_Args->BPB_Sector_No=0;
}
znFAT_Device_Read_Sector((pInit_Args->BPB_Sector_No),znFAT_Buffer); //读取DBR扇区
pdbr=(struct DBR *)znFAT_Buffer;
if(!IS_FAT32_TYPE((pdbr->BS_FilSysType1))) return FSTYPE_NOT_FAT32; //FAT32文件系统类型检验
pInit_Args->FATsectors =Bytes2Value((pdbr->BPB_FATSz32) ,4);//装入FAT表占用的扇区数到FATsectors中
pInit_Args->BytesPerSector =Bytes2Value((pdbr->BPB_BytesPerSec),2);//装入每扇区字节数到BytesPerSector中
pInit_Args->SectorsPerClust =pdbr->BPB_SecPerClus;//装入每簇扇区数到SectorsPerClust 中
pInit_Args->FirstFATSector =Bytes2Value((pdbr->BPB_RsvdSecCnt) ,2)+pInit_Args->BPB_Sector_No;//装入第一个FAT表扇区号到FirstFATSector 中
pInit_Args->FirstDirSector =(pInit_Args->FirstFATSector)+(pdbr->BPB_NumFATs)*(pInit_Args->FATsectors); //装入第一个目录扇区到FirstDirSector中
pInit_Args->Total_SizeKB =Bytes2Value((pdbr->BPB_TotSec32),4)/2; //磁盘的总容量,单位是KB
}
代码看起来有些复杂,但是逻辑关系是很清楚的。
如上图示意,利用指针把 MBR和DBR 关联起来。 |