📄 fat16.c
字号:
#include "datatype.h"
#include "fat16.h"
INT8U g_u8Fat16Buf[512];
FAT16_INIT_ARG g_Fat16InitArg;
FILE_INFO g_FileInfo;
/*************************************************************************
*名称: ByteUnite
*功能: 多字节合并
*参数: 无
*返回: 合并后的数据
*************************************************************************/
INT32U ByteUnite(INT8U *pu8Data, INT8U u8Len)
{
INT32U temp = 0;
INT32U u32Fact = 1;
INT8U i=0;
for(i = 0; i < u8Len; i++)
{
temp += pu8Data[i] * u32Fact;
u32Fact <<= 8;
}
return temp;
}
INT8U FAT16_ReadSec(INT32U u32SecNo, INT8U *pu8Buf)
{
INT8U temp;
temp = SD_ReadBlockSingle(u32SecNo, pu8Buf);
return temp;
}
/*************************************************************************
*名称: FAT16_FindBPB
*功能: 寻找BPB所在的扇区号
*参数: 无
*返回: BPB所在的扇区号
*************************************************************************/
INT32U FAT16_FindBPB(void)
{
INT32U u32BpbSectNo = 0;
while(u32BpbSectNo < FIND_BPB_UP_RANGE)
{
SD_ReadBlockSingle(u32BpbSectNo,g_u8Fat16Buf);
if(g_u8Fat16Buf[0] == 0xEB && g_u8Fat16Buf[2] == 0x90)
{
break;
}
u32BpbSectNo++;
}
return u32BpbSectNo;
}
/*************************************************************************
*名称: FAT16_Init
*功能: FAT16文件系统初始化
*参数: pArg文件系统参数指针
*返回: 零成功非零失败
*************************************************************************/
INT8U FAT16_Init(PFAT16_INIT_ARG pArg)
{
INT32U temp;
PFAT16_BPB bpb=(PFAT16_BPB)(g_u8Fat16Buf);
//将数据缓冲区指针转为 struct FAT32_BPB 型指针
pArg->BPBSecNo = FAT16_FindBPB();
pArg->TotSize = g_SDInfo.cap; //获取分区容量
//计算FAT表占用的扇区数
if(ByteUnite(bpb->BPB_FATSz16, 2) != 0)
{
pArg->FATSz = ByteUnite(bpb->BPB_FATSz16, 2);
}
else
{
pArg->FATSz = ByteUnite(bpb->BPB_FATSz32, 4);
}
//计算总的扇区数
if (ByteUnite(bpb->BPB_TotSec16, 2)!= 0)
{
pArg->TotSec = ByteUnite(bpb->BPB_TotSec16, 2);
}
else
{
pArg->TotSec = ByteUnite(bpb->BPB_TotSec32, 4);
}
pArg->FirstDirClus = ByteUnite(bpb->BPB_RootClus, 4);
//计算根目录簇号
pArg->BytesPerSec = ByteUnite(bpb->BPB_BytesPerSec, 2);
//计算每扇区字节数
pArg->SecPerClus = bpb->BPB_SecPerClus[0];
//计算每簇扇区数
pArg->FirstFATSec = ByteUnite(bpb->BPB_RsvdSecCnt,2)
+ pArg->BPBSecNo;
//计算第一个 FAT 表扇区号
pArg->RootDirCount = ByteUnite(bpb->BPB_RootEntCnt, 2);
//计算根目录项数
pArg->RootDirSz = (pArg->RootDirCount)*32 >> 9;
//装计算根目录占用的扇区数
//pArg->FirstDirSec = (INT32U)(pArg->FATSz);
pArg->FirstDirSec = pArg->FirstFATSec + bpb->BPB_NumFATs[0]
* pArg->FATSz;
//计算第一个目录扇区到
pArg->FirstDataSec =(pArg->FirstDirSec)+(pArg->RootDirSz);
//计算第一个数据扇区到
pArg->DataSec = pArg->TotSec - (ByteUnite(bpb->BPB_RsvdSecCnt,2)
+ (bpb->BPB_NumFATs[0]* pArg->FATSz)
+ pArg->RootDirSz);
pArg->ClusCnt= pArg->DataSec / bpb->BPB_SecPerClus[0]; //计算簇数
//判断文件类型
if(pArg->ClusCnt < 4085)
{
pArg->FATType = FAT_TYPE_FAT12;
}
else if(pArg->ClusCnt < 65525)
{
pArg->FATType = FAT_TYPE_FAT16;
}
else
{
pArg->FATType = FAT_TYPE_FAT32;
}
return 0;
}
INT32U FAT16_GetNextClus(INT32U u32CurClus)
{
INT32U temp;
temp =((u32CurClus / 256) + g_Fat16InitArg.FirstFATSec);
//计算给定簇号对应的簇项的扇区号
FAT16_ReadSec(temp, g_u8Fat16Buf); //读取扇区内容
u32CurClus = u32CurClus % 256 * 2;//计算簇号在扇区的偏移量;
return ByteUnite(&g_u8Fat16Buf[u32CurClus] , 2); //返回下一簇号
}
/*************************************************************************
*名称: FAT16_CmpFileName
*功能: 比较目录表文件名和输入的文件是否一致
*参数: pFileNameDir 目录表里的文件名,pFileNameInput输入的文件名
*返回: 零成功 非零失败
*************************************************************************/
INT8U FAT16_CmpFileName(INT8U *pFileNameDir, INT8U *pFileNameInput)
{
INT8U temp;
while(*pFileNameInput)
{
if(*pFileNameInput == '.') //忽略输入文件名里的.字符
{
pFileNameInput++;
continue;
}
if(*pFileNameDir == ' ')//忽略目录表文件里的填充空格字符
{
pFileNameDir++;
continue;
}
//将输入文件名里的小写字母转为大写
if(*pFileNameInput > 0x60 && *pFileNameInput < 0x7B)
{
temp = *pFileNameInput -32;
}
else
{
temp = *pFileNameInput;
}
if(temp != *pFileNameDir++) //比较字符是否一致
{
return 1;
}
pFileNameInput++;
}
return 0;
}
INT32U FAT16_OpenFile(INT8U *pFileName, PFILE_INFO pg_FileInfo)
{
INT32U u32CurSec;
INT32U u32EndSec;
INT32U u32CurDir;
PFAT16_DIR pDir;
//对根目录表所在的扇区扫描
u32CurSec = g_Fat16InitArg.FirstDirSec;
u32EndSec = g_Fat16InitArg.FirstDirSec + g_Fat16InitArg.RootDirSz;
for(; u32CurSec < u32EndSec; u32CurSec++)
{
//对根目录里的目录项逐个扫描
FAT16_ReadSec(u32CurSec, g_u8Fat16Buf);
for(u32CurDir = 0; u32CurDir < g_Fat16InitArg.BytesPerSec;
u32CurDir += 32)
{
pDir = (PFAT16_DIR)(g_u8Fat16Buf + u32CurDir);
//获取一个目录表地址
if(FAT16_CmpFileName(pDir->Name, pFileName) == 0)
//对文件名进行匹配
{
INT8U i;
pg_FileInfo->Size = ByteUnite(pDir->FileSize, 4);
//获取文件大小
//strcpy(g_FileInfo.FileName,filepath+index);
while(*pFileName)//获取文件名
{
pg_FileInfo->Name[i] = *pFileName++;
i++;
}
pg_FileInfo->FstClus = ByteUnite(pDir->FstClusL, 2);
//获取文件开始簇号
pg_FileInfo->CurClus = pg_FileInfo->FstClus;
//获取文件当前簇号
pg_FileInfo->NextClus =
FAT16_GetNextClus(pg_FileInfo->CurClus);
//获取文件的下一簇号
pg_FileInfo->Offset = 0; //获取偏移量
pg_FileInfo->CurSec = (pg_FileInfo->CurClus - 2)
*g_Fat16InitArg.SecPerClus + g_Fat16InitArg.FirstDataSec;
//获取当前文件的扇区号
return 0;
}
}
}
return 1;
}
INT32U FAT16_ReadFile(PFILE_INFO pg_FileInfo)
{
INT32U i;
INT32U j;
INT32U len;
len = pg_FileInfo->Size - pg_FileInfo->Offset;
//return pg_FileInfo->CurClus;
while(pg_FileInfo->NextClus != 0xFFFF)//循环知道没有后续簇
{
for(i = 0; i < g_Fat16InitArg.SecPerClus; i++)//读出整簇数据
{
FAT16_ReadSec(pg_FileInfo->CurSec + i, g_u8Fat16Buf);
pg_FileInfo->Offset += g_Fat16InitArg.BytesPerSec;//计算偏移量
len = pg_FileInfo->Size - pg_FileInfo->Offset; //计算剩余字节
for(j = 0; j < g_Fat16InitArg.BytesPerSec; j++)
{
Uart_Printf("%s",g_u8Fat16Buf[j]);
} //将数据发送到串口显示
}
pg_FileInfo->CurClus = pg_FileInfo->NextClus;
pg_FileInfo->NextClus =
FAT16_GetNextClus(pg_FileInfo->CurClus);
pg_FileInfo->CurSec = (pg_FileInfo->CurClus - 2 )
*g_Fat16InitArg.SecPerClus + g_Fat16InitArg.FirstDataSec;
}
while(len >= g_Fat16InitArg.BytesPerSec)
//处理不足一簇,而足扇区的数据
{
FAT16_ReadSec(pg_FileInfo->CurSec++, g_u8Fat16Buf);
pg_FileInfo->Offset += g_Fat16InitArg.BytesPerSec;//计算偏移量
len = pg_FileInfo->Size - pg_FileInfo->Offset; //计算剩余字节
for(j = 0; j < g_Fat16InitArg.BytesPerSec; j++)
{
Uart_Printf("%s",g_u8Fat16Buf[j]);
}
}
FAT16_ReadSec(pg_FileInfo->CurSec, g_u8Fat16Buf);
//读取最后一个扇区
for(j = 0; j < len; j++) //输出剩余数据
{
Uart_Printf("%s",g_u8Fat16Buf[j]);
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -