一.
文件列表:
MMCSDTimming.pdf
SD3.0_20090721.pdf-------详细介绍了SD、SDIO,标准的官方文档
SD_FAT文档.doc
Microsoft_fat32.doc
二、简易FAT32
/*********************************************************
SD卡,高位在前
SD卡在上电初期,卡主控通过检测引脚1(DAT3)来决定使用SD模式
还是SPI模式。当此脚接50KOhm上拉电阻时,卡进入SD模式;
当此脚为低电平,卡则工作于SPI模式。
*********************************************************/
#include <string.h>
#include "FAT32.h"
#include "stm32f10x_lib.h"
#include "sdcard.h"
//#include"LCM.h"
#define SS 7
#define SS_H P2OUT |=(1<<SS);
#define SS_L P2OUT &=~(1<<SS);
unsigned char SD_SPC; //每簇扇区数(Sectors Per Cluster)
unsigned long SD_SPF; //每FAT 扇区数(Sectors Per FAT)
unsigned long SD_ROOT; //根目录所在扇区(编号为第二簇)
unsigned long SD_FBG; //FAT表地址
unsigned long SD_FBG_BOOT;//FAT表基地址
unsigned char Fat32_DataBuffer[520]={0}; //512+两字节CRC+....
unsigned char DataBuffer[1024]={0}; //512+两字节CRC+....
unsigned long FileAddress =0;
/*临时静态变量定义区*/
static unsigned long Temp0=0;
static unsigned long Temp1=0;
static unsigned long Temp2=0;
static unsigned long Temp3=0;
static unsigned char StatusInformation ;
void delay(int t) //延时
{
int x;
for(;t>0;t--) //双重循环
for(x=0;x<1020;x++);
}
/****************************************************
函数功能:块地址解析
输入:
输出:到指令中间的4个字节中
备注:
*****************************************************/
void setblock(unsigned char cmd[],long block) //获取块地址
{
cmd[1]=block>>15;
cmd[2]=block>>7;
cmd[3]=block<<1;//最低位为0
cmd[4]=0;
}
void Fat32_init(void)//得到SD卡信息:FAT位置,根目录位置,每簇扇区数,每FAT扇区数
{
unsigned char Fat_Number; //FAT 数(Number of FAT) 该分区上FAT 的副本数。
#if 0
unsigned char cmd1[]={0,0,0,0,0,0};//CRC=0x95
unsigned char dbk;
sdrst(); //SD复位, CMD0
dbk=1;
cmd1[0]=INIT;
while(dbk) //等待初始化, CMD1
{
delay(50);
dbk=SPI_SendCmd(cmd1,0);
usendchar(dbk);
}
cmd1[0]=READ1; //读BPB,Read Single Block
SPI_SendCmd(cmd1,515);
//usendstr(Fat32_DataBuffer,515);
usendchar(8);
/*
Fat_Number=bp->BPB_NF; //FAT 数(02)
SD_SPC=bp->BPB_SPC; //每簇扇区数(Sectors Per Cluster)(02)
SD_SPF=bp->BPB_SPF; //每FAT 扇区数(Sectors Per FAT)(000003c3=963)
SD_FBG=bp->BPB_RS; //保留扇区(0022=34)
SD_ROOT=Fat_Number*SD_SPF+SD_FBG; *///根目录扇区(编号为第二簇)
#endif
StatusInformation = SD_ReadBlock( 0, (u32 *)Fat32_DataBuffer, 512); //读取第0扇区
Fat_Number=Fat32_DataBuffer[16];
SD_SPC=Fat32_DataBuffer[13];
SD_SPF=(Fat32_DataBuffer[39]<<24)+(Fat32_DataBuffer[38]<<16)+(Fat32_DataBuffer[37]<<8)+Fat32_DataBuffer[36];
SD_FBG=Fat32_DataBuffer[14]+(Fat32_DataBuffer[15]<<8);
SD_ROOT=Fat_Number*SD_SPF+SD_FBG;
SD_FBG_BOOT=SD_FBG;//保存fat表基地址
//FAT32文件格式: 引导扇区 其余保留扇区 FAT1 FAT2表格(重复的) 根文件夹首簇 其他文件夹及所有文件 剩余扇区
}
/****************************************************
函数功能:读文件
输入:文件的簇地址
输出: 文件的数据存于全局变量Fat32_DataBuffer[1024]中;若
备注:若成功返回0,表面文件已经结束;若返回1,表明文
件还没有读完,文件的簇地址存在全局变量FileAddress中
*****************************************************/
unsigned char ReadFile(unsigned long cstbg) //起始簇号
{
unsigned char cmdfo[]={READ1,0,0,0,0,0};
unsigned long cstnxt; //簇
unsigned long adrnxt; //扇区
//FAT_FAT *p=(FAT_FAT*)Fat32_DataBuffer; //FAT表指针
cstnxt=cstbg; //得到文件第一个簇
{
adrnxt=SD_SPC*(cstnxt-2)+SD_ROOT; //减根目录簇号:2
//读一个簇
#if 0
setblock(cmdfo,adrnxt);
SPI_SendCmd_2(cmdfo,515,0);
setblock(cmdfo, (adrnxt+1) );
SPI_SendCmd_2(cmdfo,515,1);
#endif
SD_ReadMultiBlocks( (512*adrnxt),(u32 *)DataBuffer,512,2);
/*
for(k=0;k<512;k++)
LCD_WriteData( *((unsigned int *)Fat32_DataBuffer) );*/
//usendstr(Fat32_DataBuffer,1023);
/*
if( cstnxt==128)
{
SD_FBG +=1;
}
if( cstnxt>=128)
{
cstnxt -=128;
}
*/
SD_FBG =SD_FBG_BOOT+cstnxt / (0x80);
cstnxt =cstnxt %(0x80);
#if 0
setblock(cmdfo,SD_FBG); //读fat ????
SPI_SendCmd(cmdfo,515);
#endif
SD_ReadBlock(512*SD_FBG,(u32 *)Fat32_DataBuffer,512);
//cstnxt=p->FAT_SEC[cstnxt]; //得下一个簇
Temp0=( (unsigned long)(Fat32_DataBuffer[4*cstnxt+3]) )<<8;
Temp0=((unsigned long)(Temp0))<<8;
Temp0=((unsigned long)(Temp0))<<8;
Temp1=( (unsigned long)(Fat32_DataBuffer[4*cstnxt+2]) )<<8;
Temp1=((unsigned long)(Temp1))<<8;
Temp2=( (unsigned long)(Fat32_DataBuffer[4*cstnxt+1]) )<<8;
Temp3=(unsigned long)(Fat32_DataBuffer[4*cstnxt]);
//cstnxt=Fat32_DataBuffer[4*cstnxt]+ (Fat32_DataBuffer[(4*cstnxt)+1]<<8)+(Fat32_DataBuffer[(4*cstnxt)+2]<<16)+(Fat32_DataBuffer[(4*cstnxt)+3]<<24);
cstnxt=Temp3+Temp2+Temp1+Temp0;
FileAddress =cstnxt;
if(cstnxt==0x0fffffff) //文件结束标志
{
return 0;
}
else
{
return 1;
}
}
}
/****************************************************
函数功能:在根目录下根据文件存放的序号寻找文件的首簇
输入: 文件的位置序号
输出: (隐形)文件的首簇地址赋值于全局变量FileAddress
备注:若索引成功返回1,失败返回0
*****************************************************/
unsigned char FindFileAdd_AccordingToNum(unsigned char id) //打开第id个文件
{
unsigned char i,j=0,k,m,del,atr;//delete,attribute,
unsigned char flag=0;
unsigned int t1=0;
unsigned int t2=0;
unsigned char cmd[]={READ1,0,0,0,0,0};//CRC=0x95
for(m=0;m<200;m++)//xue 该成了从0开始
{
setblock(cmd,SD_ROOT+m); //读根目录
SPI_SendCmd(cmd,515);
for(i=0;i<16;i++) //找到第一个短文件
{
for(k=0;k<32;k++)
{
if(Fat32_DataBuffer[32*i+k])
break;
}
if(k==32)
return 0;
del=Fat32_DataBuffer[32*i];
atr=Fat32_DataBuffer[32*i+11];
if((del!=0xe5)&&(atr!=0x0f))
j++;
if(j==id)
{
flag=1;
break;
}
}
if(flag)break;
}
if(m==200)return 0;
t1=Fat32_DataBuffer[32*i+20]+ (Fat32_DataBuffer[32*i+21] <<8);
t2=Fat32_DataBuffer[32*i+26]+ (Fat32_DataBuffer[32*i+27] <<8);
FileAddress =t1;
FileAddress=(FileAddress<<16)|t2;
return 1;
//ReadFile(addr);
}
#define SINGLEFILE 0
#define MULTIFILE 1
//要把有关SD卡属性的信息都设成全局变量
/****************************************************
函数功能:判断两个字符串是否相等
输入:读取的文件名首地址,被核对的文件名首地址
输出: 若相等返回1,否则返回0
备注:
*****************************************************/
unsigned char CheckFileName(unsigned char * DiskFileName,unsigned char * CheckedFileName)
{
unsigned char i,j=0;
for(i=0;i<8;i++)
{
if( (*DiskFileName) != (*CheckedFileName) )
{
if( (0x20==*DiskFileName) && (0==*CheckedFileName) )
{
return 1;
}
else
return 0;
}
DiskFileName++;CheckedFileName++;
}
return 1;
}
/****************************************************
函数功能:寻找文件的首簇
输入:文件的目录项簇号,文件名,文件类型
输出:文件的首簇地址
备注:若查找失败,返回NULL
*****************************************************/
unsigned long FindFileAdd_AccordingToName(unsigned long FileListCluser,unsigned char *FileNameTemp,unsigned char SortTemp)
{
unsigned char i,j=0,k,m,del,atr;//delete,attribute,
unsigned char flag=0;
unsigned int t1=0;
unsigned int t2=0;
unsigned char cmd[]={READ1,0,0,0,0,0};//CRC=0x95
unsigned long SD_FileCluser=0;
unsigned long addr=0;
SD_FileCluser=SD_SPC*(FileListCluser-2)+SD_ROOT;
for(m=0;m<2;m++)//xue 该成了从0开始,只搜索两个簇
{
#if 0
setblock(cmd,SD_FileCluser+m); //读文件的目录
SPI_SendCmd(cmd,515);
#endif
SD_ReadBlock( 512*(SD_FileCluser+m) ,(u32 *)Fat32_DataBuffer,512);
for(i=0;i<16;i++) //找到第一个短文件
{
for(k=0;k<32;k++)
{
if(Fat32_DataBuffer[32*i+k])
break;
}
if(k==32)
break; //搜索下一扇区
del=Fat32_DataBuffer[32*i];
atr=Fat32_DataBuffer[32*i+11];
if((del!=0xe5)&&(atr!=0x0f))
{
//if( CheckFileName( (unsigned char*)(&Fat32_DataBuffer[32*i]),FileNameTemp) )
if( CheckFileName( &Fat32_DataBuffer[32*i],FileNameTemp) )
{
if( (SortTemp==SINGLEFILE) && (Fat32_DataBuffer[32*i+11]!=0x10) )//文档
{
flag=1;
break;
}
if( (SortTemp==MULTIFILE) && (Fat32_DataBuffer[32*i+11]==0x10) )//文件夹
{
flag=1;
break;//;//会跳出包含它的最内层的循环语句(for,while)和switch,而且只跳出一层
}
}
}
}
if(flag)break;
}
if(m==2)return NULL;
t1=Fat32_DataBuffer[32*i+20]+ (Fat32_DataBuffer[32*i+21] <<8);
t2=Fat32_DataBuffer[32*i+26]+ (Fat32_DataBuffer[32*i+27] <<8);
addr=t1;
addr=addr<<16|t2; //文件起始簇号
/*
FileAddress =t1;
FileAddress=(FileAddress<<16)|t2;*/
return addr;
}
/****************************************************
函数功能:寻找根目录下文档的首簇
输入: 文件名
输出: (隐形)文件的首簇地址赋值于全局变量FileAddress
备注:若索引成功返回1,失败返回0
*****************************************************/
unsigned char FindSingleFileAdd(unsigned char *FileName)
{
unsigned long FileAddressTemp=0;
FileAddressTemp=FindFileAdd_AccordingToName(2,FileName,SINGLEFILE);
if(NULL==FileAddressTemp)
{
return 0;
}
else
{
FileAddress =FileAddressTemp;//赋给全局变量
return 1;
}
}
/****************************************************
函数功能:寻找两重文件夹中文档的首簇
输入: 第一个文件夹的名称,第二个文件夹的名称,文档
的名称
输出: (隐形)文件的首簇地址赋值于全局变量FileAddress
备注:若索引成功返回1,失败返回0
*****************************************************/
unsigned char FindMultiFileAdd(unsigned char *FirstFileName,unsigned char *SecondFileName,unsigned char *FileName)
{
unsigned long FileAddressTemp =0;
FileAddressTemp =FindFileAdd_AccordingToName(2,FirstFileName,MULTIFILE);
if(NULL==FileAddressTemp)
return 0; //没有找到第一个文件
FileAddressTemp=FindFileAdd_AccordingToName(FileAddressTemp,SecondFileName,MULTIFILE);
if(NULL==FileAddressTemp)
return 0; //没有找到第二个文件
FileAddressTemp=FindFileAdd_AccordingToName(FileAddressTemp,FileName,SINGLEFILE);
if(NULL==FileAddressTemp)
return 0; //没有找到文件
FileAddress =FileAddressTemp; 赋给全局变量
return 1;
}
/*********************************************************
SD卡,高位在前
SD卡在上电初期,卡主控通过检测引脚1(DAT3)来决定使用SD模式
还是SPI模式。当此脚接50KOhm上拉电阻时,卡进入SD模式;
当此脚为低电平,卡则工作于SPI模式。
*********************************************************/
#include <string.h>
#include "FAT32.h"
#include "stm32f10x_lib.h"
#include "sdcard.h"
//#include"LCM.h"
#define SS 7
#define SS_H P2OUT |=(1<<SS);
#define SS_L P2OUT &=~(1<<SS);
unsigned char SD_SPC; //每簇扇区数(Sectors Per Cluster)
unsigned long SD_SPF; //每FAT 扇区数(Sectors Per FAT)
unsigned long SD_ROOT; //根目录所在扇区(编号为第二簇)
unsigned long SD_FBG; //FAT表地址
unsigned long SD_FBG_BOOT;//FAT表基地址
unsigned char Fat32_DataBuffer[520]={0}; //512+两字节CRC+....
unsigned char DataBuffer[1024]={0}; //512+两字节CRC+....
unsigned long FileAddress =0;
/*临时静态变量定义区*/
static unsigned long Temp0=0;
static unsigned long Temp1=0;
static unsigned long Temp2=0;
static unsigned long Temp3=0;
static unsigned char StatusInformation ;
void delay(int t) //延时
{
int x;
for(;t>0;t--) //双重循环
for(x=0;x<1020;x++);
}
/****************************************************
函数功能:块地址解析
输入:
输出:到指令中间的4个字节中
备注:
*****************************************************/
void setblock(unsigned char cmd[],long block) //获取块地址
{
cmd[1]=block>>15;
cmd[2]=block>>7;
cmd[3]=block<<1;//最低位为0
cmd[4]=0;
}
void Fat32_init(void)//得到SD卡信息:FAT位置,根目录位置,每簇扇区数,每FAT扇区数
{
unsigned char Fat_Number; //FAT 数(Number of FAT) 该分区上FAT 的副本数。
#if 0
unsigned char cmd1[]={0,0,0,0,0,0};//CRC=0x95
unsigned char dbk;
sdrst(); //SD复位, CMD0
dbk=1;
cmd1[0]=INIT;
while(dbk) //等待初始化, CMD1
{
delay(50);
dbk=SPI_SendCmd(cmd1,0);
usendchar(dbk);
}
cmd1[0]=READ1; //读BPB,Read Single Block
SPI_SendCmd(cmd1,515);
//usendstr(Fat32_DataBuffer,515);
usendchar(8);
/*
Fat_Number=bp->BPB_NF; //FAT 数(02)
SD_SPC=bp->BPB_SPC; //每簇扇区数(Sectors Per Cluster)(02)
SD_SPF=bp->BPB_SPF; //每FAT 扇区数(Sectors Per FAT)(000003c3=963)
SD_FBG=bp->BPB_RS; //保留扇区(0022=34)
SD_ROOT=Fat_Number*SD_SPF+SD_FBG; *///根目录扇区(编号为第二簇)
#endif
StatusInformation = SD_ReadBlock( 0, (u32 *)Fat32_DataBuffer, 512); //读取第0扇区
Fat_Number=Fat32_DataBuffer[16];
SD_SPC=Fat32_DataBuffer[13];
SD_SPF=(Fat32_DataBuffer[39]<<24)+(Fat32_DataBuffer[38]<<16)+(Fat32_DataBuffer[37]<<8)+Fat32_DataBuffer[36];
SD_FBG=Fat32_DataBuffer[14]+(Fat32_DataBuffer[15]<<8);
SD_ROOT=Fat_Number*SD_SPF+SD_FBG;
SD_FBG_BOOT=SD_FBG;//保存fat表基地址
//FAT32文件格式: 引导扇区 其余保留扇区 FAT1 FAT2表格(重复的) 根文件夹首簇 其他文件夹及所有文件 剩余扇区
}
/****************************************************
函数功能:读文件
输入:文件的簇地址
输出: 文件的数据存于全局变量Fat32_DataBuffer[1024]中;若
备注:若成功返回0,表面文件已经结束;若返回1,表明文
件还没有读完,文件的簇地址存在全局变量FileAddress中
*****************************************************/
unsigned char ReadFile(unsigned long cstbg) //起始簇号
{
unsigned char cmdfo[]={READ1,0,0,0,0,0};
unsigned long cstnxt; //簇
unsigned long adrnxt; //扇区
//FAT_FAT *p=(FAT_FAT*)Fat32_DataBuffer; //FAT表指针
cstnxt=cstbg; //得到文件第一个簇
{
adrnxt=SD_SPC*(cstnxt-2)+SD_ROOT; //减根目录簇号:2
//读一个簇
#if 0
setblock(cmdfo,adrnxt);
SPI_SendCmd_2(cmdfo,515,0);
setblock(cmdfo, (adrnxt+1) );
SPI_SendCmd_2(cmdfo,515,1);
#endif
SD_ReadMultiBlocks( (512*adrnxt),(u32 *)DataBuffer,512,2);
/*
for(k=0;k<512;k++)
LCD_WriteData( *((unsigned int *)Fat32_DataBuffer) );*/
//usendstr(Fat32_DataBuffer,1023);
/*
if( cstnxt==128)
{
SD_FBG +=1;
}
if( cstnxt>=128)
{
cstnxt -=128;
}
*/
SD_FBG =SD_FBG_BOOT+cstnxt / (0x80);
cstnxt =cstnxt %(0x80);
#if 0
setblock(cmdfo,SD_FBG); //读fat ????
SPI_SendCmd(cmdfo,515);
#endif
SD_ReadBlock(512*SD_FBG,(u32 *)Fat32_DataBuffer,512);
//cstnxt=p->FAT_SEC[cstnxt]; //得下一个簇
Temp0=( (unsigned long)(Fat32_DataBuffer[4*cstnxt+3]) )<<8;
Temp0=((unsigned long)(Temp0))<<8;
Temp0=((unsigned long)(Temp0))<<8;
Temp1=( (unsigned long)(Fat32_DataBuffer[4*cstnxt+2]) )<<8;
Temp1=((unsigned long)(Temp1))<<8;
Temp2=( (unsigned long)(Fat32_DataBuffer[4*cstnxt+1]) )<<8;
Temp3=(unsigned long)(Fat32_DataBuffer[4*cstnxt]);
//cstnxt=Fat32_DataBuffer[4*cstnxt]+ (Fat32_DataBuffer[(4*cstnxt)+1]<<8)+(Fat32_DataBuffer[(4*cstnxt)+2]<<16)+(Fat32_DataBuffer[(4*cstnxt)+3]<<24);
cstnxt=Temp3+Temp2+Temp1+Temp0;
FileAddress =cstnxt;
if(cstnxt==0x0fffffff) //文件结束标志
{
return 0;
}
else
{
return 1;
}
}
}
/****************************************************
函数功能:在根目录下根据文件存放的序号寻找文件的首簇
输入: 文件的位置序号
输出: (隐形)文件的首簇地址赋值于全局变量FileAddress
备注:若索引成功返回1,失败返回0
*****************************************************/
unsigned char FindFileAdd_AccordingToNum(unsigned char id) //打开第id个文件
{
unsigned char i,j=0,k,m,del,atr;//delete,attribute,
unsigned char flag=0;
unsigned int t1=0;
unsigned int t2=0;
unsigned char cmd[]={READ1,0,0,0,0,0};//CRC=0x95
for(m=0;m<200;m++)//xue 该成了从0开始
{
setblock(cmd,SD_ROOT+m); //读根目录
SPI_SendCmd(cmd,515);
for(i=0;i<16;i++) //找到第一个短文件
{
for(k=0;k<32;k++)
{
if(Fat32_DataBuffer[32*i+k])
break;
}
if(k==32)
return 0;
del=Fat32_DataBuffer[32*i];
atr=Fat32_DataBuffer[32*i+11];
if((del!=0xe5)&&(atr!=0x0f))
j++;
if(j==id)
{
flag=1;
break;
}
}
if(flag)break;
}
if(m==200)return 0;
t1=Fat32_DataBuffer[32*i+20]+ (Fat32_DataBuffer[32*i+21] <<8);
t2=Fat32_DataBuffer[32*i+26]+ (Fat32_DataBuffer[32*i+27] <<8);
FileAddress =t1;
FileAddress=(FileAddress<<16)|t2;
return 1;
//ReadFile(addr);
}
#define SINGLEFILE 0
#define MULTIFILE 1
//要把有关SD卡属性的信息都设成全局变量
/****************************************************
函数功能:判断两个字符串是否相等
输入:读取的文件名首地址,被核对的文件名首地址
输出: 若相等返回1,否则返回0
备注:
*****************************************************/
unsigned char CheckFileName(unsigned char * DiskFileName,unsigned char * CheckedFileName)
{
unsigned char i,j=0;
for(i=0;i<8;i++)
{
if( (*DiskFileName) != (*CheckedFileName) )
{
if( (0x20==*DiskFileName) && (0==*CheckedFileName) )
{
return 1;
}
else
return 0;
}
DiskFileName++;CheckedFileName++;
}
return 1;
}
/****************************************************
函数功能:寻找文件的首簇
输入:文件的目录项簇号,文件名,文件类型
输出:文件的首簇地址
备注:若查找失败,返回NULL
*****************************************************/
unsigned long FindFileAdd_AccordingToName(unsigned long FileListCluser,unsigned char *FileNameTemp,unsigned char SortTemp)
{
unsigned char i,j=0,k,m,del,atr;//delete,attribute,
unsigned char flag=0;
unsigned int t1=0;
unsigned int t2=0;
unsigned char cmd[]={READ1,0,0,0,0,0};//CRC=0x95
unsigned long SD_FileCluser=0;
unsigned long addr=0;
SD_FileCluser=SD_SPC*(FileListCluser-2)+SD_ROOT;
for(m=0;m<2;m++)//xue 该成了从0开始,只搜索两个簇
{
#if 0
setblock(cmd,SD_FileCluser+m); //读文件的目录
SPI_SendCmd(cmd,515);
#endif
SD_ReadBlock( 512*(SD_FileCluser+m) ,(u32 *)Fat32_DataBuffer,512);
for(i=0;i<16;i++) //找到第一个短文件
{
for(k=0;k<32;k++)
{
if(Fat32_DataBuffer[32*i+k])
break;
}
if(k==32)
break; //搜索下一扇区
del=Fat32_DataBuffer[32*i];
atr=Fat32_DataBuffer[32*i+11];
if((del!=0xe5)&&(atr!=0x0f))
{
//if( CheckFileName( (unsigned char*)(&Fat32_DataBuffer[32*i]),FileNameTemp) )
if( CheckFileName( &Fat32_DataBuffer[32*i],FileNameTemp) )
{
if( (SortTemp==SINGLEFILE) && (Fat32_DataBuffer[32*i+11]!=0x10) )//文档
{
flag=1;
break;
}
if( (SortTemp==MULTIFILE) && (Fat32_DataBuffer[32*i+11]==0x10) )//文件夹
{
flag=1;
break;//;//会跳出包含它的最内层的循环语句(for,while)和switch,而且只跳出一层
}
}
}
}
if(flag)break;
}
if(m==2)return NULL;
t1=Fat32_DataBuffer[32*i+20]+ (Fat32_DataBuffer[32*i+21] <<8);
t2=Fat32_DataBuffer[32*i+26]+ (Fat32_DataBuffer[32*i+27] <<8);
addr=t1;
addr=addr<<16|t2; //文件起始簇号
/*
FileAddress =t1;
FileAddress=(FileAddress<<16)|t2;*/
return addr;
}
/****************************************************
函数功能:寻找根目录下文档的首簇
输入: 文件名
输出: (隐形)文件的首簇地址赋值于全局变量FileAddress
备注:若索引成功返回1,失败返回0
*****************************************************/
unsigned char FindSingleFileAdd(unsigned char *FileName)
{
unsigned long FileAddressTemp=0;
FileAddressTemp=FindFileAdd_AccordingToName(2,FileName,SINGLEFILE);
if(NULL==FileAddressTemp)
{
return 0;
}
else
{
FileAddress =FileAddressTemp;//赋给全局变量
return 1;
}
}
/****************************************************
函数功能:寻找两重文件夹中文档的首簇
输入: 第一个文件夹的名称,第二个文件夹的名称,文档
的名称
输出: (隐形)文件的首簇地址赋值于全局变量FileAddress
备注:若索引成功返回1,失败返回0
*****************************************************/
unsigned char FindMultiFileAdd(unsigned char *FirstFileName,unsigned char *SecondFileName,unsigned char *FileName)
{
unsigned long FileAddressTemp =0;
FileAddressTemp =FindFileAdd_AccordingToName(2,FirstFileName,MULTIFILE);
if(NULL==FileAddressTemp)
return 0; //没有找到第一个文件
FileAddressTemp=FindFileAdd_AccordingToName(FileAddressTemp,SecondFileName,MULTIFILE);
if(NULL==FileAddressTemp)
return 0; //没有找到第二个文件
FileAddressTemp=FindFileAdd_AccordingToName(FileAddressTemp,FileName,SINGLEFILE);
if(NULL==FileAddressTemp)
return 0; //没有找到文件
FileAddress =FileAddressTemp; 赋给全局变量
return 1;
}
FAT32.h
[cpp] view plaincopyprint?
/****************************
0x40:复位
0x41:初始化
0x51:读单块
0x58:写单块
0x4a:CID read,16b
0x49:CSD read,16b
****************************/
#define INIT 0X41
#define READ1 0X51
#define WRITE1 0X58
#define RCID 0X4A
#define RCSD 0X49
typedef struct
{
unsigned char BPB_NC1[0x0b]; //无用的
unsigned int BPB_BPS; //扇区字节数(Bytes Per Sector)
unsigned char BPB_SPC; //每簇扇区数(Sectors Per Cluster)
unsigned int BPB_RS; //保留扇区数(Reserved Sector) 0x0e
//第一个FAT 开始之前的扇区数,包括引导扇区。本字段的十进制值一般为32
unsigned char BPB_NF; //FAT 数(Number of FAT) 该分区上FAT 的副本数。 0x0f
//本字段的值一般为2
unsigned char BPB_NC2[0x0b]; //无用的
//2+2+1+2+2+2+++++
unsigned long BPB_HS; //隐藏扇区数(Hidden Sector)该分区上引导扇区
//之前的扇区数。在引导序列计算到根目录的数据区的绝对位移的过程中使用了该值
unsigned long BPB_LS; //总扇区数(Large Sector) 本字段包含FAT32 分区中总的扇区
unsigned long BPB_SPF; //每FAT 扇区数(Sectors PerFAT)(只被FAT32 使用)该分区 0x1e
//每个FAT 所占的扇区数。计算机利用这个数和 FAT 数以及隐藏扇区数
//(本表中所描述的)来决定根目录从哪里开始。
unsigned int BPB_EF; //扩展标志(Extended Flag)(只被FAT32 使用)
unsigned int BPB_FV; //文件系统版本(File system Version)只供FAT32 使用,高
//字节是主要的修订号,而低字节是次要的修订号。
unsigned long BPB_RCN; //根目录簇号(Root Cluster Number)
//(只供FAT32 使用) 根目录第一簇的簇号。本字段的值一般为2,但不总是如此
unsigned int BPB_FSI; //文件系统信息扇区号(File System Information
//SectorNumber)(只供FAT32 使用)
unsigned int BPB_BS; //备份引导扇区(只供FAT32 使用) 为一个非零值,这个非零
//值表示该分区保存引导扇区的副本的保留区中的扇区号。
}FAT_BPB;
typedef struct
{
unsigned long FAT_SEC[128];//四字节为一簇
}FAT_FAT; //文件分配表:file allocation table
typedef struct
{
unsigned char SFILE_NAME1[8];//文件名
unsigned char SFILE_NAME2[3];//扩展名
unsigned char SFILE_ATTR; //attribute属性
unsigned char SFILE_NEC1; //系统保留
unsigned char SFILE_DAT1[7]; //日期等
unsigned int SFILE_ADDH; //文件起始簇号的高16 位
unsigned char SFILE_DAT2[4]; //日期等
unsigned int SFILE_ADDL; //文件起始簇号的低16 位
unsigned long SFILE_LEN; //表示文件的长度
}FAT_SFILE; //短文件名文件(32)字节
typedef struct
{
unsigned char LFILE_ATTR; //
unsigned char LFILE_NAME1[10]; //
unsigned char LFILE_NEC1; //长文件名目录项标志,取值0FH
unsigned char LFILE_NEC2; //系统保留
unsigned char LFILE_CHK; //校验值(根据短文件名计算得出)
unsigned char LFILE_LNU1[12]; //长文件名unicode 码
unsigned int LFILE_ADD; //文件起始簇号(目前常置0)
unsigned char LFILE_LNU2[4]; //长文件名unicode 码
}FAT_LFILE; //长文件名文件(32)字节
typedef struct
{
FAT_SFILE MENU[16];
}FAT_MENU; //目录项
// unsigned char FindFileAdd_AccordingToName(unsigned char id);
extern unsigned char ReadFile(unsigned long cstbg);
extern unsigned long FindFileAdd_AccordingToName(unsigned long FileListCluser,unsigned char *FileNameTemp,unsigned char SortTemp);
extern unsigned char FindMultiFileAdd(unsigned char *FirstFileName,unsigned char *SecondFileName,unsigned char *FileName);
extern unsigned char FindFileAdd_AccordingToName_Temp(unsigned char id);
extern void usendstr(unsigned char s[],unsigned int size);
extern void SdWrite(unsigned char datw[],unsigned long block);//要发送的命令,以及要写在哪一块
extern void delay(int t);
/*********************************************************************************************************************
*--------------------------------------2010年4月13日11:22:08 Fat32 外部函数
**********************************************************************************************************************/
extern void Fat32_init(void);
extern unsigned char FindSingleFileAdd(unsigned char *FileName);
extern unsigned char DataBuffer[1024];
extern unsigned long FileAddress;
三、FatFs移植示例。
支持格式化文件系统、读写、目录等。目前下面的代码只支持一个设备,如若想支持多个设备的文件系统,比如在SD卡、SPI FLASH中均实现文件系统,改动下面代码即可:
对每个Physical drive nmuber响应;底层的驱动只需要提供初始化(包括获取设备的容量)、读写即可。如果希望实现NFS、串口硬盘等,只需要把这几个接口通过通信链路(网络、串口等)映射过去
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/
#include "diskio.h"
#include "stm32f10x.h"
#include "SD_drive.h"
/*-----------------------------------------------------------------------*/
/* Correspondence between physical drive number and physical drive. */
#define ATA 0
#define MMC 1
#define USB 2
static int bus_in_sdio;
/**
* @brief 检查sd卡是否就绪
* @return 0:检测成功
* -1:检测失败
*/
static int check_sdcard(void)
{
return check_maincard();
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0..) */
)
{
if( check_sdcard() == 0 )
{
bus_in_sdio = 1;
return RES_OK;
}
return RES_ERROR;
}
DSTATUS disk_unmount(BYTE drv)
{
bus_in_sdio = 0;
return RES_OK;
}
DWORD get_fattime ()
{
return 0;
}
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
DSTATUS disk_status (
BYTE drv /* Physical drive nmuber (0..) */
)
{
if(bus_in_sdio == 0)
{
return disk_initialize(drv);
}
//SD_GetStatus(); // == 0 )
//return RES_ERROR;
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to read (1..255) */
)
{
DRESULT res;
res = (DRESULT)(read_card(sector, count, buff));
if( res != 0 )
return RES_ERROR;
else
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to write (1..255) */
)
{
DRESULT res;
res = (DRESULT)(write_card(sector, count, (unsigned char*)buff));
if( res == 0)
return RES_OK;
else
return RES_ERROR;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
// 返回磁盘状态
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
if (drv)
{
return RES_PARERR; //仅支持单磁盘操作,否则返回参数错误
}
//FATFS目前版本仅需处理CTRL_SYNC,GET_SECTOR_COUNT,GET_BLOCK_SIZ三个命令
switch(ctrl)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = 1;
res = RES_OK;
break;
case GET_SECTOR_COUNT: //读卡容量
*(DWORD*)buff = sd_state.capacity;
break;
default:
res = RES_PARERR;
break;
}
return res;
}