在windows vc++环境下实现对fatfs文件系统操作(新手分享,请多多指教)

2019-08-14 05:36发布

本帖最后由 zhuzhutang 于 2017-8-25 21:26 编辑

     由于对文件系统比较感兴趣,所以早就想学习一下文件系统了,听说fatfs文件系“统麻雀虽小五脏俱全”,而且移植也挺方便的,于是就从这个系统下手吧。
     既来之则安之!
     于是找来了一块stm32f103rct6的最小系统板,再从旧手机上把里面的TF卡拆出来,装到micro sd adapter卡套上,用TF卡作为fatfs文件系统的媒介。然后对了一下micro sd adapter和TF卡的引脚关系,最后把micro sd adapter对应的引脚焊接到stm32f103rct6的SPI1引脚上,打算通过SPI口访问TF卡。硬件平台算是这么粗暴的搭建好了。
     接下来就参考正点原子的 “ALIENTEK MINISTM32 实验28 SD卡实验” 这一例程,东改一下西裁一下,只保留对SD卡操作那一部分代码,跌跌撞撞的搞了差不多一天,终于是可以读TF卡的数据了,也可以对其写数据了。
     OK,底层是通了,接下来就是移植fatfs系统了,于是我从官网上:http://elm-chan.org/fsw/ff/00index_e.html,下载了最新版本的(ff13版本)源码,又在网上查了一下fatfs的移植,其实fatfs系统的移植真的是挺简单的,就只需要修改diskio.c这个与平台相关的文件,填几个函数的内容,再不就是根据自己的需要修改ffconf.h文件来获得自己想要的东西。然后再根据“ALIENTEK MINISTM32 实验29 FATFS文件系统实验”这一例程,很快就完成了移植。移植完之后把TF卡格式化一下,马上开始了测试,很顺利,挂载、打开文件、关闭文件都没问题。然后再花一天时间去实现什么删除文件、复制文件、复制文件夹啊等等乱七八糟的功能,最后再结合串口输入输出,做了一个像命令解释器这样的功能,比如像输出 “ls”,串口就会打印当前路径下的文件和文件夹。如下图所示:
                                                                                 1.png                             后来想想,在调试阶段,对文件进行操作后,总是要把TF卡拿出来再放到电脑上看操作有没有生效,经常这样拔来拔去,心里很是不爽,于是在想,能不能在windows下操作fatfs啊, 这样就方便很多了啊。于是上网查了一下,还果真有,不过说得比较少。我就参考了这篇文章:http://blog.csdn.net/liangjiapei/article/details/65444536。然后在windows下就可以模拟测试fatfs了。以下是本人的一些历程,今天分享出来,也算是给自己留一个笔记。
     具体的操作我就不多说了,上面链接文章中已经说得挺好的了,只是有些事项我想说明一下:
     1、使用mksdcard创建一个虚拟SD卡文件时,先运行cmd,进入你放mksdcard.exe这个工具的目录,然后再执行mksdcard.exe 128M Test.img才有效。
下面贴一下代码:
main.c  :
#include <stdio.h>
#include <stdlib.h>
#include "ff.h"
#include "integer.h"
#include "diskio.h"


#define  PRINT_ENABLE    /*是否允许打印信息*/

#if (defined PRINT_ENABLE)
#define  MY_PRINTF    printf
#else
void  MY_PRINTF(char *format, ...)
{

}  
#endif

#define  ASSERT_PARAM(x)  while(x==NULL){  }


FATFS * fs[1];   /*文件系统对象指针*/
FIL * file1;     /*文件对象指针*/

