FATFS实验_STM32F1开发指南_第四十四章

                                                           第四十四章 FATFS实验
    上一章学习了SD卡的使用,不过仅仅是简单的读扇区而已。真正要好好使用SD卡,必须使用文件系统管理。
本章将使用FATFS来管理SD卡,实现SD卡文件的读写等基本功能。
    本章分为如下几部分:
44.1 FATFS简介
44.2 硬件设计
44.3 软件设计
44.4 下载验证

44.1 FATFS简介

    FATFS是一个完全免费开源的FAT文件系统模块,专为小型的嵌入式系统而设计。
    它完全用标准的 C语言编写,具有良好的硬件平台独立性,可以移植到8051、PIC、
AVR、SH、Z80、H8、 ARM等系列 单片机上而只需做简单的修改。
    它支持FTA12 FAT16 和FAT32,支持多个存储媒介;
    有独立的缓冲区,可以对多个文件进行读/写,并特别对8位和16位单片机做了优化。

FATFS的特点有:

    ① Windows兼容的FAT文件系统(支持FAT12/FAT16/FAT32);
    ② 与平台无关,移植简单;
    ③ 代码量少,效率高;
    ④ 多种配置选项
        支持多卷(物理驱动器或分区,最多10个卷);
        多个ANSI/OEM代码页,包括DBCS;
        支持长文件名,ANSI/OEM或Unicode;
        支持RTOS;
        支持多种扇区大小;
        只读、最小化的API和I/O缓冲区等。
    FATFS的这些特点,加上免费、开源的原则,使得FATFS应用非常广泛。

FATFS模块的层次结构:

FATFS实验_STM32F1开发指南_第四十四章_第1张图片
     最顶层是应用层 使用者无需理会FATFS的内部结构和复杂的FAT协议,只需要调用
FATFS模块提供给用户的一系列应用接口即可,如f_open,f_read, f_write和f_close等,
就可以像在PC上读/写文件那样简单。
     中间层FATFS模块 实现了FAT文件读写协议。
FATFS模块提供的是ff.c和ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接
包含进去即可。
      底层存储媒介接口,包括存储媒介读/写接口(disk I/O)和供文件创建修改时间的实时时钟。
这些接口需要我们编写移植。

FATFS源码:

   下载地址:  http://elm-chan.org/fsw/ff/00index_e.html  
    文件解压后内容:doc和src。 doc里面是对FATFS的介绍;src里面是需要的源码。
序号 分类 文件名 功能
1 与平台无关 ffconf.h FATFS配置文件
2 ff.h FATFS和应用模块公用的包含文件
3 ff.c FATFS模块
4 diskio.h FATFS和disk I/O模块公用的包含文件
5 interger.h 数据类型定义
6 option     可选的外部功能(比如支持中文等)
7 与平台有关(需要用户提供) diskio.c FATFS和disk I/O模块接口层文件
    FATFS模块在移植时,一般只需要修改2个文件,即ffconf.h和diskio.c。
     FATFS模块的所有配置项都是存放在ffconf.h里面,我们可以通过配置里面的一些选项,来满足
自己的需求。下面是几个重要的配置选项。
序号 配置名 内容
1 _FS_TINY 这个选项在R0.07版本中开始出现,以前是以独立的C文件出现(FATFS和Tiny FATFS),有了这个选项后,两者合在一起了,使用起来更方便。我们使用FATFS,所以设置为0即可。
2 _FS_READONLY 配置是否只读。
本章需要读写都用,所以设置为0即可。
3 _USE_STRFUNC 配置是否支持字符串操作,比如f_putc,f_puts等。
本章用到,所以设置为1。
4 _USE_MKFS     定时是否使能格式化。
本章用到,所以设置为1。
5 _USE_FASTSEEK    使能快速定位。
本章需要快速定位,设置为1。
6 _USE_LABEL 设置是否支持磁盘盘符(磁盘名字)读取与设置。
本章用到,可以读取或设置磁盘的名字。使能,设置为1。
7 _CODE_PAGE     设置语言类型,包括很多选项(见FATFS官网说明),我们设置为936,即简体中文(GBK码,需要c936.c文件支持,该文件在option文件夹)
8 _USE_LFN 设置是否支持长文件名(还需要_CODE_PAGE支持),取值范围为0~3。
0:不支持;
1~3:支持,但存储的地方不一样,我们使用3,通过ff_memalloc函数来动态分配长文件名的存储区。
9 _VOLUMES     设置FATFS支持的逻辑设备数目。
我们设置为2,即支持2个设备。
10 _MAX_SS     扇区缓冲的最大值,一般为512。
    其他配置项,参见FATFS说明文档。

