⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat.c

📁 采用Mega16+VS1011B+SD卡制作的Mp3
💻 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 + -