/*------------------------------ 提示信息 -----------------------------*/
const char * tip[]=
{
        "FR_OK ,                        (0) Succeeded",
        "FR_DISK_ERR,                (1) A hard error occurred in the low level disk I/O layer" ,
        "FR_INT_ERR,                (2) Assertion failed",
        "FR_NOT_READY,                (3) The physical drive cannot work" ,
        "FR_NO_FILE,                (4) Could not find the file" ,
        "FR_NO_PATH,                (5) Could not find the path" ,
        "FR_INVALID_NAME,        (6) The path name format is invalid.",
        "FR_DENIED,                        (7) Access denied due to prohibited access or directory full ",
        "FR_EXIST,                        (8) Access denied due to prohibited access ",
        "FR_INVALID_OBJECT,        (9) The file/directory object is invalid ",
        "FR_WRITE_PROTECTED,(10) The physical drive is write protect." ,
        "FR_INVALID_DRIVE,        (11) The logical drive number is invalid" ,
        "FR_NOT_ENABLED,        (12) The volume has no work area",
        "FR_NO_FILESYSTEM,        (13) There is no valid FAT volume" ,
        "FR_MKFS_ABORTED,        (14) The f_mkfs() aborted due to any problem" ,
        "FR_TIMEOUT,                (15) Could not get a grant to access the volume within defined period" ,
        "FR_LOCKED,                        (16) The operation is rejected according to the file sharing policy" ,
        "FR_NOT_ENOUGH_CORE,         (17) LFN working buffer could not be allocated" ,
        "FR_TOO_MANY_OPEN_FILES, (18) Number of open files > FF_FS_LOCK" ,
        "FR_INVALID_PARAMETER         (19) Given parameter is invalid" ,
} ;



/*-----------------------------------------------------------------------*/
/* 挂载设备                      */
/*-----------------------------------------------------------------------*/
void MountDevice(FATFS * fs, const BYTE * str, BYTE opt)
{
        FRESULT res;

        ASSERT_PARAM(fs);

        res = f_mount(fs, str, opt);
        if(res==RES_OK)  
        {
                MY_PRINTF("Mount success! ");
                MY_PRINTF("file csize is %d. ", fs->csize);
                MY_PRINTF("file fsize is %d. ", fs->fsize);
                MY_PRINTF("file n_fats is %d. ", fs->n_fats);
        }
        else            
        {
                MY_PRINTF("Mount fail! %s ",tip[res]);
        }
}



int main(void)
{
        FRESULT  res;
        UINT fre_clust=0;
        UINT bw=0, br=0, num2read=0;
        UINT pos=0;
        const BYTE * str = "1234567890!";
        BYTE * pstr;

        /**------------------ 为文件系统对象和文件对象申请内存空间 -------------------**/
        file1 = malloc(sizeof(FIL));
        if(file1!=NULL)  
        {
                MY_PRINTF("Malloc FIL space success! ");
        }
        else      
        {
                MY_PRINTF("Malloc FIL space fail! ");
        }

        fs[0] = malloc(sizeof(FATFS));
        if(fs[0]!=NULL)  
        {
                MY_PRINTF("Malloc FATFS space success! ");
        }
        else      
        {
                MY_PRINTF("Malloc FATFS space fail! ");
        }

        /**------------------ 挂载一个设备 -------------------**/
        MountDevice(fs[0], "0:", 1);


        /**----------------------- 打开文件 ------------------**/
        res = f_open(file1,  "0:/zrt.txt", FA_OPEN_ALWAYS | FA_WRITE);
        if(res==RES_OK)  
        {
                MY_PRINTF("Open file success! ");
        }
        else            
        {
                MY_PRINTF("Open file fail! %s ",tip[res]);
        }

    /*-------------------------- 写文件 -------------------------*/
        //f_lseek(file1, f_size(file1));   /*定位到文件的结尾,从文件结尾开始写数据*/
        res = f_write(file1, str, strlen(str), &bw);
        if(res==RES_OK)  
        {
                MY_PRINTF("Write file success! ");
        }
        else            
        {
                MY_PRINTF("Write file fail! %s ",tip[res]);
        }  

        /* 关闭打开的文件。注意:如果对文件进行了修改,一定要关闭文件修改才能起效,如果做了修改不关闭文件,用UltraISO打开SD卡镜像时内容是没有同步更新的 */
        res = f_close(file1);
        if(res==RES_OK)  
        {
                MY_PRINTF("close file success! ");
        }
        else            
        {
                MY_PRINTF("close file fail! %s ",tip[res]);
        }

        
        /**----------------------- 打开文件 ------------------**/
        res = f_open(file1,  "0:/zrt.txt", FA_OPEN_EXISTING | FA_READ);
        if(res==RES_OK)  
        {
                MY_PRINTF("Open file success! ");
        }
        else            
        {
                MY_PRINTF("Open file fail! %s ",tip[res]);
        }

        /***-------------------------- 读文件 ------------------------**/
        pstr = malloc(FF_MAX_SS);
    MY_PRINTF("This file size is %d byte. ",f_size(file1));   /*打印文件大小*/
        while(res == RES_OK)
        {
                res = f_read(file1, pstr, FF_MAX_SS, &br);  /*一次读的大小不能超过FF_MAX_SS,不然会造成数组越界,在free内存时出现异常*/
                for(num2read=0; num2read<br; num2read++)
                {
                        //putchar(pstr[num2read]);
                        MY_PRINTF("%c",pstr[num2read]);
                }
                if(br == 0)   
                {
                        break;
                }
        }
        free(pstr); /** 释放pstr所占内存 **/
        
    MY_PRINTF(" ");


    /*------------------------------------- 关闭打开的文件 ------------------------------*/
        res = f_close(file1);
        if(res==RES_OK)  
        {
                MY_PRINTF("close file success! ");
        }
        else            
        {
                MY_PRINTF("close file fail! %s ",tip[res]);
        }


        /*----------- 释放空间 -------------*/
        free(file1);
        free(fs[0]);  

        return 0;
}


