使用AVR单片机读取SD卡文件(FAT32文件系统)
参考为删减的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;
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_OFFPORTB|=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);
if(pcmd==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={0};
uint08 pCMD0 ={0x40,0x00,0x00,0x00,0x00,0x95}; //CMD0,将SD卡从默认上电后的SD模式切换到SPI模式,使SD卡进入IDLE状态
uint08 pCMD1 ={0x41,0x00,0x00,0x00,0x00,0x01}; //CMD1,MMC卡使用CMD1命令进行初始化
uint08 pCMD8 ={0x48,0x00,0x00,0x01,0xAA,0x87}; //CMD8,用于鉴别SD卡的版本,并可从应答得知SD卡的工作电压
uint08 pCMD16={0x50,0x00,0x00,0x02,0x00,0x01}; //CMD16,设置扇区大小为512字节,此命令用于在初始化完成之后进行试探性的操作,
//如果操作成功,说明初始化确实成功
uint08 pCMD55={0x77,0x00,0x00,0x00,0x00,0x01}; //CMD55,用于告知SD卡后面是ACMD,即应用层命令 CMD55+ACMD41配合使用
//MMC卡使用CMD1来进行初始化,而SD卡则使用CMD55+ACMD41来进行初始化
uint08 pACMD41H={0x69,0x40,0x00,0x00,0x00,0x01}; //ACMD41,此命令用于检测SD卡是否初始化完成,MMC卡,不适用此命令,针对2.0的SD卡
uint08 pACMD41S={0x69,0x00,0x00,0x00,0x00,0x01}; //ACMD41,此命令用于检测SD卡是否初始化完成,MMC卡,不适用此命令,针对1.0的SD卡
uint08 pCMD58={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=SPI_Rece(); rbuf=SPI_Rece(); //读取4个字节的R7回应,通过它可知此SD卡是否支持2.7~3.6V的工作电压
rbuf=SPI_Rece(); rbuf=SPI_Rece();
if(rbuf==0X01 && rbuf==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=SPI_Rece(); rbuf=SPI_Rece(); //读取4个字节的OCR,其中CCS指明了是SDHC还是普通的SD
rbuf=SPI_Rece(); rbuf=SPI_Rece();
if(rbuf&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=(uint08)((addr&0xFF000000)>>24); //将字节地址写入到CMD17字节序列中
pCMD16=(uint08)((addr&0x00ff0000)>>16);
pCMD16=(uint08)((addr&0x0000ff00)>>8);
//pCMD17=(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={0x52,0x00,0x00,0x00,0x00,0x01}; //CMD18的字节序列
uint08 pCMD12={0x1C,0x00,0x00,0x00,0x00,0x01}; //CMD12,强制停止命令
if(!SD1_Addr_Mode) addr<<=9; //sector = sector * 512 将块地址(扇区地址)转为字节地址
pCMD18=(uint08)(addr>>24); //将字节地址写入到CMD17字节序列中
pCMD18=(uint08)(addr>>16);
pCMD18=(uint08)(addr>>8);
pCMD18=(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;
uint32 Capacity;
uint08 n,i;
uint16 csize;
uint08 pCMD9={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&0xC0)==0x40) //SD2.0的卡
{
csize=pCSD+(((uint16)(pCSD))<<8)+1;
Capacity=((uint32)csize)<<10;//得到扇区数
}
else //SD1.0的卡
{
n=(pCSD&0x0F)+((pCSD&0x80)>>7)+((pCSD&0x03)<<1)+2;
csize=(pCSD>>6)+((uint16)pCSD<<2)+((uint16)(pCSD&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 //数据重定向函数名定义
/*========================文件函数关系=====================*/
//打开文件所用函数
#ifdefFAT32_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
//读数据
#ifdefFAT32_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)) && ('A'==(FST)) && ('T'==(FST)) && ('3'==(FST)) && ('2'==(FST))) //检验文件系统是否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; //分区的第一个扇区
uint08 Size; //分区的大小,总扇区数
}DPT_Item;
//MBR:分区扇区(绝对0扇区)定义如下
typedef struct
{
uint08 PartCode; //MBR的引导程序
DPT_Item Part; //4个分区记录
uint08 BootSectSig0;//55
uint08 BootSectSig1;//AA
}MBR;
//FAT32中对BPB的定义如下一共占用90个字节
typedef struct
{uint08 BS_jmpBoot; //跳转指令 offset:0
uint08 BS_OEMName; //OEM名称 offset:3
uint08 BPB_BytesPerSec;//每扇区字节数 offset:11
uint08 BPB_SecPerClus; //每簇扇区数 offset:13
uint08 BPB_RsvdSecCnt; //保留扇区数目 offset:14
uint08 BPB_NumFATs; //此卷中FAT表数 offset:16
uint08 BPB_RootEntCnt; //FAT32为0 offset:17
uint08 BPB_TotSec16; //FAT32为0 offset:19
uint08 BPB_Media; //存储介质 offset:21
uint08 BPB_FATSz16; //FAT32为0 offset:22
uint08 BPB_SecPerTrk;//磁道扇区数 offset:24
uint08 BPB_NumHeads; //磁头数 offset:26
uint08 BPB_HiddSec; //FAT区前隐扇区数 offset:28
uint08 BPB_TotSec32; //该卷总扇区数 offset:32
uint08 BPB_FATSz32; //一个FAT表扇区数 offset:36
uint08 BPB_ExtFlags; //FAT32特有 offset:40
uint08 BPB_FSVer; //FAT32特有 offset:42
uint08 BPB_RootClus; //根目录簇号 offset:44
uint08 FiSInfo; //保留扇区FSINFO扇区数offset:48
uint08 BPB_BkBootSec;//通常为6 offset:50
uint08 BPB_Reserved;//扩展用 offset:52
uint08 BS_DrvNum; // offset:64
uint08 BS_Reserved1; // offset:65
uint08 BS_BootSig; // offset:66
uint08 BS_VolID; // offset:67
uint08 BS_FilSysType; // offset:71
uint08 BS_FilSysType1; //"FAT32" offset:82
} DBR;
//FAT32中对文件目录项的定义如下一共占用32个字节
typedef struct
{
uint08 Name; // 文件名,不足部分以空格补充
uint08 Extension; // 扩展名,不足部分以空格补充
uint08 Attributes; // 文件属性
uint08 LowerCase; // 0
uint08 CTime10ms; // 创建时间的10毫秒位
uint08 CTime; // 创建时间
uint08 CDate; // 创建日期
uint08 ADate; // 访问日期
uint08 HighClust; // 开始簇的高字
uint08 MTime; // 最近的修改时间
uint08 MDate; // 最近的修改日期
uint08 LowClust; // 开始簇的低字
uint08 FileSize; // 文件大小
} FDI;
//FAT32中对文件系统信息结构的定义
typedefstruct
{
uint08 Head; //"RRaA"
uint08 Resv1;
uint08 Sign; //"rrAa"
uint08 Free_Cluster; //剩余空簇数
uint08 Next_Free_Cluster; //下一空簇参考值
uint08 Resv2;
uint08 Tail; //"55 AA"
}FSInfo;
//-----------------------------------
typedef struct
{
FDI FDIes; //扇区中的文件目录项数组 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; //FAT32中FAT表项占用4个字节,即32位
} FAT_Item;
typedef struct //FAT32中对FAT表扇区结构的定义
{
FAT_Item items; //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; //完整文件名 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; //文件目录项所在的扇区
uint08nFDI; //文件目录项在扇区中的索引
}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 intuint16;
typedef signed intsint16;
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
剕常感謝大大大分享,下來研究一下 6666666666 请问楼主,声明的那些函数都是啥呀?方不方便提供一下? 在main.h里的那些void icebee250 发表于 2017-12-30 10:44
请问楼主,声明的那些函数都是啥呀?方不方便提供一下?
下下来,都在.C文件里面 谢谢啦!慢慢看。
页:
[1]