用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

点击进入授权页面

只需一步,快速开始

  • QQ空间
  • 回复
  • 收藏
  • TA的每日心情
    擦汗
    2018-4-26 11:09
  • 签到天数: 103 天

    [LV.6]常住居民II

    希岩 中级会员 2016-6-30 20:02 楼主
        参考为删减的FAT32文件系统,删改大部分函数,形成了在ICCAVR下编译只有7519字节的hex文件。大家可以参考本文的文件系统来实现文件读取,文件定位,可以用来编写MP3解码和电子书解码。本程序在ICCAVR7.2下编译通过,采用Atmega 328p芯片,片外16Mhz晶振。本程序作为示例程序,仅供参考。以下是部分程序,完整见附件。

    //------------------------main.c文件-----------------------------------
    /********************************************************************************
    功能:基于FAT32文件系统的SD卡、TF卡打开文件、读取数据。
    Atmega328P 8位单片机,片外16Mhz晶体振荡器。串口波特率19200
    CS片选选PB2     
    参考:于振南FAT32文件系统
                                                2016/3/22 ChenYanan
    *********************************************************************************/
    #include<iom328pv.h>
    #include<AVRdef.h>
    #include<string.h>
    #include "SdInit.h"
    #include "FAT32.h"  //文件系统信息结构体
    #include "main.h"

    //全局变量


    FAT32_Init_Args Init_Args ,*pInit_Args; //初始化参数集合
    FileInfo fileinfo;                      //文件信息集合


    //设备初始化---------------------------------------------------------------
    void Init_Devices(void)
    {Init_Clock();
    Init_Timer0();
    Init_Port();
    Init_USART0();
    }


    //主函数=====================================================================
    void main(void)
    { uint08 u8temp;
      uint16 len;
      uint08 FAT32_ReceBuffer[512];
      CLI();                                        //禁中断
      Init_Devices();                               //初始化设备
      //SEI();                                      //中断使能

    //======================================================  
    SCI_Send_Str("Start to init SD...\r\n");
    u8temp=FAT32_Device_Init();                    //SD首次初始化时间较长
    if(u8temp)                                     //返回0说明初始化成功
    { SCI_Send_Str("SD Init ERROR!\r\n");
       SCI_Put_Inf("Error Code:",(uint32)u8temp);
    }
    pInit_Args=&Init_Args;                         //将FAT32的初始化参数集合指针指向设备的初始化参数集

    Init_watchdog();                              //初始化完成后开启看门狗

    SCI_Put_Inf("Total Sector:",SD_GetTotalSec()); //获取SD卡的总扇区数
    SCI_Send_Str("=================\r\n");
    //=========================================================
      SCI_Send_Str("Start to Init FAT32...\r\n");
       u8temp=(uint08)FAT32_Init();                 //初始化文件系统
    if(!u8temp)                                    //文件系统初始化成功
    {
       SCI_Put_Inf("BPB_Sector_No:",Init_Args.BPB_Sector_No);   
       SCI_Put_Inf("Total_SizeKB:",Init_Args.Total_SizeKB);
       SCI_Put_Inf("BytesPerSector:",Init_Args.BytesPerSector);
       SCI_Put_Inf("FATsectors:",Init_Args.FATsectors);  
       SCI_Put_Inf("SectorsPerClust:",Init_Args.SectorsPerClust);
       SCI_Put_Inf("FirstFATSector:",Init_Args.FirstFATSector);
       SCI_Put_Inf("FirstDirSector:",Init_Args.FirstDirSector);
       SCI_Put_Inf("FSsec:",Init_Args.FSINFO_Sec);
       SCI_Put_Inf("Next_Free_Cluster:",Init_Args.Next_Free_Cluster);
       SCI_Put_Inf("FreenCluster:",Init_Args.Free_nCluster);
    } else
       SCI_Put_Inf("File System inits fail, Err Code:",u8temp);  
    //=============================================================
    //文件打开
      u8temp=FAT32_Open_File(&fileinfo,(sint08*)"/test1.txt",0,1);
      if(!u8temp)                                          //打开文件成功
      {
      SCI_Send_Str("Succeed to open file.\r\n");
      SCI_Send_Str("====================\n");
      SCI_Send_Str("File_Name(Short 8.3):");               //8.3格式文件名,不支持中文文件名
      SCI_Send_Str((uint08*)fileinfo.File_Name);
      SCI_Put_Inf("File_Size:",fileinfo.File_Size);
             
      SCI_Send_Str("File_CDate:");
      SCI_Put_Num(fileinfo.File_CDate.year); SCI_Send_Str("/");
      SCI_Put_Num(fileinfo.File_CDate.month);SCI_Send_Str("/");
      SCI_Put_Num(fileinfo.File_CDate.day);  SCI_Send_Str("  ");
      SCI_Put_Num(fileinfo.File_CTime.hour); SCI_Send_Str(":");
      SCI_Put_Num(fileinfo.File_CTime.min);  SCI_Send_Str(":");
      SCI_Put_Num(fileinfo.File_CTime.sec);  SCI_Send_Str("\r\n");
             
      SCI_Put_Inf("File_StartClust:",fileinfo.File_StartClust);
      SCI_Put_Inf("File_CurClust:",fileinfo.File_CurClust);
      SCI_Put_Inf("File_CurSec:",fileinfo.File_CurSec);
      SCI_Put_Inf("File_CurPos:",fileinfo.File_CurPos);
      SCI_Put_Inf("File_CurOffset:",fileinfo.File_CurOffset);
      SCI_Send_Str("==================\n");
      len=(uint16)FAT32_ReadData(&fileinfo,10,100,FAT32_ReceBuffer);  //从文件起始偏移10位置开始读取100个字节
      SCI_Put_Inf("Have Read data:",len);
      SCI_Send_Str("Data:\n");

      SCI_Send_Str(FAT32_ReceBuffer);                                //输出数据
      }
       else SCI_Put_Inf("Fail to Open file, Err Code:",u8temp);

       (void)FAT32_Close_File(&fileinfo); //必要步骤:关闭文件
    //=========================================================================

      while(1)
      { WDR();                            //清看门狗

      }

    }


    //------------------------sdinit.c file---------------------
    #include<iom328pv.h>
    #include<AVRdef.h>
    #include "SDInit.h"
    #include "main.h"


    //--------------------------------------------------------------
    //片选端口         
    #define SS_ON   PORTB&=0xFB                                  //低电平
    #define SS_OFF  PORTB|=0x04                                  //高电平
    uint08 SD1_Addr_Mode=0;
    uint08 SD1_Ver=SD_VER_ERR;
    //=============================================================================
    //-----------------------------------------------------------------------------
    void SPI_High_Rate(void)
    {
      //最高操作速率不能高于25Mbps
      SPCR &= 0x5C;   //BR=busclk/(SPPR *SPR )=8M/4=2M ,page147
       //SPCR = (1<<SPE)|(1<<MSTR);              
    }
    //SPI主机初始化模式1,低速模式250k==========================================================
    void SPI_Init_M1(void)
    {                                          //SPI模式1
      DDRB|= (1<<DDB3)|(1<<DDB5);              //设置MOSI 和SCK 为输出,其他为输入
      SPCR = 0b01010001;                       //使能SPI 主机模式,时钟模式为下降沿,结束沿采样,设置时钟速率为fck/16
    }
    //SPI主机初始化模式3,低速模式250k==========================================================
    void SPI_Init_M3(void)
    {                                          //SPI模式3
      DDRB|= (1<<DDB3)|(1<<DDB5);              //设置MOSI 和SCK 为输出,其他为输入
      SPCR = 0b01011001;                       //使能SPI 主机模式,时钟模式为下降沿,结束沿采样,设置时钟速率为fck/16
    }
    //SPI主机初始化模式4,必须使用低速模式,62.5k==========================================================
    void SPI_Init_M4(void)
    {                                          //SPI模式4
      DDRB|= (1<<DDB3)|(1<<DDB5);              //设置MOSI 和SCK 为输出,其他为输入
      SPCR = 0b01011111;                       //使能SPI 主机模式,时钟模式为下降沿,结束沿采样,设置时钟速率为fck/128
    }
    //SPI数据发送,采用轮询=======================================================
    void SPI_Send(uint08 data)
    {
    SPDR = data;                                //启动数据传输
    while(!(SPSR & (1<<SPIF)));                 //等待传输结束                        
    }
    //SPI数据接收,采用轮询=======================================================
    uint08 SPI_Rece(void)
    {
    SPDR = 0xff;                                //启动数据传输
    while(!(SPSR & (1<<SPIF)));                 //等待传输结束
    return SPDR;                                                 //接收字符
    }

    /******************************************************************
    - 功能描述:向SD卡写命令
    - 参数说明:SD卡的命令是6个字节,pcmd是指向命令字节序列的指针
    - 返回说明:命令写入不成功,将返回0xff
    ******************************************************************/
    uint08 SD_Write_Cmd(uint08 *pcmd)
    {
    uint08 r=0,time=0;
      SS_OFF;
    (void)SPI_Rece();                //发送8个时钟,提高兼容性,如果没有这里,有些SD卡可能不支持   
      SS_ON;        
    while(SPI_Rece()!=0xFF);        //等待SD卡准备好,再向其发送命令      
    //_NOP();
    //将6字节的命令序列写入SD卡
    for(r=0;r<6;r++)
       SPI_Send(pcmd[r]);
               
    if(pcmd[0]==0x1C) (void)SPI_Rece(); //如果是停止命令,跳过多余的字节

    do
      {
       r=SPI_Rece();
       time++;
      }while((r==0xff)&&(time<TRY_TIME)); //等待响应,
      // _NOP();
       return r;
    }
    /******************************************************************
    - 功能描述:SD卡初始化,针对于不同的SD卡,如MMC、SD或SDHC,初始化
                 方法是不同的
    - 参数说明:无
    - 返回说明:调用成功,返回0x00,否则返回错误码
    ******************************************************************/
    uint08 SD_Init(void)
    {
    uint08 time=0,r=0,i=0;        
    uint08 rbuf[4]={0};        
    uint08 pCMD0[6] ={0x40,0x00,0x00,0x00,0x00,0x95}; //CMD0,将SD卡从默认上电后的SD模式切换到SPI模式,使SD卡进入IDLE状态
    uint08 pCMD1[6] ={0x41,0x00,0x00,0x00,0x00,0x01}; //CMD1,MMC卡使用CMD1命令进行初始化
    uint08 pCMD8[6] ={0x48,0x00,0x00,0x01,0xAA,0x87}; //CMD8,用于鉴别SD卡的版本,并可从应答得知SD卡的工作电压
    uint08 pCMD16[6]={0x50,0x00,0x00,0x02,0x00,0x01}; //CMD16,设置扇区大小为512字节,此命令用于在初始化完成之后进行试探性的操作,
                                                              //如果操作成功,说明初始化确实成功
    uint08 pCMD55[6]={0x77,0x00,0x00,0x00,0x00,0x01}; //CMD55,用于告知SD卡后面是ACMD,即应用层命令 CMD55+ACMD41配合使用
                                                              //MMC卡使用CMD1来进行初始化,而SD卡则使用CMD55+ACMD41来进行初始化
    uint08 pACMD41H[6]={0x69,0x40,0x00,0x00,0x00,0x01}; //ACMD41,此命令用于检测SD卡是否初始化完成,MMC卡,不适用此命令,针对2.0的SD卡
    uint08 pACMD41S[6]={0x69,0x00,0x00,0x00,0x00,0x01}; //ACMD41,此命令用于检测SD卡是否初始化完成,MMC卡,不适用此命令,针对1.0的SD卡

    uint08 pCMD58[6]={0x7A,0x00,0x00,0x00,0x00,0x01}; //CMD58,用于鉴别SD2.0到底是SDHC,还是普通的SD卡,二者对扇区地址的寻址方式不同


    SPI_Init_M4();                                       // **关键步骤 SPI接口相关初始化

    SS_OFF;                                                 //片选禁用
            
    for(i=0;i<0x1f;i++)      //首先要发送最少31*8个时钟信号,这是必须的!激活SD卡
      (void)SPI_Rece();                           
    do
    {
       r=SD_Write_Cmd(pCMD0);                               //写入CMD0
       time++;
       if(time>=TRY_TIME) return(INIT_CMD0_ERROR);          //CMD0写入失败
      }while(r!=0x01);

      if(SD_Write_Cmd(pCMD8)==1)                             //写入CMD8,如果返回值为1,则SD卡版本为2.0
    {
            rbuf[0]=SPI_Rece(); rbuf[1]=SPI_Rece(); //读取4个字节的R7回应,通过它可知此SD卡是否支持2.7~3.6V的工作电压
            rbuf[2]=SPI_Rece(); rbuf[3]=SPI_Rece();         
            if(rbuf[2]==0X01 && rbuf[3]==0XAA)                    //SD卡是否支持2.7~3.6V
            {               
             time=0;
             do
             {
              (void)SD_Write_Cmd(pCMD55);//写入CMD55
                    r=SD_Write_Cmd(pACMD41H);//写入ACMD41,针对SD2.0
                    time++;
        if(time>=TRY_TIME) return(INIT_SDV2_ACMD41_ERROR);//对SD2.0使用ACMD41进行初始化时产生错误

       }while(r!=0);        

       if(0==SD_Write_Cmd(pCMD58)) //写入CMD58,开始鉴别SD2.0
       {
              rbuf[0]=SPI_Rece(); rbuf[1]=SPI_Rece(); //读取4个字节的OCR,其中CCS指明了是SDHC还是普通的SD
              rbuf[2]=SPI_Rece(); rbuf[3]=SPI_Rece();        
        if(rbuf[0]&0x40)
                    {
                     SD1_Ver=SD_VER_V2HC;    //SDHC卡        
                     SD1_Addr_Mode=1;        //SDHC卡的扇区寻址方式是扇区地址
                    }        
        else SD1_Ver=SD_VER_V2; //普通的SD卡,2.0的卡包含SDHC和一些普通的卡                                
       }
      }
    }
    else                       //SD V1.0或MMC
    {
            //SD卡使用ACMD41进行初始化,而MMC使用CMD1来进行初始化,依此来进一步判断是SD还是MMC
            (void)SD_Write_Cmd(pCMD55);//写入CMD55
            r=SD_Write_Cmd(pACMD41S);  //写入ACMD41,针对SD1.0

      if(r<=1)                  //检查返回值是否正确,如果正确,说明ACMD41命令被接受,即为SD卡
      {
             SD1_Ver=SD_VER_V1; //普通的SD1.0卡,一般来说容量不会超过2G
                            
             time=0;
             do
             {
                    (void)SD_Write_Cmd(pCMD55);//写入CMD55
                    r=SD_Write_Cmd(pACMD41S);//写入ACMD41,针对SD1.0
                    time++;
        if(time>=TRY_TIME)
        {
         return(INIT_SDV1_ACMD41_ERROR);//对SD1.0使用ACMD41进行初始化时产生错误
        }
       }while(r!=0);                        
      }
      else                 //否则为MMC        
            {
             SD1_Ver=SD_VER_MMC; //MMC卡,它不支持ACMD41命令,而是使用CMD1进行初始化
                            
             time=0;
       do
       {
        r=SD_Write_Cmd(pCMD1);//写入CMD1
        time++;
        if(time>=TRY_TIME)
        {
         return(INIT_CMD1_ERROR);//MMC卡使用CMD1命令进行初始化中产生错误
        }
       }while(r!=0);                        
      }
    }

    if(0!=SD_Write_Cmd(pCMD16)) //SD卡的块大小必须为512字节
    {
            SD1_Ver=SD_VER_ERR; //如果不成功,则此卡为无法识别的卡
            return INIT_ERROR;
    }        

      SS_OFF;
    (void)SPI_Rece(); //按照SD卡的操作时序在这里补8个时钟

    SPI_High_Rate();                      //SPI切到高速           // **函数调用

    return 0;//返回0,说明复位操作成功
    }

    /****************************************************************************
    - 功能描述:读取addr扇区的512个字节到buffer指向的数据缓冲区
    - 参数说明:addr:扇区地址
                 buffer:指向数据缓冲区的指针
    - 返回说明:调用成功,返回0x00,否则返回错误
    ****************************************************************************/
    uint08 SD_Read_Sector(uint32 addr,uint08 *buffer)//从SD卡的指定扇区中读出512个字节,使用CMD17
    {
    uint16 i;
    uint08 time,r;
    uint08 pCMD16[]={0x51,0x00,0x00,0x00,0x00,0xFF}; //CMD16的字节序列

    addr=addr<<=9;                     //sector = sector * 512将块地址(扇区地址)转为字节地址
            
    pCMD16[1]=(uint08)((addr&0xFF000000)>>24);                //将字节地址写入到CMD17字节序列中
    pCMD16[2]=(uint08)((addr&0x00ff0000)>>16);
    pCMD16[3]=(uint08)((addr&0x0000ff00)>>8);
    //pCMD17[4]=(uint08)addr;

    time=0;
    do
    {  
      r=SD_Write_Cmd(pCMD16);                     //写入CMD17
      time++;
      if(time==TRY_TIME) return(READ_BLOCK_ERROR); //读块失败
    }while(r!=0);
                               
                            
    while(SPI_Rece()!= 0xfe); //一直读,当读到0xfe时,说明后面的是512字节的数据了

    for(i=0;i<BufferSize;i++)                    //将数据写入到数据缓冲区中
       if(i<BufferSize) *(buffer++)=SPI_Rece();         


    SPI_Rece();
    SPI_Rece();       //两个字节的CRC校验码,不用关心
    _NOP();
    SS_OFF;
    //(void)SPI_Trans_Byte(0xFF);      //按照SD1卡的操作时序在这里补8个时钟

    return 0;
    }
    //============================================================================================
    /****************************************************************************
    - 功能描述:读取addr扇区开始的nsec个扇区的数据(★硬件多扇区读取)
    - 参数说明:nsec:扇区数
                 addr:开始扇区地址
                 buffer:指向数据缓冲区的指针
    - 返回说明:调用成功,返回0x00,否则返回错误码
    - 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率
    ****************************************************************************/
    uint08 FAT32_Device_Read_nSector(uint32 nsec,uint32 addr,uint08 *buffer)
    {
    uint08 r,time;
    uint32 i=0,j=0;
            
    uint08 pCMD18[6]={0x52,0x00,0x00,0x00,0x00,0x01}; //CMD18的字节序列
    uint08 pCMD12[6]={0x1C,0x00,0x00,0x00,0x00,0x01}; //CMD12,强制停止命令

    if(!SD1_Addr_Mode) addr<<=9; //sector = sector * 512           将块地址(扇区地址)转为字节地址

    pCMD18[1]=(uint08)(addr>>24); //将字节地址写入到CMD17字节序列中
    pCMD18[2]=(uint08)(addr>>16);
    pCMD18[3]=(uint08)(addr>>8);
    pCMD18[4]=(uint08)addr;        

    time=0;
    do
    {  
      r=SD_Write_Cmd(pCMD18); //写入CMD18
      time++;
      if(time==TRY_TIME)
      {
       return(READ_CMD18_ERROR); //写入CMD18失败
      }
    }while(r!=0);

    for(j=0;j<nsec;j++)
    {  
      while(SPI_Rece()!= 0xFE); //一直读,当读到0xfe时,说明后面的是512字节的数据了

      for(i=0;i<512;i++)         //将数据写入到数据缓冲区中        
       *(buffer++)=SPI_Rece();

      for(i=0;i<2;i++)
    (void)SPI_Rece(); //两个字节的CRC校验码,不用关心
    }

    (void)SD_Write_Cmd(pCMD12); //写入CMD12命令,停止数据读取

    SS_OFF;
    (void)SPI_Rece(); //按照SD卡的操作时序在这里补8个时钟

    return 0;
    }

    /****************************************************************************
    - 功能描述:获取SD卡的总扇区数(通过读取SD卡的CSD寄器组计算得到总扇区数)
    - 参数说明:无
    - 返回说明:返回SD卡的总扇区数
    - 注:无
    ****************************************************************************/
    uint32 SD_GetTotalSec(void)
    {
    uint08 pCSD[16];
    uint32 Capacity;  
    uint08 n,i;
    uint16 csize;

    uint08 pCMD9[6]={0x49,0x00,0x00,0x00,0x00,0x01}; //CMD9        

    if(SD_Write_Cmd(pCMD9)!=0) //写入CMD9命令
    {
            return GET_CSD_ERROR; //获取CSD时产生错误
    }

    while(SPI_Rece()!= 0xFE); //一直读,当读到0xfe时,说明后面的是16字节的CSD数据

    for(i=0;i<16;i++) pCSD=SPI_Rece(); //读取CSD数据

    for(i=0;i<2;i++)
    (void)SPI_Rece(); //两个字节的CRC校验码,不用关心

      SS_OFF;
    (void)SPI_Rece(); //按照SD卡的操作时序在这里补8个时钟
            
    //如果为SDHC卡,即大容量卡,按照下面方式计算
    if((pCSD[0]&0xC0)==0x40)          //SD2.0的卡
    {        
            csize=pCSD[9]+(((uint16)(pCSD[8]))<<8)+1;
        Capacity=((uint32)csize)<<10;//得到扇区数                           
    }
    else //SD1.0的卡
    {        
            n=(pCSD[5]&0x0F)+((pCSD[10]&0x80)>>7)+((pCSD[9]&0x03)<<1)+2;
            csize=(pCSD[8]>>6)+((uint16)pCSD[7]<<2)+((uint16)(pCSD[6]&0x03)<<0x0A)+1;
            Capacity=((uint32)csize)<<(n-9);//得到扇区数   
    }
    return Capacity;
    }

    //This is the end




    //---------------------------fat32.h----------------------------------------------
    //===========================================================
    //基于AVR单片机FAT32文件系统程序
    //创建时间:2016/3/22
    //创建者 :Chen Yanan
    //============================================================
    #include "main.h"

    #ifndef _FAT32_H_
    #define _FAT32_H_


    //FAT32的裁减宏:

    //====================以下是FAT32的功能函数裁减宏,要使用到哪个功能函数,请将相应宏的注释去掉
    //#define FAT32_FLUSH_FS  //刷新文件系统  如果没有使用RT_UPDATE_FSINFO,则在所有的文件操作完成之后,需要调用此函数

    #define FAT32_OPEN_FILE  //打开文件
    #define FAT32_CLOSE_FILE //关闭文件
    #define FAT32_READDATA   //文件数据读取
    //#define FAT32_READDATAX  //文件数据读取+重定向 此函数会将读取的每个字节送到处理函数,处理函数由使用者提供,请看宏Data_Redirect

    //#define FAT32_CREATE_FILE //创建文件
    //#define FAT32_DELETE_FILE //删除文件
    //#define FAT32_WRITEDATA //写入数据,写入数据均是从文件的末尾追加数据
    //#define FAT32_MODIFY_DATA //数据修改

    //===================================================================================================================================

    //#define TOV_CNT (200) //存储设备扇区读写重试次数,如果次数超过此值,仍然失败,则会导致物理设备的IO错误
    //=================================================================================================================================

    //CCCB,压缩簇链缓冲,是FAT32中所使用簇链缓冲算法,它可以极大的提高数据写入的速度
    #define CCCB_LEN (8)   //簇链缓冲的长度,必须为偶数,且不小于4

    //#define Data_Redirect UART_Send_Byte //数据重定向函数名定义  


    /*========================文件函数关系=====================*/
    //打开文件所用函数
    #ifdef  FAT32_OPEN_FILE
    #define FAT32_ENTER_DIR
    #define GET_DIR_START_CLUSTER
    #define CHECK_SFN_ILLEGAL_LENGTH
    #define CHECK_SFN_DOT
    #define CHECK_ILLEGAL_CHAR
    #define CHECK_SFN_SPECIAL_CHAR
    #define CHECK_SFN_ILLEGAL_LOWER
    #define TO_FILE_NAME
    #define SFN_MATCH
    #define FINDSUBSTR
    #define GET_NEXT_CLUSTER
    #define IS_WILDFILENAME
    #define ANALYSE_FDI
    #endif
    //读数据
    #ifdef  FAT32_READDATA
    #define FAT32_SEEK
    #define GET_NEXT_CLUSTER
    #define GET_NEXT_CLUSTER
    #endif



    //==========================================================================================
    #define MBR_SECTOR (0)            //MBR扇区
    #define DBR_MARK {0XEB,0X58,0X90} //DBR的标志码

    //#define FDI_NBYTES (32)           //文件目录项所占字节数
    #define NFDI_PER_SEC (16)         //每扇区的文件目录项数

    #define FAT32_BUF_SIZE (512) //FAT32内部缓冲区大小
    //-------------------------------------------------------------------------------------------
    #define SOC(c)  (((c-2)*(pInit_Args->SectorsPerClust))+(pInit_Args->FirstDirSector)) //计算簇的开始扇区 Start Sector Of Cluster

    #define NFATITEMBYTES   (4)                                                               //FAT表项所占用的字节数
    #define NITEMSINFATSEC  (128)                                                             //FAT表一个扇区中包含的表项数

    #define IS_END_CLU(cluster) ((0X0FFFFFFF)==(cluster))                                       //判断一个簇项的值是否是结束簇
    #define IS_END_SEC_OF_CLU(sec,cluster) ((sec-SOC(cluster))==(pInit_Args->SectorsPerClust-1)) //判断是否是簇的最后一个扇区
    #define LAST_SEC_OF_CLU(cluster) (SOC(cluster)+(pInit_Args->SectorsPerClust-1))              //簇的最后一个扇区的地址
    #define IS_FAT32_TYPE(FST) (('F'==(FST[0])) && ('A'==(FST[1])) && ('T'==(FST[2])) && ('3'==(FST[3])) && ('2'==(FST[4]))) //检验文件系统是否FAT32

    #define CHK_ATTR_FILE(attr) ((!((attr&0X10)!=0X00)) && (0X0F!=attr) && (0X00!=attr) && (0X08!=attr)) //属性字节第4位为0,同时不是长名属性0X0F,空项或卷标
    #define CHK_ATTR_DIR(attr) ((attr&0X10)!=0X00)                                               //属性字节第4位为
    #define Lower2Up(c) ((c>='a' && c<='z')?(c-32):c)
    #define Upper2Low(C) ((C>='A' && C<='Z')?(C+32):C)

    #define BOOL_TRUE     (1)
    #define BOOL_FALSE    (0)
    #define NUL_RET  (0)
    //#define NUL_PTR  ((void *)0)


    //=================错误码=======================
    #define ERR_SUCC                  (0)
    #define ERR_FAIL                  (1)
    #define FSTYPE_NOT_FAT32          (2)
    #define ERR_NO_FILE               (3)
    #define ERR_NO_DIR                (4)
    #define ERR_ILL_CHAR              (5)
    #define ERR_SFN_ILL_LEN                  (6)


    //================================================


    //DPT:分区记录结构如下
    typedef struct
    {
    uint08 Active;         //0x80表示此分区有效
    uint08 StartHead;      //分区的开始磁头
    uint08 StartSect;      //开始扇区
    uint08 StartCyl;       //开始柱面
    uint08 PartType;       //分区类型
    uint08 EndHead;        //分区的结束头
    uint08 EndSect;        //结束扇区
    uint08 EndCyl;         //结束柱面
    uint08 StartLBA[4];    //分区的第一个扇区
    uint08 Size[4];        //分区的大小,总扇区数
    }DPT_Item;
    //MBR:分区扇区(绝对0扇区)定义如下
    typedef struct
    {
    uint08   PartCode[446]; //MBR的引导程序
    DPT_Item Part[4];       //4个分区记录
    uint08   BootSectSig0;  //55
    uint08   BootSectSig1;  //AA
    }MBR;
    //FAT32中对BPB的定义如下  一共占用90个字节
    typedef struct
    {uint08 BS_jmpBoot[3];     //跳转指令            offset:0
    uint08 BS_OEMName[8];     //OEM名称             offset:3
    uint08 BPB_BytesPerSec[2];//每扇区字节数        offset:11
    uint08 BPB_SecPerClus;    //每簇扇区数          offset:13
    uint08 BPB_RsvdSecCnt[2]; //保留扇区数目        offset:14
    uint08 BPB_NumFATs;       //此卷中FAT表数       offset:16
    uint08 BPB_RootEntCnt[2]; //FAT32为0            offset:17
    uint08 BPB_TotSec16[2];   //FAT32为0            offset:19
    uint08 BPB_Media;         //存储介质            offset:21
    uint08 BPB_FATSz16[2];    //FAT32为0            offset:22
    uint08 BPB_SecPerTrk[2];  //磁道扇区数          offset:24
    uint08 BPB_NumHeads[2];   //磁头数              offset:26
    uint08 BPB_HiddSec[4];    //FAT区前隐扇区数     offset:28
    uint08 BPB_TotSec32[4];   //该卷总扇区数        offset:32
    uint08 BPB_FATSz32[4];    //一个FAT表扇区数     offset:36
    uint08 BPB_ExtFlags[2];   //FAT32特有           offset:40
    uint08 BPB_FSVer[2];      //FAT32特有           offset:42
    uint08 BPB_RootClus[4];   //根目录簇号          offset:44
    uint08 FiSInfo[2];        //保留扇区FSINFO扇区数offset:48
    uint08 BPB_BkBootSec[2];  //通常为6             offset:50
    uint08 BPB_Reserved[12];  //扩展用              offset:52
    uint08 BS_DrvNum;         //                    offset:64
    uint08 BS_Reserved1;      //                    offset:65
    uint08 BS_BootSig;        //                    offset:66
    uint08 BS_VolID[4];       //                    offset:67
    uint08 BS_FilSysType[11]; //                           offset:71
    uint08 BS_FilSysType1[8]; //"FAT32"             offset:82
    } DBR;

    //FAT32中对文件目录项的定义如下一共占用32个字节
    typedef struct
    {
    uint08 Name[8];        // 文件名,不足部分以空格补充
    uint08 Extension[3];         // 扩展名,不足部分以空格补充
    uint08 Attributes;           // 文件属性
    uint08 LowerCase;            // 0
    uint08 CTime10ms;             // 创建时间的10毫秒位
    uint08 CTime[2];             // 创建时间
    uint08 CDate[2];             // 创建日期
    uint08 ADate[2];             // 访问日期
    uint08 HighClust[2];   // 开始簇的高字
    uint08 MTime[2];             // 最近的修改时间
    uint08 MDate[2];             // 最近的修改日期
    uint08 LowClust[2];           // 开始簇的低字
    uint08 FileSize[4];      // 文件大小
    } FDI;
    //FAT32中对文件系统信息结构的定义
    typedef  struct  
    {
    uint08 Head[4]; //"RRaA"
    uint08 Resv1[480];
    uint08 Sign[4]; //"rrAa"
    uint08 Free_Cluster[4]; //剩余空簇数
    uint08 Next_Free_Cluster[4]; //下一空簇参考值
    uint08 Resv2[14];
    uint08 Tail[2]; //"55 AA"
    }FSInfo;
    //-----------------------------------
    typedef struct
    {
    FDI FDIes[16]; //扇区中的文件目录项数组 16
    }FDIesInSEC;
    //----------------------------------------
    typedef struct
    {
    uint16 year;
    uint08 month;
    uint08 day;
    }Date;

    typedef struct
    {
    uint08 hour;
    uint08 min;
    uint08 sec;
    }Time;

    typedef struct  //日期与时间
    {
      Date date; //日期
      Time time; //时间
    }DateTime;

    extern DateTime dt; //全局变量----------------------------------

    typedef struct   //FAT32中对FAT表项的结构定义
    {
    uint08 Item[4]; //FAT32中FAT表项占用4个字节,即32位
    } FAT_Item;
    typedef struct         //FAT32中对FAT表扇区结构的定义
    {
    FAT_Item items[NITEMSINFATSEC]; //FAT扇区包含128个FAT表项
    }FAT_Sec;


    #define DATE_YEAR_BASE (1980)
    #define TIME_HOUR_MARK  (0X001F)
    #define TIME_MIN_MARK   (0X002F)
    #define TIME_SEC_MARK   (0X001F)

    #define DATE_YEAR_MARK  (0X007F)
    #define DATE_MONTH_MARK (0X000F)
    #define DATE_DAY_MARK   (0X001F)

    #define TIME_HOUR_NBITS   (5)
    #define TIME_MIN_NBITS    (6)
    #define TIME_SEC_NBITS    (5)

    #define DATE_YEAR_NBITS   (7)
    #define DATE_MONTH_NBITS  (4)
    #define DATE_DAY_NBITS    (5)

    //FAT32初始化时初始参数装入如下结构体中
    typedef struct
    {
    uint32 BPB_Sector_No;   //DBR(BPB)所在扇区号
    uint32 Total_SizeKB;    //磁盘的总容量,单位为KB
    uint32 BytesPerSector;         //每个扇区的字节数
    uint32 FATsectors;      //FAT表所占扇区数
    uint32 SectorsPerClust; //每簇的扇区数
    uint32 FirstFATSector;         //第一个FAT表所在扇区
    uint32 FirstDirSector;         //第一个目录所在扇区
    uint32 FSINFO_Sec;      //FSINFO扇区所在的扇区
    uint32 Free_nCluster;   //空闲簇的个数
    uint32 Next_Free_Cluster; //下一空簇
    }FAT32_Init_Args;

    extern FAT32_Init_Args Init_Args,*pInit_Args;  //初始化参数结构体指针,用以指向某一存储设备的初始化参数集合

    //FAT32中对文件信息集合的定义
    typedef struct
    {
    sint08 File_Name[13];          //完整文件名 EX:text.txt
    sint08 File_Attr;                    //文件属性
    Time   File_CTime;       //文件创建时间
    Date   File_CDate;       //文件创建日期
    uint32 File_StartClust;  //文件开始簇
    uint32 File_Size;                    //文件大小
    uint32 File_CurClust;    //文件当前簇
    uint32 File_CurSec;      //文件当前扇区
    uint16 File_CurPos;            //文件当前扇区偏移量
    uint08 File_IsEOF;       //文件是否到达结束位置
    uint32 File_CurOffset;          //文件当前偏移量
    uint32 FDI_Sec;          //文件目录项所在的扇区
    uint08  nFDI;            //文件目录项在扇区中的索引
    }FileInfo;

    extern FileInfo fileinfo; //全局变量,文件信息集合


      //函数声明
    //以下是对用户可用的函数的声明
    uint08 FAT32_Init(void);
    uint08 FAT32_Device_Init(void); //存储设备初始化,底层驱动接口
    uint08 FAT32_Device_Read_Sector(uint32 addr,uint08 *buf);
    uint08 To_File_Name(sint08 *name_in_fdi,sint08 *pfileName);
    uint08 SFN_Match(sint08 *t,sint08*s);
    uint08 FAT32_Enter_Dir(sint08 *dirpath,uint32 *pCluster,uint32 *pos); //进入目录
    uint08 Analyse_FDI( FileInfo *pfi, FDI *pFDI); //目录项解析
    uint32 FAT32_ReadData(FileInfo *pFI,uint32 offset,uint32 len,uint08 *app_Buffer); //数据读取
    uint08 FAT32_Seek(FileInfo *pFI,uint32 offset); //文件定位
    uint08 FAT32_Open_File(FileInfo *pFI,sint08 *filepath,uint32 n,uint08 is_file); //文件打开
    uint08 FAT32_Close_File(FileInfo *pfi); //关闭文件,如果程序中没有打开实时文件大小更新,则文件操作完后,尤其是写入和更改操作,必须调用此函数


    //----------------------------------------------------------------------------------------------
    #endif




    //------------------------------------------main.h---------------------------------------
    #ifndef _MAIN_H_
    #define _MAIN_H_
    //数据类型宏定义
    typedef unsigned char uint08;
    typedef signed   char sint08;
    typedef unsigned int  uint16;
    typedef signed   int  sint16;
    typedef unsigned long uint32;
    //变量定义
    #define BufferSize      512 //数据缓冲区,不可超过512

    void Init_Timer0(void);
    void delayms(uint16 u16count);
    void Init_Clock(void);
    void Init_watchdog(void);
    void Init_Port(void);
    void Init_USART0(void);
    void delayms(uint16 u16count);
    void USART_Send(uint08 data);
    void SCI_Send_Str(uint08 *str) ;
    void EEPROM_Write(uint16 add,uint08 dat);
    uint08 EEPROM_Read(uint16 Add);
    void SCI_Put_Inf(uint08 *inf,uint32 dat);
    void SCI_Put_Num(uint32 dat);

    void SPI_Init_M3(void);
    void SPI_Init_M4(void);
    uint08 SD_Init(void);
    uint08 SD_Read_Sector(uint32 addr,uint08 *buffer);//从SD卡的指定扇区中读出512个字节,使用CMD17
    uint08 SD_Read_nSector(uint32 nsec,uint32 addr,uint08 *buffer);
    //uint08 SD_Write_Sector(uint32 addr,uint08 *buffer);
    uint32 SD_TotalSector(void);
    void SCI_Send_Str(uint08 *str);

    uint08 SD_Read_Sector(uint32 addr,uint08 *buffer);         //从地址为addr的扇区中读取数据到buffer数据缓冲区中
    //文件系统部分
    uint08 FAT32_Device_Read_nSector(uint32 nsec,uint32 addr,uint08 *buffer); //将buffer数据缓冲区中的数据写入起始地址为addr的nsec个连续扇区中
    uint32 SD_GetTotalSec(void);                                  //获取SD卡的总扇区数

    #endif




    //---------------------------------------------sdinit.h---------------------------------------
    #ifndef _SDINIT_H_
    #define _SDINIT_H_


    #define TRY_TIME 200   //读TRY_TIME次,如果在TRY_TIME次中读不到回应,产生超时错误,命令写入失败

    //相关宏定义
    //-------------------------------------------------------------
    #define SD_VER_ERR     0X00
    #define SD_VER_MMC     0X01
    #define SD_VER_V1      0X02
    #define SD_VER_V2      0X03
    #define SD_VER_V2HC    0X04


    #define INIT_ERROR                  0x01 //初始化错误
    #define INIT_CMD0_ERROR             0x02 //CMD0错误
    #define INIT_CMD1_ERROR             0x03 //CMD1错误
    #define INIT_SDV2_ACMD41_ERROR            0x04 //ACMD41错误
    #define INIT_SDV1_ACMD41_ERROR            0x05 //ACMD41错误
    #define READ_BLOCK_ERROR            0x08 //读块错误

    #define READ_CMD18_ERROR            0x0B //在连续多块读时产生CMD18错误

    #define GET_CSD_ERROR               0x0C //读CSD失败
    //#define SPI_WRITE_ERROR             0x0D //在连续多块读时产生CMD18错误
    //#define SPI_READ_ERROR              0x0E //读CSD失败


    #endif

    fat32.zip

    21.05 KB, 下载次数: 33

    剕常感謝大大大分享,下來研究一下
    starrain 来自手机 新手上路 2016-7-9 13:31
    沙发
    6666666666
    请问楼主,声明的那些函数都是啥呀?方不方便提供一下?
    在main.h里的那些void
    icebee250 发表于 2017-12-30 10:44
    请问楼主,声明的那些函数都是啥呀?方不方便提供一下?

    下下来,都在.C文件里面
    发新帖
    发表评论
    高级模式  
    您需要登录后才可以回帖 登录 | 立即注册  
    关闭

    推荐主题 上一条 /2 下一条