diskio.c  :
#include <Windows.h>
#include <stdio.h>
#include "diskio.h"                /* FatFs lower layer API */


#define     SECTOR_SIZE 512

FILE *fpImg = 0;   /*FILE是系统自带的结构体*/

/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
        BYTE pdrv                /* Physical drive nmuber to identify the drive */
)
{
        if (pdrv == 0)  
    {  
        return RES_OK;  
    }  

    return STA_NOINIT;
}



/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
        BYTE pdrv                                /* Physical drive nmuber to identify the drive */
)
{
        if (pdrv == 0)  
    {  
        if (!fpImg)  
        {         
                        fpImg = fopen("./MMC_SD.img", "rb+");   /*打开本目录下的MMC_SD.img文件,这里就是把SD卡的镜像文件挂载进来*/
            if (fpImg == NULL)
                        {
                return STA_NOINIT;  
                        }
        }  
        return RES_OK;  
    }
        return RES_ERROR;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
        BYTE pdrv,                /* Physical drive nmuber to identify the drive */
        BYTE *buff,                /* Data buffer to store read data */
        DWORD sector,        /* Start sector in LBA */
        UINT count                /* Number of sectors to read */
)
{
        UINT i = 0;
        BYTE *pOut;

        if (pdrv == 0)  
    {  
        pOut = buff;  

        if (!fpImg)  
            return RES_ERROR;  

        fseek(fpImg, SECTOR_SIZE*sector, SEEK_SET);  /*定位到文件所在的扇区,SEEK_SET表示开始位置*/

        for (i = 0; i<count; i++)     /*读取扇区数据*/
        {  
            fread(pOut, SECTOR_SIZE, 1, fpImg);  

            pOut = pOut + SECTOR_SIZE;  
        }  

        return RES_OK;  
    }
        return RES_ERROR;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

DRESULT disk_write (
        BYTE pdrv,                        /* Physical drive nmuber to identify the drive */
        const BYTE *buff,        /* Data to be written */
        DWORD sector,                /* Start sector in LBA */
        UINT count                        /* Number of sectors to write */
)
{
        UINT i = 0;
        const BYTE *pOut;
        DRESULT result;

        if (pdrv == 0)  
    {  
        pOut = buff;  

        if (!fpImg)  
                {
            return RES_ERROR;
                }

        fseek(fpImg, SECTOR_SIZE*sector, SEEK_SET);    /*定位到文件所在的扇区,SEEK_SET表示开始位置*/

        for (i = 0; i < count; i++)  
        {  
            fwrite(pOut, SECTOR_SIZE, 1, fpImg);  

            pOut = pOut + SECTOR_SIZE;  
        }  
        result = RES_OK;         
    }  
        return result;
}



/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
        BYTE pdrv,                /* Physical drive nmuber (0..) */
        BYTE cmd,                /* Control code */
        void *buff                /* Buffer to send/receive control data */
)
{
        switch (cmd)  
        {  
                default:  
                        break;  
        }  
        return RES_OK;
}


DRESULT get_fattime(void)
{
        return RES_OK;
}


    最后,附上源码。 pc_fatfs.zip (2.77 MB, 下载次数: 112) 2017-8-25 21:26 上传 点击文件名下载附件
    最后的最后,新手求罩!
   




友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。