单片机读取FLASHWord格式.docx

上传人:b****3 文档编号:17824130 上传时间:2022-12-11 格式:DOCX 页数:20 大小:215.65KB
下载 相关 举报
单片机读取FLASHWord格式.docx_第1页
第1页 / 共20页
单片机读取FLASHWord格式.docx_第2页
第2页 / 共20页
单片机读取FLASHWord格式.docx_第3页
第3页 / 共20页
单片机读取FLASHWord格式.docx_第4页
第4页 / 共20页
单片机读取FLASHWord格式.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

单片机读取FLASHWord格式.docx

《单片机读取FLASHWord格式.docx》由会员分享,可在线阅读,更多相关《单片机读取FLASHWord格式.docx(20页珍藏版)》请在冰豆网上搜索。

单片机读取FLASHWord格式.docx

每簇扇区数

13

RsvdSecCnt

保留扇区数目

14

NumFATs

此卷中FAT表数

16

RootEntCnt

FAT32为0

17

TotSec16

19

Media

存储介质

21

FATSz16

22

SecPerTrk

磁道扇区数

24

NumHeads

磁头数

26

HiddSec

4

FAT区前隐扇区数

28

TotSec32

该卷总扇区数

32

FATSz32

FAT表扇区数

36

ExtFlags

FAT32特有

40

FSVer

42

RootClus

根目录簇号

44

FSInfo

文件系统信息

48

BkBootSec

通常为6

50

Reserved

12

扩展用

52

DrvNum

64

Reserved1

65

BootSig

66

VolID

67

FilSysType

71

FilSysType1

82

      DBR的实现代码:

structFAT32_DBR

{

unsignedcharBS_jmpBoot[3];

//跳转指令offset:

0

unsignedcharBS_OEMName[8];

//offset:

3

unsignedcharBPB_BytesPerSec[2];

//每扇区字节数offset:

unsignedcharBPB_SecPerClus[1];

//每簇扇区数offset:

unsignedcharBPB_RsvdSecCnt[2];

//保留扇区数目offset:

unsignedcharBPB_NumFATs[1];

//此卷中FAT表数offset:

unsignedcharBPB_RootEntCnt[2];

//FAT32为0offset:

unsignedcharBPB_TotSec16[2];

unsignedcharBPB_Media[1];

//存储介质offset:

unsignedcharBPB_FATSz16[2];

unsignedcharBPB_SecPerTrk[2];

//磁道扇区数offset:

unsignedcharBPB_NumHeads[2];

//磁头数offset:

unsignedcharBPB_HiddSec[4];

//FAT区前隐扇区数offset:

unsignedcharBPB_TotSec32[4];

//该卷总扇区数offset:

unsignedcharBPB_FATSz32[4];

//一个FAT表扇区数offset:

unsignedcharBPB_ExtFlags[2];

//FAT32特有offset:

unsignedcharBPB_FSVer[2];

unsignedcharBPB_RootClus[4];

//根目录簇号offset:

unsignedcharFSInfo[2];

//保留扇区FSINFO扇区数offset:

unsignedcharBPB_BkBootSec[2];

//通常为6offset:

unsignedcharBPB_Reserved[12];

//扩展用offset:

unsignedcharBS_DrvNum[1];

//offset:

unsignedcharBS_Reserved1[1];

unsignedcharBS_BootSig[1];

unsignedcharBS_VolID[4];

unsignedcharBS_FilSysType[11];

//  offset:

unsignedcharBS_FilSysType1[8];

//"

FAT32"

offset:

};

      在程序中我们采用以上的结构体指针对扇区数据指针进行转化,就可以直接读取数据中的某一字段,如要读取BPB_BytesPerSec,可以这样来作:

      ((structFAT32_DBR*)pSector)->

BPB_BytesPerSec

用如上语句就可以得到这一字段的首地址。

心细的读者可能会发现读回来的字节拼在一起,与实际的数据并不吻合。

例如BPB_BytesPerSec读出来的内容是“0002”,在程序中我们把00作为int型变量的高字节,把02作为其低字节,那么这个变量的值为2,而实际的SD卡里的扇区大小为512个字节,这512与2之间相去甚远。

是什么造成这种现象的呢?

这就是大端模式与小端模式在作怪。

上面我们合成int型变量的方法(00为高字节,02为低字节)为小端模式。

而如果我们改用大端模式来进行合成的话,结果就会不同:

将02作高字节,而把00作低字节,变量值就成了0x0200(十进制的512),这样就和实际数据吻合了。

可见FAT32中字节的排布是采用小端模式的。

在我们程序中需要将它转为大端模式的表达方式。

在笔者的程序有这样一个函数lb2bb,专门将小端模式转为大端模式,程序如下:

unsignedlonglb2bb(unsignedchar*dat,unsignedcharlen)//小端转为大端

unsignedlongtemp=0;

unsignedlongfact=1;

unsignedchari=0;

for(i=0;

i<

len;

i++)

{

temp+=dat[i]*fact;

fact*=256;

}

returntemp;

}

这样就可以从BPB中读出关于磁盘的各种参数信息,为我们后面的工作作准备。

而这个从BPB中读取参数装入到参数表中以备后用的过程就是FAT32的初始化了。

具体的实现如下:

先定义用来装入从BPB中读取的参数的结构:

structFAT32_Init_Arg

unsignedcharBPB_Sector_No;

//BPB所在扇区号

unsignedlongTotal_Size;

//磁盘的总容量

unsignedlongFirstDirClust;

//根目录的开始簇

unsignedlongFirstDataSector;

//文件数据开始扇区号

unsignedintBytesPerSector;

//每个扇区的字节数

unsignedintFATsectors;

//FAT表所占扇区数

unsignedintSectorsPerClust;

//每簇的扇区数

unsignedlongFirstFATSector;

//第一个FAT表所在扇区

unsignedlongFirstDirSector;

//第一个目录所在扇区

unsignedlongRootDirSectors;

//根目录所占扇区数

unsignedlongRootDirCount;

//根目录下的目录与文件数

当然也可以用零散的变量来存储参数,但用结构体更方便管理,也会使程序更为整洁。

FAT32的初始化将向结构中装入参数,实现如下:

voidFAT32_Init(structFAT32_Init_Arg*arg)

structFAT32_BPB*bpb=(structFAT32_BPB*)(FAT32_Buffer);

//将数据缓冲区指针转为structFAT32_BPB型指针

arg->

BPB_Sector_No=FAT32_FindBPB();

//FAT32_FindBPB()可以返回BPB所在的扇区号

Total_Size=FAT32_Get_Total_Size();

//FAT32_Get_Total_Size()可以返回磁盘的总容量,单位是兆

FATsectors=lb2bb((bpb->

BPB_FATSz32),4);

//装入FAT表占用的扇区数到FATsectors中

FirstDirClust=lb2bb((bpb->

BPB_RootClus),4);

//装入根目录簇号到FirstDirClust中

BytesPerSector=lb2bb((bpb->

BPB_BytesPerSec),2);

//装入每扇区字节数到BytesPerSector中

SectorsPerClust=lb2bb((bpb->

BPB_SecPerClus),1);

//装入每簇扇区数到SectorsPerClust中

arg->

FirstFATSector=lb2bb((bpb->

BPB_RsvdSecCnt),2)+arg->

BPB_Sector_No;

//装入第一个FAT表扇区号到FirstFATSector中

RootDirCount=lb2bb((bpb->

BPB_RootEntCnt),2);

//装入根目录项数到RootDirCount中

RootDirSectors=(arg->

RootDirCount)*32>

>

9;

//装入根目录占用的扇区数到RootDirSectors中

FirstDirSector=(arg->

FirstFATSector)+(bpb->

BPB_NumFATs[0])*(arg->

FATsectors);

//装入第一个目录扇区到FirstDirSector中

FirstDataSector=(arg->

FirstDirSector)+(arg->

RootDirSectors);

//装入第一个数据扇区到FirstDataSector中

3)FAT(文件分配表)

FAT表是FAT32文件系统中用于磁盘数据(文件)索引和定位引进的一种链式结构。

可以说FAT表是FAT32文件系统最有特色的一部分,它的链式存储机制也是FAT32的精华所在,也正因为有了它才使得数据的存储可以不连续,使磁盘的功能发挥得更为出色。

FAT表到底在什么地方?

它到底是什么样子的呢?

从第一步从BPB中提取参数中的FirstFATSector就可以知道FAT表所在的扇区号。

其实每一个FAT表都有另一个与它一模一样的FAT存在,并且这两个FAT表是同步的,也就是说对一个FAT表的操作,同样地,也应该在另一个FAT表进行相同的操作,时刻保证它们内容的一致。