FATFS移植:

    FATFS移植主要分为3步:
① 数据类型:在integer.h里面去定义好数据的类型。这里需要了解你的编译器类型,并根据编译器定义好数据类型;
② 配置:通过ffconf.h配置FATFS的相关功能,以满足你的需求;
③ 函数编写:打开diskio.c,进行底层驱动编写,一般需要编写6个函数接口,如所示:
diskio.c disk_initialize()
disk_status()
disk_read()
disk_write()
disk_ioctl()
get_fattime()
通过 以下三步即可完成对FATFS的移植。
    第一步:使用的是MDK5.13编译器,其数据类型和integer.h里面定义的一致,所以此步
不需要做任何改动。
    第二步:根据上面讲过的需求,配置ffconf.h里面的配置,其他的用默认配置即可。
    第三步:因为FATFS模块完全和磁盘I/O层分开,因此需要下面的函数来实现底层物理磁盘
的读写与获取当前时间。
    底层磁盘I/O模块并不是FATFS的一部分,必须由用户提供。就是上面提到的6个函数。
函数1名称 disk_initialize
函数原型 DSTATUS disk_initialize(BYTE Drive)
功能描述 初始化磁盘驱动器
函数参数 Drive:指定要初始化的逻辑驱动器号,即盘符,应当取值0~9.
返回值 磁盘操作状态。(磁盘状态的细节信息,参考disk_status函数)
所在文件 ff.c
示例 disk_initialize(0);//初始化驱动器0
注意事项 函数初始化一个逻辑磁盘驱动器为读/写做准备,成功时,返回值的STA_NOINIT标志被清零;
应用程序不应该调用此函数,否则卷上的FAT结构可能被破坏;
如果需要重新初始化文件系统,可以使用f_mount函数;
在FatFs模块的上卷注册处理时,调用该函数可控制设备的改变;
此函数在FatFs挂在卷时调用,应用程序不应该在FatFs活动时使用此函数。
函数2名称 disk_status
函数原型 DISTATUS disk_status(BYTE Drive)
功能描述 返回当前的磁盘驱动器的状态
函数参数 Drive:指定要确认的逻辑驱动器号,即盘符,应当取值0~9
返回值 磁盘状态返回下列标志的组合,FatFs只使用STA_NOINIT和STA_PROTECTED。
STA_NOINIT:表明磁盘驱动未初始化,下面列出了该标志置位或清零的原因:
置位:系统复位,磁盘被移除和磁盘初始化函数失败;
清零:磁盘初始化函数成功。
STA_NODISK:表明磁盘驱动器没有设备,安装磁盘驱动器后总为0。
STA_PROTECTED:表明设备被写保护,不支持写保护的设备总为0,当STA_NODISK置位时非法。
所在文件 ff.c
示例 disk_status(0);//获取驱动器0的状态
注意事项  
函数3名称 disk_read
函数原型 DRESULT disk_read(BYTE    Drive, BYTE *   Buffer, DWORD SectorNumber, BYTE      SectorCount)
功能描述 从磁盘驱动器上读取扇区
函数参数 Drive:指定逻辑驱动器号,即盘符,应当取值0~9;
Buffer:指向储存读取数据字节数组的指针(需要为所读取字节数的大小,扇区统计的扇区大小的需要的);
注:FatFs指定的内存地址不总是字对齐的,如果硬件不支持不对其的数据传输,则函数里需要进行处理;
SectorNumber:指定起始扇区的逻辑块(LBA)上的地址;
SectorCount:指定要读取的扇区数,取值1~128。
返回值 RES_OK(0):函数成功
RES_ERROR:读操作期间产生了任何错误且不能恢复它
RES_PARERR:非法参数
RES_NOTRDY:磁盘驱动器没有初始化
所在文件 ff.c
函数4名称 disk_write
函数原型 DRESULT disk_write(BYTE Drive,  const BYTE * Buffer, DWORD  SectorNumber, BYTE  SectorCount)
功能描述 向磁盘写入一个或多个扇区
函数参数 Drive:指定逻辑驱动器号,即盘符,应当取值0~9;
Buffer:指向要写入字节数组的指针;
注:FatFs指定的内存地址并不总是字节对齐的,如果硬件不支持不对齐的数据传输,则函数里面需要进行处理。
SectorNumber:指定起始扇区的逻辑块(LBA)上的地址
SectorNumber:指定要写入的扇区数,取值1~128
返回值 RES_OK(0):函数成功
RES_ERROR:读操作期间产生了任何错误且不能恢复它
RES_WRPRT:媒体被写保护
RES_PARERR:非法参数
RES_NOTRDY:磁盘驱动器没有初始化
所在文件 ff.c
注意事项 只读配置中不需要此函数
函数5名称 disk_ioctl
函数原型 DRESULT disk_ioctl (BYTE Drive, BYTE Command, void *  Buffer)
功能描述 控制设备指定特性除了读写外的杂项功能
函数参数 Drive        :指定逻辑驱动器号,即盘符,取值0~9;
Command:指定命令代码;
Buffer       :指向参数缓冲区的指针,取决于命令代码,不使用时,指定一个NULL指针
返回值 RES_OK(0)     :函数成功
RES_ERROR  :读操作期间产生了任何错误且不能恢复它
RES_PARERR:非法参数
RES_NOTRDY:磁盘驱动器没有初始化
所在文件 ff.c
注意事项 CTRL_SYNC                   :确保磁盘驱动器已经完成了写处理,当磁盘I/O有一个写回缓存,
立即刷新原扇区,只读配置下不适用此命令。
GET_SECTOR_SIZE      :返回磁盘扇区大小,只用于f_mkfs();
GET_SECTOR_COUNT  :返回可利用的扇区数,_MAX_SS >= 1024时可用;
GET_BLOCK_SIZE         :获取擦除块大小,只用于f_mkfs();
CTRL_ERASE_SECTOR:强制擦除一块的扇区,_USE_REASE > 0时可用。
函数6名称 get fattime
函数原型 DWORD get_fattime()
功能描述 获取当前时间
函数参数
返回值 当前时间以双字值封装返回。
位域如下:
bit31:25  年(0~127)(从1980开始)
bit24:21  月(1~12)
bit20:16  日(1~31)
bit15:11  小时(0~23)
bit10:5    分钟(0~59)
bit4:0      秒(0~29)
所在文件 ff.c
注意事项 get_fattime函数必须返回一个合法的时间即使系统不支持实时时钟,如果返回0,
文件没有一个合法的时间:只读配置下无需此函数。
    通过以上步骤,就完成了对FATFS的移植,就可以在我们的代码里面使用FATFS了。
    注意:使用FATFS的时候,必须先通过f_mount函数注册一个工作区,才能开始后续的API的使用,
