📄 fat.c
字号:
#include "fat.h"
#include "mmc.h"
//每扇区的字节数目
unsigned int BlockSize; //每扇区的字节数,一般为512
unsigned long fat_offset; ////FAT1的起始扇区号
unsigned long data_offset; //数据区的起始扇区数,FAT32的根目录区和数据区重合:
unsigned char FatFlags; //FAT类型:FAT32,FAT16,FAT12
unsigned long blocknow;
unsigned char SecPerClus; //每个簇占用的扇区数目,1GB的SD卡应为8
unsigned char *pointer_FDT;
unsigned long FirstRootDirSecNum; //根目录区(FDT)的起始扇区号
unsigned int old_pos_a=0;
unsigned long old_pos_blk;
const unsigned char Search_FileExName1[3]={'M','P','3'}; //要查找的是TXT文件,可以改成其它的
//############################################################################
//从BPB中获取根目录区的起始地址,同时判断FAT制式(判定方法不可靠,不是微软推荐的)
unsigned long fat_root_dir_addr(unsigned char *buff)
//############################################################################
{
struct BootSec *bootp; //FAT16 BPB
struct BootSec32 *bootp32; //FAT32 BPB
unsigned int VBRadd; //DBR起始扇区号,在它之前都是磁盘分区信息占用的扇区数目
MMC_SD_ReadSingleBlock(BIOS_PARAMETER_BLOCK,buff); //读取BPB/MBR
if(buff[0] != 0xEB || buff[0] != 0xE9) //buff[0]!=0xEB,0xE9,this is mbr //我们的SD卡应该是这一种
{
VBRadd = buff[VBR_ADDR] + (buff[VBR_ADDR + 1])*256; //real BPB address
}
else // buff[0]==0xEB,mbr和DBR相同,都是从0扇区开始
{
VBRadd = 0;
}
MMC_SD_ReadSingleBlock(VBRadd,buff); //重新再读取DBR
bootp=(struct BootSec *)buff; //Fat16 的BPB
bootp32=(struct BootSec32 *)buff; //Fat32 的BPB
if(bootp->BPB_RootEntCnt == 0) //根据根目录下面项目数为0,确定是FAT32
{
BlockSize=bootp32->BPB_BytesPerSec; //获取每扇区字节数目
FatFlags = FAT_Flg_32; //Fat32文件系统
fat_offset = bootp32->BPB_RsvdSecCnt + VBRadd; //FAT1的起始扇区号
//根目录区(FDT)的起始扇区号=保留扇区+FAT占用扇区:
FirstRootDirSecNum=VBRadd+(bootp32->BPB_RsvdSecCnt+(bootp32->BPB_NumFATs*bootp32->BPB_FATSz32));
SecPerClus = bootp32->BPB_SecPerClus; //每个簇占用的扇区数目,SD卡应为8
//数据区的起始扇区数,FAT32的根目录区和数据区重合:
data_offset = FirstRootDirSecNum;
}
else //FAT16或者FAT12文件系统
{
BlockSize=bootp->BPB_BytesPerSec; //获取每扇区字节数目
if(bootp->BPB_SysID[4] == '2') //根据扩展FAT12/FAT16的系统ID部分,判断
FatFlags = FAT_Flg_12; //FAT12
else
FatFlags = FAT_Flg_16; //FAT16
fat_offset = bootp->BPB_RsvdSecCnt + VBRadd;
//根目录区(FDT)的起始扇区号=保留扇区+FAT占用扇区:
FirstRootDirSecNum=VBRadd+(bootp->BPB_RsvdSecCnt+(bootp->BPB_NumFATs*bootp->BPB_FATSz16));
SecPerClus = bootp->BPB_SecPerClus; //每个簇占用的扇区数目,SD卡应为8
//数据区的起始扇区数,FAT16/FAT12的根目录,一般占用32个扇区的大小:
data_offset = FirstRootDirSecNum + 32;
}
return(FirstRootDirSecNum); //返回根目录区的起始扇区号
}
//############################################################################
//解析FAT链表
void fat_load(unsigned long Cluster, //文件起始扇区
unsigned long *Block, //返回文件下一扇区
unsigned char *TMP_Buffer) //函数所需buffer
//############################################################################
{
unsigned int FAT_Byte_Addresse;
unsigned long FAT_Block_Addresse;
//读取FAT表,根据FAT制式搜寻扇区
if(FatFlags == FAT_Flg_16)
{
if(Cluster == 0xFFFF)
{
return; //文件已经到达末尾
}
FAT_Byte_Addresse = ((Cluster<<1) & 0x1FF);
FAT_Block_Addresse = ((Cluster<<1)/BlockSize) + fat_offset;
MMC_SD_ReadSingleBlock(FAT_Block_Addresse,TMP_Buffer);
*Block = (TMP_Buffer[FAT_Byte_Addresse + 1] << 8) + TMP_Buffer[FAT_Byte_Addresse];
if(*Block == 0xFFFF)
*Block = 0xFFFFFFFF;
}
else if(FatFlags == FAT_Flg_12)
{
if(Cluster == 0xFFF)
{
return; //文件已经到达末尾
}
FAT_Byte_Addresse = (((Cluster*3)>>1) & 0x1FF);
FAT_Block_Addresse = (((Cluster*3)>>1) / BlockSize) + fat_offset;
if(FAT_Byte_Addresse == 0x1FF)
{
MMC_SD_ReadSingleBlock(FAT_Block_Addresse,TMP_Buffer);
if((Cluster % 2) == 0)
{
*Block = TMP_Buffer[FAT_Byte_Addresse];
}
else
{
*Block = (TMP_Buffer[FAT_Byte_Addresse] >> 4);
}
MMC_SD_ReadSingleBlock(FAT_Block_Addresse+1,TMP_Buffer);
if((Cluster % 2) == 0)
{
*Block += ((TMP_Buffer[0] & 0x0F) << 8);
}
else
{
*Block += (TMP_Buffer[0] << 4);
}
}
else
{
MMC_SD_ReadSingleBlock(FAT_Block_Addresse,TMP_Buffer);
if((Cluster % 2) == 0)
{
*Block = ((TMP_Buffer[FAT_Byte_Addresse + 1] & 0x0F) << 8) + TMP_Buffer[FAT_Byte_Addresse];
}
else
{
*Block = (TMP_Buffer[FAT_Byte_Addresse + 1] << 4) + (TMP_Buffer[FAT_Byte_Addresse] >> 4);
}
}
if(*Block == 0xFFF)
*Block = 0xFFFFFFFF;
}
else if(FatFlags == FAT_Flg_32)
{
unsigned long Tmp;
Tmp=Cluster/128;
if(Cluster == 0xFFFFFFFF)
{
*Block = 0xFFFFFFFF;
return; //文件已经到达末尾
}
FAT_Byte_Addresse = (Cluster*4)%512;
FAT_Block_Addresse = Tmp + fat_offset ;
MMC_SD_ReadSingleBlock (FAT_Block_Addresse,TMP_Buffer);
//测试使用:
//DisplayHexNum(1,1,TMP_Buffer[FAT_Byte_Addresse+3]);
//DisplayHexNum(2,1,TMP_Buffer[FAT_Byte_Addresse+2]);
//DisplayHexNum(3,1,TMP_Buffer[FAT_Byte_Addresse+1]);
//DisplayHexNum(4,1,TMP_Buffer[FAT_Byte_Addresse]);
//Delay(1000);
//
*Block = (TMP_Buffer[FAT_Byte_Addresse+3]*(unsigned long)16777216) +
(TMP_Buffer[FAT_Byte_Addresse+2]*(unsigned long)65536) +
(TMP_Buffer[FAT_Byte_Addresse+1]*(unsigned long)256) +
TMP_Buffer[FAT_Byte_Addresse];
}
return;
}
//############################################################################
//读取文件目录区FDT相关信息,错误的时候返回0xffffffff,目录搜索完毕,返回0xFFFFFFFE
unsigned long fat_read_dir_ent(unsigned long dir_cluster,//目录所在簇
unsigned int Entry_Count, //目录中文件序号
unsigned long *Size, //文件长度
unsigned char *Dir_Attrib, //文件属性
unsigned char *buff) //函数所需buffer
//############################################################################
{
unsigned int TMP_Entry_Count = 0;
unsigned long Block=0; //目录所在扇区地址
unsigned long blk;
unsigned int a;
struct DirEntry *dir; //文件目录指针
if (dir_cluster == 0) //读取根目录,得到FDT起始扇区号
{
Block = FirstRootDirSecNum;
}
else //读取子目录,本程序中用不到
{
Block = (dir_cluster-2)*SecPerClus+data_offset;
}
//下面的算法效率有问题。注意它每次都是从根目录下面依次去找第Entry_Count个文件
//for (blk = old_pos_blk;;blk++)
for (blk = Block;;blk++) //从该目录下面,依次读取一个扇区
{
MMC_SD_ReadSingleBlock(blk,buff);
Next_a:
//for (a=old_pos_a;a<BlockSize; a = a + 32)
for (a=0;a<BlockSize; a = a + 32) //依次分析每一个32字节的目录/文件结构
{ //依次分析每一个文件或目录,可能会出现空的、已删除、正常的目录/文件
dir=(struct DirEntry *)(buff + a); //装载目录内容
if (dir->DIR_Name[0] == 0) //目录已经搜索完毕,返回.
{
return (0xFFFFFFFE);
}
//非卷标,非长文件名,并且文件没有删除
if ((dir->DIR_Attr != ATTR_LONG_NAME) && (dir->DIR_Attr != DIR_ATTRIB_VOL_ID) && (dir->DIR_Name[0] != DIR_ENTRY_IS_FREE))
{
//搜索字库文件:
if(Entry_Count==0 && dir->DIR_Name[2] == 'F' && dir->DIR_Name[3] == 'O' && dir->DIR_Name[4] == 'N' && dir->DIR_Name[5] == 'T' && dir->DIR_Name[6] == '1' && dir->DIR_Name[7] == '6')
{
pointer_FDT=buff + a;
*Dir_Attrib = dir->DIR_Attr;
//文件长度
*Size=dir->DIR_FileSize;
//文件起始簇的低16位
dir_cluster = dir->DIR_FstClusLO + (dir->DIR_FstClusHI)*65536;
//返回起始簇
return(dir_cluster);
}
//搜索mp3文件:
else if(dir->DIR_Name[8] == Search_FileExName1[0] && dir->DIR_Name[9] == Search_FileExName1[1] && dir->DIR_Name[10] == Search_FileExName1[2]) //找到要搜索的文件
{
TMP_Entry_Count++;
//找寻第Entery_Count个指定文件
if (TMP_Entry_Count == Entry_Count)
{
pointer_FDT=buff + a;
*Dir_Attrib = dir->DIR_Attr;
//文件长度
*Size=dir->DIR_FileSize;
//文件起始簇的低16位
dir_cluster = dir->DIR_FstClusLO + (dir->DIR_FstClusHI)*65536;
/*
if((a+32)<512) //判断是否该搜索下一个扇区的目录文件信息了
{
old_pos_a=a+32;
old_pos_blk=blk;
}
else //到下一扇区寻找
{
old_pos_a=0;
old_pos_blk=blk+1;
}
*/
//返回起始簇
return(dir_cluster);
}
}
}
}
}
return (0xFFFFFFFF); //目录本身有错误,返回0xFFFF
}
//############################################################################
//读取文件内容每次512bytes,文件没有读完,返回0;否则为1
unsigned char fat_read_file(unsigned long Cluster, //文件起始簇号
unsigned char *buff, //文件内容缓冲区
unsigned long BlockCount, //扇区号
unsigned char *blockserial)
//############################################################################
{
unsigned long Block;
static unsigned char serial=0;
if(BlockCount == 0)
{
fat_load(Cluster,&Block,buff);
//测试使用
//DisplayLong(Block,1);
MMC_SD_ReadSingleBlock((Cluster-2)*SecPerClus+data_offset+serial,buff);
serial++;
blocknow = Cluster;
*blockserial = SecPerClus-serial;
if(serial == SecPerClus)
serial = 0;
}
else
{
fat_load(blocknow,&Block,buff);
MMC_SD_ReadSingleBlock((blocknow-2)*SecPerClus+data_offset+serial,buff);
serial++;
*blockserial = SecPerClus-serial;
if(serial == SecPerClus)
serial = 0;
}
if(serial == 0)
blocknow = Block;
if(blocknow == 0xFFFFFFFF)
return 1;
else
return 0;
}
unsigned char strscmp(unsigned char *src,unsigned char *dist)
{
while(*src)
{
if((*src) != (*dist))
{
if((*src) > (*dist))
return 1;
else
return 2;
}
src++;
dist++;
}
return 0;
}
//####################################################################################
//Sucht ein File im Directory
unsigned char fat_search_file (unsigned char *File_Name, //要查找的文件名
unsigned long *Cluster, //要查找的文件所在簇
unsigned long *Size, //查到的文件大小
unsigned char *Dir_Attrib,//查到的文件属性
unsigned char *buff) //查到的文件名称
//####################################################################################
{
unsigned int Dir_Cluster_Store = *Cluster;
unsigned char a;
for (a = 0;a < 100;a++)
{
*Cluster = fat_read_dir_ent(Dir_Cluster_Store,a,Size,Dir_Attrib,buff);
if (*Cluster == 0xffff)
{
return(0); //File not Found
}
if(strscmp(File_Name,buff) == 0)
{
return(1); //File Found
}
}
return(2); //Error
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -