SD_STM32_SPI驱动+FatFs文件系统

一.

文件列表:

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;  
}  



 

你可能感兴趣的:(cmd,null,文档,byte,disk,delay)