大家可以通过FATFS自带的介绍文件进一步了解和熟悉FATFS的使用。

44.2 硬件设计

  本章实验功能:
    开机时先初始化SD卡;
    之后注册两个工作区(一个给SD卡使用,一个给SPI FLASH用);
    然后获取SD卡的容量和剩余空间,并显示在LCD上;
    最后,等待USMART输入指令进行各项测试。
    本实验通过DS0指示程序运行状态。
本实验用到的硬件资源:
    1)指示灯DS0;
    2)串口;
    3)TFTLCD模块;
    4)SD卡;
    5)SPI FLASH。

44.3 软件设计

介绍的文件:

    diskio.c
    ffconf.h
    main.c

diskio.c内容:

    实现了前面提到的6个函数,同时因为在ffconf.h里面设置对长文件名的支持为方法3,所以必须实现 ff_memalloc和ff_memfree这两个函数。
    本章,我们用FATFS管理了两个磁盘:SD卡和SPI FLASH。SD卡比较好说,但是SPI FLASH,因为其扇区是4K字节大小,为了方便设计,强制将其扇区定义为512字节,这样好处是设计使用相对简单,坏处是擦除次数大增,所以不要随便向SPI FLASH里面写数据,非必要最好别写,如果频繁写的话,很容易将SPI FLASH写坏。
    另外,diskio.c里面的函数,直接决定了磁盘编号(盘符/卷标)所对应的具体设备,比如,上面代码中,设置SD_CARD为0,EX_FLASH位为1,对应到disk_read/disk_write函数里面, 通过switch来判断,到底要操作SD卡,还是SPI FLASH,然后,分别执行对应设备的相关操作,以此实现磁盘编号磁盘关联。
    打开diskio.c,代码如下:
#define SD_CARD           0            //SD卡,卷标为0
#define EX_FLASH          1            //外部Flash,卷标为1
#define FLASH_SECTOR_SIZE 512
 
//对于W25Q128
//前12M字节给FatFs使用,12M字节后,用于存放字库,字库占3.09M,剩余的给客户自己使用
u16 FLASH_SECTOR_COUNT = 2048*12;    //W25Q128前12M字节
#define FLASH_BLOCK_SIZE    8        //每个BLOCK有8个扇区
//获得磁盘状态
DSTATUS disk_status(BYTE pdrv)    //Physical drive number to identify the drive
{
    return RES_OK;
}    
//初始化磁盘
DSTATUS disk_initialize(BYTE pdrv)    //Physical drive number to identify the drive
{
    u8 res = 0;
    switch(pdrv)
    {
        case SD_CARD:           //SD卡
            res = SD_Init();    //SD卡初始化
            break;
        case EX_FLASH:          //外部Flash
            W25QXX_Init();
            FLASH_SECTOR_COUNT = 2048*12;    //前12M字节给FATFS占用
            break;
 
        default:
            res = 1;
    }
 
    if(res)
        return STA_NOINIT;
    else
        return 0;    //初始化成功
}
 
//读扇区
//pdrv   :磁盘编号0~9
//*buffer:数据接收缓冲首地址
//sector :扇区地址
//count  :需要读取的扇区数
DRESULT disk_read(BYTE pdrv,    //physical drive number to identify the drive
                  BYTE *buff,   //Data buffer to store read data
                  DWORD sector, //Sector address in LBA
                  UINT count)   //Number of sectors to read
{
    u8 res = 0;
    if(!count)
        return RES_PARERR;    //count不能等于0,否则返回参数错误
    switch(pdrv)
    {
        case SD_CARD:           //SD卡
            res = SD_ReadDisk(buff, sector, count);
            while(res)    //读出错
            {
                SD_Init();    //重新初始化SD卡
                res = SD_ReadDisk(buff, sector, count);
                //printf("sd rd error:%d\r\n", res);
            }
            break;
        case EX_FLASH:          //外部Flash
            for(; count > 0; count--)
            {
                W25QXX_Read(buff, sector*FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE)
                sector++;
                buff += FLASH_SECTOR_SIZE;
            }
            res = 0;
            break;
 
        default:
            res = 1;
    }
    //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值
    if(res == 0x00)
        return RES_OK;
    else
        return RES_ERROR;
}
 
//写扇区
//pdrv   :磁盘编号0~9
//*buffer:发送数据首地址
//sector :扇区地址
//count  :需要写入的扇区数
#if _USE_WRITE
DRESULT disk_write(BYTE pdrv,          //physical drive number to identify the drive
                  const BYTE *buff,   //Data buffer to store read data
                  DWORD sector,       //Sector address in LBA
                  UINT count)         //Number of sectors to write
{
    u8 res = 0;
    if(!count)
        return RES_PARERR;    //count不能等于0,否则返回参数错误
    switch(pdrv)
    {
        case SD_CARD:    //SD卡
            res = SD_WriteDisk((u8*)buff, sector, count);
            while(res)    //写出错
            {
                SD_Init();    //重新初始化SD卡
                res = SD_WriteDisk((u8*)buff, sector, count);
                //printf("sd wr error:%d\r\n", res);
            }
        break;
        case EX_FLASH:    //外部Flash
            for(; count > 0; count--)
            {
                W25QXX_Write((u8*)buff, sector*FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE);
                sector++;
                buff += FLASH_SECTOR_SIZE;
            }
            res = 0;
        break;
 
        default:
            res = 1;
    }
    //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值
    if(res == 0x00)
        return RES_OK;
    else
        return RES_ERROR;   
}
#endif
 
