fat32.c
来自「用MEGA16驱动SD卡」· C语言 代码 · 共 281 行
C
281 行
#include <mega16.h>
#include "SD.c"
/*----------------------数据类型定义-----------------------*/
#define uint8 unsigned char //8位无符号整数
#define uint16 unsigned int //16位无符号整数
#define uint32 unsigned long int //32位无符号整数
#define FIND_UP_RANGE 128
//定义根目录下最大的文件名描述项
//根目录占据一个簇的大小,每个目录或者文件用32个字节描述
//所以目录加文件的描述项一般就是128个
//8*512/32=128
uint8 BUFF[512];
uint8 table[10]={'0','1','2','3','4','5','6','7','8','9'};
/*----------------记录FAT表中簇项-----------*/
//每四个字节一个簇项
//一个扇区中有128个簇项 128=512/4
struct FAT32_FAT_Item
{
uint8 Item[4];
};
struct FAT32_FAT
{
struct FAT32_FAT_Item Items[128];
};
/*----FAT32中对BPB的定义如下 一共占用90个字节--*/
struct FAT32_BPB
{
uint8 BS_jmpBoot[3]; //跳转指令 offset: 0
uint8 BS_OEMName[8]; // offset: 3
uint8 BPB_BytesPerSec[2];//每扇区字节数 offset:11
uint8 BPB_SecPerClus[1]; //每簇扇区数 offset:13
uint8 BPB_RsvdSecCnt[2]; //保留扇区数目 offset:14
uint8 BPB_NumFATs[1]; //此卷中FAT表数 offset:16
uint8 BPB_RootEntCnt[2]; //FAT32为0 offset:17
uint8 BPB_TotSec16[2]; //FAT32为0 offset:19
uint8 BPB_Media[1]; //存储介质 offset:21
uint8 BPB_FATSz16[2]; //FAT32为0 offset:22
uint8 BPB_SecPerTrk[2]; //磁道扇区数 offset:24
uint8 BPB_NumHeads[2]; //磁头数 offset:26
uint8 BPB_HiddSec[4]; //FAT区前隐扇区数 offset:28
uint8 BPB_TotSec32[4]; //该卷总扇区数 offset:32
uint8 BPB_FATSz32[4]; //一个FAT表扇区数 offset:36
uint8 BPB_ExtFlags[2]; //FAT32特有 offset:40
uint8 BPB_FSVer[2]; //FAT32特有 offset:42
uint8 BPB_RootClus[4]; //根目录簇号 offset:44
uint8 FSInfo[2]; //保留扇区FSINFO扇区数offset:48
uint8 BPB_BkBootSec[2]; //通常为6 offset:50
uint8 BPB_Reserved[12]; //扩展用 offset:52
uint8 BS_DrvNum[1]; // offset:64
uint8 BS_Reserved1[1]; // offset:65
uint8 BS_BootSig[1]; // offset:66
uint8 BS_VolID[4]; // offset:67
uint8 BS_FilSysType[11]; // offset:71
uint8 BS_FilSysType1[8]; //"FAT32 " offset:82
};
struct FAT32_INI_ARG//FAT32初始化基本信息
{
uint16 BytesPerSec;//一个扇区的字节数
uint8 SecPerClus;//一个簇的扇区数
uint16 RsvdSecCnt;//保留扇区数
uint8 NumFATs;//FAT表的数目
uint32 FATSz32; //FAT表的扇区数
uint32 FirstFatAddr;//第一个FAT表地址
uint32 RootDirAddr;//根目录地址----也是第二簇的地址
}Fat_Info;
/*--------------------------目录或文件定义---------------------*/
struct direntry
{
uint8 deName[8]; // 文件名
uint8 deExtension[3]; // 扩展名
uint8 deAttributes; // 文件属性
uint8 deLowerCase; // 系统保留
uint8 deCHundredth; // 创建时间的10 毫秒位
uint8 deCTime[2]; // 文件创建时间
uint8 deCDate[2]; // 文件创建日期
uint8 deADate[2]; // 文件最后访问日期
uint8 deHighClust[2]; // 文件起始簇号的高16 位
uint8 deMTime[2]; // 文件的最近修改时间
uint8 deMDate[2]; // 文件的最近修改日期
uint8 deLowCluster[2];// 文件起始簇号的低16 位
uint8 deFileSize[4]; // 表示文件的长度
};
/*-----------------------被读取文件的信息-----------------*/
struct File_Arg
{
uint8 FileName[12]; //文件名 包括扩展名前的 " . "
uint32 FileStartCluster; //文件首簇号
uint32 FileCurCluster; //文件当前簇号
uint32 FileNextCluster; //下一簇号
uint32 FileSize; //文件大小
uint8 FileAttr; //文件属性
uint8 FileCreateTime; //文件建立时间
uint8 FileCreateDate; //文件建立日期
uint8 FileMTime; //文件修改时间
uint8 FileMDate; //文件修改日期
uint32 FileSector; //文件当前扇区
uint16 FileOffset; //文件偏移量
}File_Info;
uint32 lb2bb(uint8 *dat,uint8 len) //小端转为大端
{
uint32 temp=0;
uint32 fact=1;
uint32 i=0;
for(i=0;i<len;i++)//一个字节对应256
{
temp+=dat[i]*fact;
fact*=256;
}
return temp;
}
uint8 INI_FAT32()//FAT32的初始化函数
{
struct FAT32_BPB *p;
Rbyte_SD(BUFF,0,512);//读出BPB的信息并放在缓冲区间中
p=(struct FAT32_BPB *)BUFF;//转换指针
Fat_Info.BytesPerSec=(uint16)lb2bb((*p)->BPB_BytesPerSec,2);
Fat_Info.SecPerClus=(*p)->BPB_SecPerClus[0];
Fat_Info.RsvdSecCnt=lb2bb((*p)->BPB_RsvdSecCnt,2);
Fat_Info.NumFATs=(*p)->BPB_NumFATs[0];
Fat_Info.FATSz32=lb2bb((*p)->BPB_FATSz32,4);
//第一个FAT表头的地址 = 扇区字节数 x 保留区数
Fat_Info.FirstFatAddr=Fat_Info.BytesPerSec*Fat_Info.RsvdSecCnt;
//根目录地址 = 第一个FAT表头地址 + 两个FAT表长
Fat_Info.RootDirAddr=Fat_Info.FirstFatAddr+Fat_Info.FATSz32*Fat_Info.NumFATs*Fat_Info.BytesPerSec;
/*测试初始化的语句
Rbyte_SD(BUFF,Fat_Info.RootDirAddr,512);
lcd_wdat(table[Fat_Info.BytesPerSec/100]);
lcd_wdat(table[Fat_Info.BytesPerSec/10%10]);
lcd_wdat(table[Fat_Info.BytesPerSec%10]);
lcd_wdat(table[Fat_Info.SecPerClus]);
lcd_wdat(table[Fat_Info.RsvdSecCnt/10]);
lcd_wdat(table[Fat_Info.RsvdSecCnt%10]);
lcd_wdat(table[Fat_Info.NumFATs]);
lcd_wdat(table[Fat_Info.FATSz32/1000]);
lcd_wdat(table[Fat_Info.FATSz32/100%10]);
lcd_wdat(table[Fat_Info.FATSz32/10%10]);
lcd_wdat(table[Fat_Info.FATSz32%10]);
lcd_wdat(BUFF[0]);
lcd_wdat(BUFF[1]);
*/
}
uint8 Compare_File_Name(uint8 *p1,uint8 *p2)
{
//判断文件名是否相等(包括扩展名)
uint8 i,j=8;
uint8 name_temp[12];//用来将输入的文件名转换为标准的文件名
for(i=0;i<11;i++)
name_temp[i]=0x20;//全部输入空格
name_temp[11]=0;//文件属性位为只读
i=0;
while(*p1!='.')
{
name_temp[i++]=*p1++;
}
i++;
p1++;
while(*p1!=0)
{
name_temp[j++]=*p1++;
}
for(i=0;i<11;i++)
{
if(name_temp[i]!=*p2++)
return 0;
}
return 1;
}
struct direntry *Find_File(uint8 *File_Name)
{
struct direntry *p;
uint8 retry=0;
uint8 i;
Rbyte_SD(BUFF,Fat_Info.RootDirAddr,512);//读取根目录的第一个扇区
p=(struct direntry *)BUFF;
while(retry<FIND_UP_RANGE)
{
if((*p)->deName[0]!=0xE5&&(*p)->deName[0]!=0x00&&(*p)->deName[0]!=0x0f)
//判断是否有意义
{
if(Compare_File_Name(File_Name,(*p)->deName)==1)
return p;
}
p++;
retry++;
}
//如果没有找到文件,返回0指针
return 0;
}
uint32 Get_NextCluster(uint32 FileCurCluster)
{
uint32 temp;
temp=((FileCurCluster/128)*512+Fat_Info.FirstFatAddr);
Rbyte_SD(BUFF,temp,512);
return lb2bb(&BUFF[FileCurCluster*4],4);
}
void File_Print()//把数据发送到显示终端上
{;}
uint8 READ_FILE(uint8 *File_Name)
{
uint8 i=0;
uint32 sub;//记录该文件还要多少数据没有读出
uint32 iSectorInCluster=0;//记录读取了一个簇中的扇区数
struct direntry *p;
if((p=Find_File(File_Name))==0)
{
return 0;
}
//---------开始初始化文件信息
for(i=0;i<=7;i++)//文件名
{
File_Info.FileName[i]=(*p)->deName[i];
}
File_Info.FileName[i]='.';
for(i=0;i<=2;i++)//扩展名
{
File_Info.FileName[i]=(*p)->deExtension[i];
}
//文件属性
File_Info.FileAttr=(*p)->deAttributes;
//首簇号
File_Info.FileStartCluster=(lb2bb((*p)->deHighClust,2)<<16)+lb2bb((*p)->deLowCluster,2);
lcd_wdat(table[File_Info.FileStartCluster]);
//测试用的 Rbyte_SD(BUFF,Fat_Info.RootDirAddr+(File_Info.FileStartCluster-0x00000002)*8*512,512);
//当前簇号
File_Info.FileCurCluster=File_Info.FileStartCluster;
//文件大小
File_Info.FileSize=lb2bb((*p)->deFileSize,4);
//文件偏离量
File_Info.FileOffset=0;
sub=File_Info.FileSize - File_Info.FileOffset;
//下一簇号
File_Info.FileNextCluster=Get_NextCluster(File_Info.FileCurCluster);
//开始读取文件
lcd_wdat(table[File_Info.FileNextCluster]);
lcd_wdat('V');
while(File_Info.FileNextCluster!=0x0fffffff)
{
lcd_wdat(table[Fat_Info.SecPerClus]);
for(iSectorInCluster=0;iSectorInCluster<Fat_Info.SecPerClus;iSectorInCluster++)//读出整簇数据
{
Rbyte_SD(BUFF,Fat_Info.RootDirAddr+(File_Info.FileCurCluster-0x00000002+iSectorInCluster)*8*512,512);
File_Print();
File_Info.FileOffset=File_Info.FileOffset+512;
}
lcd_wdat(table[iSectorInCluster]);
//Fat簇链传递
File_Info.FileCurCluster=File_Info.FileNextCluster;
File_Info.FileNextCluster=Get_NextCluster(File_Info.FileCurCluster);
//文件偏移量的处理
sub=File_Info.FileSize-File_Info.FileOffset;
}
iSectorInCluster=0;
while(sub>=Fat_Info.BytesPerSec)//读出不满一个簇的数据
{
Rbyte_SD(BUFF,Fat_Info.RootDirAddr+(File_Info.FileCurCluster-2+iSectorInCluster)*8*512,512);
File_Print();
File_Info.FileOffset=File_Info.FileOffset+512;
sub=File_Info.FileSize - File_Info.FileOffset;
iSectorInCluster++;
}
Rbyte_SD(BUFF,Fat_Info.RootDirAddr+(File_Info.FileCurCluster-2+iSectorInCluster)*8*512,512);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?