这样是为了安全起见,当一个FAT因为一些原因而遭到破坏的时候,可以从另一个FAT表进行恢复。

FAT表的内容如下图所示:

上图就是一个实际的FAT表。

前8个字节“F8FFFF0FFFFFFFFF”为FAT32的FAT表头标记,用以表示此处是FAT表的开始。

后面的数据每四个字节为一个簇项(从第2簇开始),用以标记此簇的下一个簇号。

拿我们创建的那个叫TEST.TXT(大小为20个字节)的文件来说,如果这个文件的开始簇为第2簇的话,那么就到FAT表里来查找,看文件是否有下一个簇(如果文件大小大于一个簇的容量,必须会有数据存储到下一个簇,但下一个簇与上一个簇不一定是连续的),可以看到“簇2”的内容为“FFFFFF0F”,这样的标记就说明这个文件到第2簇就已经结束了,没有后继的簇,即此文件的大小是小于一个簇的容量的。

上面讲了很多,都是围绕簇这样一个词来讲的,簇又是什么?

为什么要将它引入到FAT32里来呢?

磁盘上最小可寻址存储单元称为扇区,通常每个扇区为512个字节。

由于多数文件比扇区大得多,因此如果对一个文件分配最小的存储空间,将使存储器能存储更多数据,这个最小存储空间即称为簇。

根据存储设备(磁盘、闪卡和硬盘)的容量,簇的大小可以不同以使存储空间得到最有效的应用。

在早期的360KB磁盘上,簇大小为2个扇区(1,024字节);

第一批的10MB硬盘的簇大小增加到8个扇区(4,096字节);

现在的小型闪存设备上的典型簇大小是8KB或16KB。

2GB以上的硬盘驱动器有32KB的簇。

如果对于容量大的存储定义了比较小的簇的话,就会使FAT表的体积很大,从而造成数据的冗余和效率的下降。

需要指出的是,簇作为FAT32进行数据存储的最小单位,内部扇区是不能进一步细分的,即使一个文件的数据写到一个簇中后,簇中还有容量的剩余(里部扇区没有写满),哪怕这个簇只写了一个字节,其它文件的数据也是不能接在后面继续数据的,而只能另外找没有被占用的簇。

我们按照初始化参数表中的SectorsPerClust可以知道一个簇中的扇区数,笔者的SD卡实测簇大小为4个扇区,按照上面的说法,TEST.TXT这样一个只有20个字节的文件,也会占用一个簇的容量,让我们在Windows里看看它的实际占用空间的情况。

从上图可以看到文件大小为20个字节,但占用空间却是2048个字节(一个簇的容量,4个扇区)。

TEST.TXT容量只有20个字节,所以只占用了一个簇,可能FAT表中还看不出链式结构,现在我们再创建一个文件,使它占用26个簇,如下:

 

             

可以看到图中红色标记的就是文件所占用的26个簇。

从第4簇开始,簇项4的内容为“05000000”(小端模式),说明下一个簇为第5簇,而簇项5的内容为“06000000”,说明下一个簇为第6簇……依此类推,直到内容为“FFFFFF0F”,说明无后继簇,文件数据到此结束。

FAT表中的链式存储结构已经非常明显。

把我们从FAT表中分析的结果与Windows的统计结束进行对比,说明我们的解理是正确的,如下图:

从上面可以看到,当数据结束于某一簇时,FAT32就用“FFFFFF0F”来对其进行标记。

其实还有其实的标记以表达其它的簇属性,如“00000000”表示未分配的簇,“FFFFFFF7”表示坏簇等。

        给出一个簇号,计算出它的后继簇号,是实现FAT32的重点,实现如下:

unsignedlongFAT32_GetNextCluster(unsignedlongLastCluster)

unsignedlongtemp;

structFAT32_FAT*pFAT;

structFAT32_FAT_Item*pFAT_Item;

temp=((LastCluster/128)+Init_Arg.FirstFATSector);

//计算给定簇号对应的簇项的扇区号

FAT32_ReadSector(temp,FAT32_Buffer);

pFAT=(structFAT32_FAT*)FAT32_Buffer;

pFAT_Item=&

((pFAT->

Items)[LastCluster%128]);

  

//在算出的扇区中提取簇项

returnlb2bb(pFAT_Item,4);

  //返回下一簇号

那么FAT表有多大呢?

FAT表中每四个字节表示一个簇,所以FAT表的大小由实际的簇数来决定。