//其他表参数的获取
//pdrv:磁盘编号0~9
//ctrl:控制代码
//*buff:发送/接收缓冲区指针
#if _USE_IOCTL
DRESULT disk_ioctl(BYTE pdrv,   //Physical drive number(0...)
                   BYTE cmd,    //Control code
                   void * buff) //Buffer to send/receive control data
{
    DRESULT res;
    if(pdrv == SD_CARD)    //SD卡
    {
        switch(cmd)
        {
            case CTRL_SYNC:
                res = RES_OK;
                break;
            case GET_SECTOR_SIZE:
                *(DWORD*)buff = 512;
                res = RES_OK;
                break;
            case GET_BLOCK_SIZE:
                *(WORD*)buff = SDCardInfo.CardBlockSize;
                res = RES_OK;
                break;
            case GET_SECTOR_COUNT:
                *(DWORD*)buff = SDCardInfo.CardCapacity/512;
                res = RES_OK;
                break;
            default:
                res = RES_PARERR;
                break;
        }
    }
    else if(pdrv == EX_FLASH)    //外部FLASH
    {
        switch(cmd)
        {
            case CTRL_SYNC:
                res = RES_OK;
                break;
            case GET_SECTOR_SIZE:
                *(WORD*)buff = FLASH_SECTOR_SIZE;
                res = RES_OK;
                break;
            case GET_BLOCK_SIZE:
                *(WORD*)buff = FLASH_BLOCK_SIZE;
                res = RES_OK;
                break;
            case GET_SECTOR_COUNT:
                *(DWORD*)buff = FLASH_SECTOR_COUNT;
                res = RES_OK;
                break;
            default:
                res = RES_PARERR;
                break;
        }
    }
    else
        res = RES_ERROR;    //其他不支持
    return res;
}
#endif
//获取时间
//User defined function to give a current time to fatfs module
//当前时间以双字值封装返回。
//位域如下:
//bit31:25  年(0~127)(从1980开始)
//bit24:21  月(1~12)
//bit20:16  日(1~31)
//bit15:11  小时(0~23)
//bit10:5   分钟(0~59)
//bit4:0    秒(0~29)
DWORD get_fattime(void)
{
    return 0;
}
 
//动态分配内存
void *ff_memcalloc(UINT size)
{
    return (void*)mymalloc(SRAMIN, size);
}
 
//释放内存
void ff_memfree(void * mf)
{
    myfree(SRAMIN, mf);
}

    ffconf.h内容:

        头文件可以看到我们还修改了fatfs相关配置,参考例程源码。
    cc936.c主要提供 UNICODE到  GBK以及 GBKUNICODE的码表转换,里面就是两个大数组,
并提供一个ff_conver的转换函数,供UNICODE和GBK码互换,这个在中文长文件名支持的时
候必须用到。
    FATFS文件夹下还有一个文件夹exfuns,里面保存一些FATFS针对FATFS的扩展代码,本章
编写了4个文件,分别是:exfuns.c、exfuns.h、fattester.c和fattester.h。
exfuns.c:主要定义了一些全局变量,方便FATFS使用,同时实现了磁盘容量获取等函数;
fattester.c:主要是为了测试FATFS用,因为FATFS的很多函数无法直接通过USMART调用,所
fattester.c里面对这些函数进行了一次再封装,使得可以通过USMART调用。

    main.c内容:

    在main函数里面,我们为SD卡和FLASH都注册了工作区(挂在),在初始化SD卡并显示器容
量信息后 进入死循环,等待USMART测试。
int main()
{
    u32 total, free;
    u8 t = 0; u8 res = 0;
    delay_init();            //延时函数初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    uart_init(115200);   
    usmart_dev.init(72);    //初始化USMART
    LED_init();
    KEY_init();
    LCD_init();
    W25QXX_init();          //初始化W25Q128
    my_mem_init(SRAMIN);    //初始化内部内存池
    POINT_COLOR = RED;
    LCD_ShowString(30,50,200,16,16,"WarShip STM32");
    LCD_ShowString(30,70,200,16,16,"FATFS TEST");
    LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
    LCD_ShowString(30,110,200,16,16,"2015/1/20"); 
    LCD_ShowString(30,130,200,16,16,"Use USMART for test");
    while(SD_Init())//检测不到 SD 卡
    {
        LCD_ShowString(30,150,200,16,16,"SD Card Error!"); delay_ms(500);
        LCD_ShowString(30,150,200,16,16,"Please Check! "); delay_ms(500);
        LED0=!LED0;//DS0 闪烁
    }
    exfuns_init();                  //为fatfs相关变量申请内存
    f_mount(fs[0], "0:", 1);        //挂载SD卡
    res = f_mount(fs[1], "1:", 1);  //挂载FLASH
    if(res == 0x0D)                 //FLASH磁盘,FAT文件系统错误,重新格式化FLASH
    {
        LCD_ShowString(30,150,200,16,16,"Flash Disk Formatting...");//格式化 FLASH
        res = f_mkfs("1:", 1, 4096);   //格式化FLASH, 1, 盘符;1,不需要引导区,8个扇区为1镞
        if(res == 0)
        {
            f_setlabel((const TCHAR*)"1:ALIENTEK"); //设置Flash磁盘名:ALIENTEK
            LCD_ShowString(30,150,200,16,16,"Flash Disk Format Finish");//格式化完成
        }
        else
            LCD_ShowString(30,150,200,16,16,"Flash Disk Format Error ");//格式化失败
        delay_ms(1000); 
    }
    LCD_Fill(30,150,240,150+16,WHITE);        //清除显示 
    while(exf_getfree("0", &total, &free))    //得到SD卡的总容量和剩余容量
    {
        
        LCD_ShowString(30,150,200,16,16,"SD Card Fatfs Error!");
        delay_ms(200);
        LCD_Fill(30,150,240,150+16,WHITE);//清除显示
        delay_ms(200);
        LED0=!LED0;//DS0 闪烁
    }
    POINT_COLOR=BLUE;//设置字体为蓝色
    LCD_ShowString(30,150,200,16,16,"FATFS OK!");
    LCD_ShowString(30,170,200,16,16,"SD Total Size: MB");
    LCD_ShowString(30,190,200,16,16,"SD Free Size: MB");
    LCD_ShowNum(30+8*14,170,total>>10,5,16); //显示 SD 卡总容量 MB
    LCD_ShowNum(30+8*14,190,free>>10,5,16); //显示 SD 卡剩余容量 MB
    while(1)
    {
        t++;
        delay_ms(200);
        LED0=!LED0;
    }
}
    最后,在usmart_conf.c里面的usmart_nametab数组添加如下内容:
这些函数均是在fattester.c里面实现的,通过调用这些函数,即可实现对FATFS对应API函数的测试。
(void*)mf_mount,     "u8   mf_mount      (u8* path,u8 mt)",
(void*)mf_open,      "u8   mf_open       (u8*path,u8 mode)",
(void*)mf_close,     "u8   mf_close      (void)",
(void*)mf_read,      "u8   mf_read       (u16 len)",
(void*)mf_write,     "u8   mf_write      (u8*dat,u16 len)",
(void*)mf_opendir,   "u8   mf_opendir    (u8* path)",
(void*)mf_closedir,  "u8   mf_closedir   (void)",
(void*)mf_readdir,   "u8   mf_readdir    (void)",
(void*)mf_scan_files,"u8   mf_scan_files (u8 * path)",
(void*)mf_showfree,  "u32  mf_showfree   (u8 *drv)",
(void*)mf_lseek,     "u8   mf_lseek      (u32 offset)",
(void*)mf_tell,      "u32  mf_tell       (void)",
(void*)mf_size,      "u32  mf_size       (void)",
(void*)mf_mkdir,     "u8   mf_mkdir      (u8*pname)",
(void*)mf_fmkfs,     "u8   mf_fmkfs      (u8* path,u8 mode,u16 au)",
(void*)mf_unlink,    "u8   mf_unlink     (u8 *pname)",
(void*)mf_rename,    "u8   mf_rename     (u8 *oldname,u8* newname)",
(void*)mf_getlabel,  "void mf_getlabel   (u8 *path)",
(void*)mf_setlabel,  "void mf_setlabel   (u8 *path)",
(void*)mf_gets,      "void mf_gets       (u16 size)",
(void*)mf_putc,      "u8   mf_putc       (u8 c)",
(void*)mf_puts,      "u8   mf_puts       (u8*c)",

44.4 下载验证

    在代码编译成功之后,我们通过下载代码到ALIENTEK战舰STM32F103上,可以看到
LCD显示下图所示内容(SD卡已经插上了):
FATFS实验_STM32F1开发指南_第四十四章_第2张图片
    打开串口调试助手,可以用串口调用前面添加的各种FATFS测试函数了。比如输入
mf_scan_files("0:"),即可扫描SD卡根目录下面的额所有文件,如下图所示:
  FATFS实验_STM32F1开发指南_第四十四章_第3张图片
     注意:这里0代表SD卡,1代表SPI的FLASH。
                mf_ulink函数,在删除文件夹时,必须保证文件夹是空的,才可以正常删除,否则不能删除。















你可能感兴趣的:(应用-,stm32)