从这里也可以看出,如果簇过大,则FAT表比较小,但会造成空间的浪费,而如果簇过小,可以减小空间的浪费,但会使FAT表变得臃肿。

FAT表的大小也可以从BPB参数FATsectors读出。

从上面的BPB图可以得知笔者的SD卡的FAT表大小为958个扇区(“BE 03 00 00”的大端表示)。

如果这958个扇区每四个字节都表示一个簇项,则它可以表示(958*512/4)-2=122622个簇(减去2是因为有8个字节的FAT表头标识。

        看看我们计算的是否正确呢,下面是Winhex计算出来的簇数:

        与Winhex计算的结果是吻合的,我们对FAT表与簇的理解是正确的。

        看完上面对FAT表的讲解中,你可能会问:

一个文件数据的首簇号怎样来确定呢?

只有知道了一个文件数据的首簇号才能继续查找下一簇数据的位置,直到数据结束。

下面将要讲到的“根目录区”就可以由一个文件的文件名来查到它的首簇。

    4)根目录区

        在FAT32中其实已经把文件的概念进行扩展,目录同样也是文件,从根目录的地位与其它目录是相同的,因此根目录也被看作是文件。

既然是文件就会有文件名,根目录的名称就是磁盘的卷标。

如笔者的SD卡在格式会时设置卷标为znmcu,则根目录的名称就为ZNMCU,如下图:

        每一个文件都对应一个描述它属性的结构,定义如下:

FAT32文件目录项32个字节的定义

字节偏移量

字数量

定义

0~7

文件名

8~10

扩展名

属性字节 

0x00(读写)

0x01(只读)

0x02(隐藏)

0x04(系统)

0x08(卷标)

0x10(子目录)

0x20(归档)

系统保留

创建时间的10毫秒位

14~15

文件创建时间

16~17

文件创建日期

18~19

文件最后访问日期

20~21

文件起始簇号的高16位

22~23

文件的最近修改时间

24~25

文件的最近修改日期

26~27

文件起始簇号的低16位

28~31

表示文件的长度

根目录区所在扇区可从BPB参数FirstDirSector获取,从BPB图得FirstDirSector=FirstFATSector+BPB_NumFATs*FATsectors=2053。

根目录区的初始大小为一个簇,实际的内容如下:

        图中的记录1描述根目录,前八个字节为文件名“ZNMCU”(长度小于8的部分用空格符补齐),下面的三个字节为扩展名“”(长度小于3的部分用空格符补齐),08表示此文件为卷标,开始簇高字节为00 00,低字节为00 00,开始簇为0,文件长度为0。

        记录2描述TEST.TXT文件,文件名为“TEST”,扩展名为“TXT”,20表示此文件为归档,开始簇为3(“00 00 00 03”),长度为20。

        记录3描述BIGTEST.TXT文件,文件名为“BIGTES~1”,扩展名为“TXT”,开始簇为4,长度为5200字节(00 00 CB 20)。

        可以看到FAT32中的文件名都以大写字母表示,长度不足的部分用空格符补齐,所以我们要读取的文件TEST.TXT就变成了“TEST.TXT”,这将有助于文件名的匹配,我们不用去处理不等长文件名所带来的麻烦。

另外,还会发现长度过长的部分会被~1所替换,如果替换后有文件与之重名,则~后面的数字将增加为2。

      

        文件目录项结构的实现如下:

structdirentry

unsignedchardeName[8];

//文件名

unsignedchardeExtension[3];

//扩展名

unsignedchardeAttributes;

//文件属性

unsignedchardeLowerCase;

//系统保留

unsignedchardeCHundredth;

//创建时间的10毫秒位

unsignedchardeCTime[2];

//文件创建时间

unsignedchardeCDate[2];

//文件创建日期

unsignedchardeADate[2];

//文件最后访问日期

unsignedchardeHighClust[2];

//文件起始簇号的高16位

unsignedchardeMTime[2];

//文件的最近修改时间

unsignedchardeMDate[2];

//文件的最近修改日期

unsignedchardeLowCluster[2];

// 文件起始簇号的低16位

unsignedchardeFileSize[4];

//表示文件的长度

        我们最终要实现的是对TEST.TXT文件的读取,须要作到给定文件名后,可以得到相应文件的首簇。

主要的思想就是对根目录区中(本实例只针对根目录中的文件进行

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1