• 方案介绍
  • 附件下载
  • 相关推荐
申请入驻 产业图谱

基于STM32完成FATFS文件系统移植与运用--这是完全免费开源的FAT文件系统

02/18 09:18
5470
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

更多详细资料请联系.docx

共1个文件

一、环境介绍

主控MCU: STM32F103ZET6

STM32程序开发IDE: keil5

STM32程序风格:? 采用寄存器方式开发,注释齐全,执行效率高,方便移植

硬件包含:??一块STM32F103ZET6系统板、一个SPI接口的SD卡卡槽模块、一张SD卡

工程完整源码下载地址:??https://download.csdn.net/download/xiaolong1126626497/19687693

这篇文章主要演示FATFS文件系统如何移植到自己的工程,并完成文件的读写。

因为SD卡采用的是SPI模拟时序,所以,其他单片机一样可以照着移植,代码都可以复制粘贴的。

二、FATFS文件系统介绍

2.1 FATFS简介

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

2.2 特点

  1. ?Windows兼容的FAT文件系统
  2. 不依赖于平台,易于移植
  3. 代码和工作区占用空间非常小
  4. ?多种配置选项
  5. 多卷(物理驱动器和分区)
  6. ?多ANSI/OEM代码页,包括DBCS
  7. 在ANSI/OEM或Unicode中长文件名的支持
  8. RTOS的支持
  9. 多扇区大小的支持
  10. 只读,最少API,I/O缓冲区等等

2.3 移植性

fatfs模块是ANSI C(C89)编写的。 没有平台的依赖, 编译器只要符合ANSI C标准就可以编译。

fatf模块假设大小的字符/短/长8/16/32位和int是16或32位。 这些数据类型在integer.h文件中定义。这些数据类型在大多数的编译器中定义都符合要求。 如果现有的定义与编译器有任何冲突发生时,需要自己解决。

2.4 源码下载

下载地址:http://elm-chan.org/fsw/ff/00index_e.html

FATFS有两个版本,一个大版本,一个小版本。小版本主要用于8位机(内存小)使用。

下载图:

2.5 FATFS源码文件介绍

将下载的源码解压后可以得到两个文件夹: doc 和 src。 doc 里面主要是对 FATFS 的介绍(离线文档—英文和日文),而 src 里面才是我们需要的源码。

其中,与平台无关的是:

ffconf.h???? FATFS配置文件

ff.h??????? 应用层头文件

ff.c??????? 应用层源文件

diskio.h??? 硬件层头文件

interger.h?? 数据类型定义头文件

option???? 可选的外部功能(比如支持中文等)

与平台相关的代码:

diskio.c???? 底层接口文件(需要用户提供)

FATFS 模块在移植的时候,我们一般只需要修改 2 个文件,即 ffconf.h 和 diskio.c。

FATFS模块的所有配置项都是存放在 ffconf.h 里面,我们可以通过配置里面的一些选项,来满足自己的需求。

FATFS最顶层是应用层,使用者无需理会 FATFS 的内部结构和复杂的 FAT 协议,只需要调用FATFS 模块提供给用户的一系列应用接口函数,如 f_open, f_read, f_write 和 f_close 等,就可以像在 PC 上读/写文件那样简单。

中间层 FATFS 模块, 实现了 FAT 文件读/写协议。 FATFS 模块提供的是 ff.c 和 ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。

需要我们编写移植代码的是 FATFS 模块提供的底层接口,它包括存储媒介读/写接口 ( disk、I/O) 和供给文件创建修改时间的实时时钟

三、 移植FATFS文件系统

移植之前,首先得准备一个能正常编译的工程,并且工程里有SD卡的驱动代码,提供了读写扇区这些函数才能进行FATFS文件系统的正常移植。

关于如何编写SD卡驱动,SD卡的时序介绍、命令介绍等知识点下篇文章再讲解。这篇文章重点是FATFS文件系统的移植过程。

3.1? 新建工程

FATFS文件系统源码下载下来,解压之后,移植修改的步骤如下:

打开KEIL工程,添加FATFS文件源码:

加入.h文件主要是方便配。cc936.c 用于支持中文。

3.2? 修改diskio.c文件

注释掉现在不需要的用到的文件,因为我们现在用的是SD卡,与USB,ATA,MMC卡没关系。

并加入一个新的宏 :

#define? SD? 0

定义SD卡的物理驱动器号为0。

修改 disk_status函数,该函数主要是用来获取磁盘状态。现在未用到,可以直接函数体内代码删除。

修改截图:

代码示例:

#include "diskio.h" ??????? ? /* fatf底层API */

#include "sd.h"??????? ??????? ????? /* SD卡驱动头文件? */

/* 定义每个驱动器的物理驱动器号*/

#define SD??? 0

/*-----------------------------------------------------------------------*/

/* 获取设备(磁盘)状态???????????????????????????????????????????????????? */

/*-----------------------------------------------------------------------*/

DSTATUS disk_status (

BYTE pdrv???? ??????? /* 物理驱动识别 */

)

{

return 0;? //该函数现在无需用到,直接返回0

}

修改disk_initialize函数,添加SD卡的初始化,其他不用到的代码直接删掉,该函数成功返回0,失败返回1。

修改截图:

代码示例:

/*-----------------------------------------------------------------------*/

/* 初始化磁盘驱动??????????????? ????????????????????????????????????????*/

/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (

BYTE pdrv???? ??????? ??????? ??????? /* 物理驱动识别 */

)

{

DSTATUS stat;

int result;

switch (pdrv) {

case SD :??????????? //选择SD卡

stat=SD_Init();?? //初始化SD卡-用户自己提供

}

if(stat)return STA_NOINIT;? //磁盘未初始化

return 0; //初始化成功

}

修改disk_read函数,加入SD卡读任意扇区的函数(需要用户自己提供),其他不用到的选项可以删掉。

修改代码如下:

/*-----------------------------------------------------------------------*/

/* 读扇区??????????????? ????????????????????????????????????????????????*/

/*-----------------------------------------------------------------------*/

DRESULT disk_read (

BYTE pdrv,??? ??????? /* 物理驱动编号 - 范围0-9*/

BYTE *buff,?? ??????? /* 数据缓冲区存储读取数据 */

DWORD sector,? /* 扇区地址*/

UINT count???? ??????? /* 需要读取的扇区数*/

)

{

DRESULT res;

int result;

switch (pdrv) {

case SD:

res=SD_Read_Data((u8*)buff,sector,count);? //读SD扇区函数--用户提供

return res; //在此处可以判错误

}

return RES_PARERR;? //无效参数

}

修改disk_write 函数,添加写扇区函数:

代码:

/*-----------------------------------------------------------------------*/

/* 写扇区??????????????????????????????????????????????????????????????? */

/*-----------------------------------------------------------------------*/

#if _USE_WRITE

DRESULT disk_write (

BYTE pdrv,??? ??????? ??????? ? /* 物理驱动号*/

const BYTE *buff, ?????? /* 要写入数据的首地址 */

DWORD sector,????? ??????? ?? /* 扇区地址 */

UINT count???? ??????? ??????? ? ?/* 扇区数量*/

)

{

DRESULT res;

int result;

switch (pdrv) {

case SD:

res=SD_Write_Data((u8*)buff,sector,count); //写入扇区

return res;

}

return RES_PARERR;? //无效参数

}

#endif

修改disk_ioctl 函数,填充ioctl命令功能。这些功能是标准的命令,在diskio.h有定义。

代码如下:

/*-----------------------------------------------------------------------*/

/* 其他函数??????????????????? ??????????????????????????*/

/*-----------------------------------------------------------------------*/

#if _USE_IOCTL

DRESULT disk_ioctl (

BYTE pdrv,??? ??????? /* 物理驱动号 */

BYTE cmd,???? ??????? ? /* 控制码? */

void *buff?????? ??????? /* 发送/接收数据缓冲区地址 */

)

{

DRESULT res;

int result;

switch (pdrv) {

case SD:

switch(cmd)

{

case CTRL_SYNC:???? ?//等待写过程

SD_CS(0);????????? //选中SD卡

if(SD_Wait_Ready())result = RES_ERROR;/*等待卡准备好*/

else res = RES_OK;???? //成功

SD_CS(1);??????????? //释放SD卡

break;

case GET_SECTOR_SIZE://获取扇区大小

*(DWORD*)buff = 512;

res = RES_OK;???? //成功

break;

case GET_BLOCK_SIZE:??? //获取块大小

*(WORD*)buff = 8;????? //块大小(扇区为单位),一块等于8个扇区

res = RES_OK;

break;

case GET_SECTOR_COUNT: //获取总扇区数量

*(DWORD*)buff = SD_Get_Sector_Count();

res = RES_OK;

break;

default:? //命令错误

res = RES_PARERR;

break;

}

return res;

}

return RES_PARERR;? //返回状态

}

diskio.c 文件修改完整代码:

/*-----------------------------------------------------------------------*/

/* 低级别磁盘I / O模块框架fatf(C)ChaN)2014

*存储控制模块fatf模块定义了一个API。????? */

/*-----------------------------------------------------------------------*/

#include "diskio.h" ??????? ? /* fatf底层API */

#include "sd.h"??????? ??????? ????? /* SD卡驱动头文件 ?*/

/* 定义每个驱动器的物理驱动器号*/

#define SD??? 0

/*-----------------------------------------------------------------------*/

/* 获取设备(磁盘)状态?????????????????????????????????????????????? ??????*/

/*-----------------------------------------------------------------------*/

DSTATUS disk_status (

BYTE pdrv???? ??????? /* 物理驱动识别 */

)

{

return 0;? //该函数现在无需用到,直接返回0

}

/*-----------------------------------------------------------------------*/

/* 初始化磁盘驱动??????? ????????????????????????????????????????????????*/

/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (

BYTE pdrv???? ??????? ??????? ??????? /* 物理驱动识别 */

)

{

DSTATUS stat;

int result;

switch (pdrv) {

case SD :?? ????????//选择SD卡

stat=SD_Init();?? //初始化SD卡-用户自己提供

}

if(stat)return STA_NOINIT;? //磁盘未初始化

return 0; //初始化成功

}

/*-----------------------------------------------------------------------*/

/* 读扇区????????????????????????????????????????????????????????? ??????*/

/*-----------------------------------------------------------------------*/

DRESULT disk_read (

BYTE pdrv,??? ??????? /* 物理驱动编号 - 范围0-9*/

BYTE *buff,?? ??????? /* 数据缓冲区存储读取数据 */

DWORD sector,????? /* 扇区地址*/

UINT count???? ??????? /* 需要读取的扇区数*/

)

{

DRESULT res;

int result;

switch (pdrv) {

case SD:

res=SD_Read_Data((u8*)buff,sector,count);? //读SD扇区函数--用户提供

return res; //在此处可以判错误

}

return RES_PARERR;? //无效参数

}

/*-----------------------------------------------------------------------*/

/* 写扇区????????????????????? ??????????????????????????????????????????*/

/*-----------------------------------------------------------------------*/

#if _USE_WRITE

DRESULT disk_write (

BYTE pdrv,??? ??????? ??????? ? /* 物理驱动号*/

const BYTE *buff, /* 要写入数据的首地址 */

DWORD sector,????? ??????? ? /* 扇区地址 */

UINT count???? ??????? ??????? ? /* 扇区数量*/

)

{

DRESULT res;

int result;

switch (pdrv) {

case SD:

res=SD_Write_Data((u8*)buff,sector,count); //写入扇区

return res;

}

return RES_PARERR;? //无效参数

}

#endif

/*-----------------------------------------------------------------------*/

/* 其他函数????????????????????????????????????????????? */

/*-----------------------------------------------------------------------*/

#if _USE_IOCTL

DRESULT disk_ioctl (

BYTE pdrv,??? ??????? /* 物理驱动号 */

BYTE cmd,???? ??????? ? /* 控制码? */

void *buff?????? ??????? /* 发送/接收数据缓冲区地址 */

)

{

DRESULT res;

int result;

switch (pdrv) {

case SD:

switch(cmd)

{

case CTRL_SYNC:????? //等待写过程

SD_CS(0);????????? //选中SD卡

if(SD_Wait_Ready())result = RES_ERROR;/*等待卡准备好*/

else res = RES_OK;???? //成功

SD_CS(1);????????? //释放SD卡

break;

case GET_SECTOR_SIZE://获取扇区大小

*(DWORD*)buff = 512;

res = RES_OK;???? //成功

break;

case GET_BLOCK_SIZE:? //获取块大小

*(WORD*)buff = 8;????? //块大小--一块等于8个扇区

res = RES_OK;

break;

case GET_SECTOR_COUNT: //获取总扇区数量

*(DWORD*)buff = SD_Get_Sector_Count();

res = RES_OK;

break;

default:? //命令错误

res = RES_PARERR;

break;

}

return res;

}

return RES_PARERR;? //返回状态

}

#endif

//返回FATFS时间

//获得时间

DWORD get_fattime (void)

{

return (DWORD)(2017-1980)<<25|??? //年

7<<21|??? //月

27<<16|??? //日

12<<11|??? //时

13<<5|??? //分

14;??? //秒

}

/*

Return Value

Currnet local time is returned with packed into a DWORD value. The bit field is as follows:

bit31:25

Year origin from the 1980 (0..127)

bit24:21

Month (1..12)

bit20:16

Day of the month(1..31)

bit15:11

Hour (0..23)

bit10:5

Minute (0..59)

bit4:0

Second / 2 (0..29)

*/

3.3?修改ffconf.h文件

需要注意的一些宏配置:

#define _CODE_PAGE? 936?? //采用中文GBK编码?????? (64行)

#define??? _USE_LFN???? 3???? //动态的堆上工作???????????? (93行)

#define??? _MAX_LFN?? 255?? /*_USE_LFN选项开关LFN(长文件名)特性。

#define _VOLUMES????? 1???? /* 支持的磁盘数量(逻辑驱动器)。 */?? (142行)

#define??? _MIN_SS??????? ??????? 512????????????????????????????????? (165行)

#define??? _MAX_SS????? ??????? 512?? /*这些选项配置支持扇区大小的范围。(512,1024, 4096*/

#define _FS_NORTC???? ??? 0??? /*启用RTC时间功能*/?? (202行)

#define _NORTC_MON ? ??1

#define _NORTC_MDAY???? 1

#define _NORTC_YEAR?????? 2015 //年

/*需要实现:get_fattime()函数*/

ffconf.h 文件源码(讲解):

/*---------------------------------------------------------------------------/

/? FatFs - FAT文件系统模块配置文件? R0.11a (C)ChaN, 2015

/---------------------------------------------------------------------------*/

#define _FFCONF 64180?????? /* 版本识别*/

/*---------------------------------------------------------------------------/

/ 功能配置

/---------------------------------------------------------------------------*/

#define _FS_READONLY???? 0

/* 这个选项开关只读配置。(0:读/写或1:只读)

/只读配置删除编写API函数,f_write(),f_sync(),

/ f_unlink(),f_mkdir(),f_chmod(),f_rename(),f_truncate(),f_getfree()

/写和可选的功能. */

#define _FS_MINIMIZE??????? 0

/*此选项定义删除一些基本的API函数极小化水平。

/

/ 0:所有基本功能都是激活的。

/ 1:f_stat(),f_getfree(),f_unlink(),f_mkdir(),f_chmod(),f_utime(),

/ f_truncate()和f_rename()函数删除。

/ 2:f_opendir(),f_readdir()和f_closedir()中除了1。

/ 3:f_lseek()函数删除除了2。*/

#define??? _USE_STRFUNC? 1

/*这个选项开关字符串函数,f_gets(),f_putc(),f_puts()和

/ f_printf()。

/

/ 0:禁用字符串函数。

/ 1:启用没有LF-CRLF转换。

/ 2:启用LF-CRLF(回车换行)转换。*/

#define _USE_FIND????? ??????? 0

/*这个选项开关过滤目录读取特性和相关功能,

/ f_findfirst()和f_findnext()。(0:禁用或1:启用)*/

#define??? _USE_MKFS ??????? 1

/* 这个选项开关f_mkfs()函数。(0:禁用或1:启用) */

#define??? _USE_FASTSEEK 1

/* 这个选项开关快速寻求功能。(0:禁用或1:启用) */

#define _USE_LABEL?? ??????? 1

/*   磁盘卷标这个选项开关功能,f_getlabel()和f_setlabel()。

/(0:禁用或1:启用) */

#define??? _USE_FORWARD 0

/*  这个选项开关f_forward()函数。(0:禁用或1:启用)

/启用它,也_FS_TINY需要设置为1. */

/*---------------------------------------------------------------------------/

/ 语言环境和名称空间配置

/---------------------------------------------------------------------------*/

#define _CODE_PAGE? 936? //采用中文GBK编码

/* 这个选项指定OEM代码页在目标系统上使用。

/不正确的代码页的设置会导致文件打开失败.

/

/?? 1?? - ASCII (没有扩展字符。Non-LFN cfg。只有)

/?? 437 - U.S.

/?? 720 - 阿拉伯语

/?? 737 - 希腊语;

/?? 771 - 阿富汗

/?? 775 - 波罗的海

/?? 850 - 拉丁1

/?? 852 - 拉丁2

/?? 855 - 西里尔字母

/?? 857 - 土耳其语

/?? 860 - 葡萄牙语

/ ??861 - 冰岛语

/?? 862 - 希伯来人

/?? 863 - 加拿大法语

/?? 864 - 阿拉伯语

/?? 865 - 日耳曼民族的

/?? 866 - 俄语

/?? 869 - 希腊 2

/?? 932 - 日本人 (DBCS)

/?? 936 - 简体中文(DBCS)

/?? 949 - 韩国人 (DBCS)

/?? 950 - 繁体中文(DBCS)

*/

#define??? _USE_LFN???? 3 //动态的堆上工作

#define??? _MAX_LFN?? 255

/*_USE_LFN选项开关LFN(长文件名)特性。

/

/ 0:禁用LFN特性。_MAX_LFN没有影响。

/ 1:启用LFN BSS静态工作缓冲区。总是不是线程安全的。

/ 2:启用LFN与动态缓冲栈上的工作。

/ 3:使LFN与动态缓冲区在堆上工作。

/

/? 当启用LFN(长文件名)特性,Unicode(选项/ unicode.c)必须处理功能

/被添加到项目中。LFN工作缓冲区占用(_MAX_LFN + 1)* 2字节。

/当使用堆栈缓冲区,照顾堆栈溢出。当使用堆

/工作缓冲区内存,内存管理功能,ff_memalloc()和

/ ff_memfree(),必须添加到项目中。 */

#define??? _LFN_UNICODE?? 0

/* 这个选项开关字符编码的API。(0:ANSI / OEM或1:Unicode)

路径名/使用Unicode字符串,并设置_LFN_UNICODE启用LFN特性

/1。这个选项也会影响行为的字符串的I / O功能。

*/

#define _STRF_ENCODE???? 3

/* 当_LFN(长文件名)_UNICODE是1,这个选项选择文件的字符编码

/通过字符串读取/写入I /O功能,f_gets(),f_putc(),f_puts和f_printf().

/

/? 0: ANSI/OEM

/? 1: UTF-16LE

/? 2: UTF-16BE

/? 3: UTF-8

/

/ 当_LFN_UNICODE = 0时,该选项没有影响。*/

#define _FS_RPATH???? 0

/* 这个选项配置相对路径的功能。  /

/ 0:禁用相对路径特性和删除相关功能。

/ 1:启用相对路径特性。f_chdir()和f_chdrive()是可用的。

/ 2:f_getcwd()函数可用除了1。  /

/注意,目录项读通过f_readdir()这个选项。

*/

/*---------------------------------------------------------------------------/

/ 驱动/卷配置

/---------------------------------------------------------------------------*/

#define _VOLUMES????? 1

/* 支持的磁盘数量(逻辑驱动器)。 */

#define _STR_VOLUME_ID 0

#define _VOLUME_STRS??????? "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"

/* STR_VOLUME_ID选项开关卷ID字符串功能。

/当_STR_VOLUME_ID设置为1时,也可以使用预先定义的字符串在路径名称/数量。

为每个_VOLUME_STRS定义驱动ID字符串

/逻辑驱动器。条目的数量必须等于_VOLUMES。有效字符

/驱动ID字符串:a - z和0 - 9。*/

#define??? _MULTI_PARTITION? 0

/*  这个选项开关多分区的特性。在默认情况下(0),每个逻辑驱动器

/号绑定到相同的物理驱动器号

/物理驱动器将被安装。当启用分区特性(1),

/每个逻辑驱动器号是绑定到任意物理驱动器和分区

/中列出VolToPart[]。还f_fdisk()函数可用. */

#define??? _MIN_SS??????? ??????? 512

#define??? _MAX_SS????? ??????? 512

/*  这些选项配置支持扇区大小的范围。(512,1024,

/ 2048或4096)总是为大多数系统设置两个512,卡和所有类型的内存

/硬盘。但是可能需要更大的值为车载闪存和一些

/类型的光学媒体。当_MAX_SS大于_MIN_SS,fatf配置

/变量扇区大小和GET_SECTOR_SIZE命令必须执行  disk_ioctl()函数. */

#define??? _USE_TRIM? 0

/* 这个选项开关ATA-TRIM特性。(0:禁用或1:启用)

/启用削减特性,也应该实现CTRL_TRIM命令

/ disk_ioctl()函数。*/

#define _FS_NOFSINFO?????? 0

/*

如果你需要知道正确的自由空间体积FAT32,设置一些0

/选项,f_getfree()函数在第一次后体积将迫使山

/全脂肪扫描。位1控制使用的集群数量分配。  /

/ bit0 = 0:使用免费的集群计算FSINFO如果可用。

/ bit0 = 1:不相信自由FSINFO集群计算。

/ bit1 = 0:最后使用集群可用FSINFO如果数量分配。

/ bit1 = 1:不相信最后分配FSINFO集群数量.

*/

/*---------------------------------------------------------------------------/

/ 系统配置列表

/---------------------------------------------------------------------------*/

#define??? _FS_TINY????? 0

/* 这个选项开关小缓冲区配置。(0:正常或1:小)

/小配置,文件对象的大小(FIL)_MAX_SS减少字节。而不是私人部门从文件对象,缓冲了

/公共部门缓冲文件系统中的对象(fatf)是用于该文件

/数据传输. */

#define _FS_NORTC???? 0

#define _NORTC_MON 1

#define _NORTC_MDAY???? 1

#define _NORTC_YEAR?????? 2015 //年

/* _FS_NORTC选项开关时间戳的特性。如果系统没有/

RTC函数或不需要有效的时间戳,_FS_NORTC 1设置为禁用/

时间戳的特性。所有对象修改fatf将有一个固定的时间戳。/

固定的时间定义为_NORTC_MON _NORTC_MDAY _NORTC_YEAR。

/当启用时间戳特性(_FS_NORTC = = 0),需要实现get_fattime()函数。  /

添加到项目RTC读当前时间形式。_NORTC_MON,   /

_NORTC_MDAY和_NORTC_YEAR没有效果。

/这些选项没有影响只读配置(_FS_READONLY = = 1)。 */

#define??? _FS_LOCK???? 0

/*  _FS_LOCK选项开关控制复制的文件打开的文件锁定功能

/和非法操作打开对象。这个选项_FS_READONLY时必须是0

/是1。  /

/ 0:禁用文件锁定功能。为了避免体积腐败、应用程序

/应该避免非法打开,删除和重命名的开放对象。

/ > 0:启用文件锁定功能。值定义了多少文件/子目录

可以同时打开的/文件锁的控制之下。注意,这个文件独立于re-entrancy /锁功能。 */

#define _FS_REENTRANT?? 0

#define _FS_TIMEOUT ??????? 1000

#define??? _SYNC_t ??????? ??????? HANDLE

/*  _FS_REENTRANT选项开关re-entrancy fatf的(线程安全)

/模块本身。注意,不管这个选项,文件访问不同

/体积始终是凹角和音量控制功能,f_mount(),f_mkfs()

/和f_fdisk()函数,总是不凹角。只有文件/目录的访问

/相同的体积是这个功能的控制。

/

/ 0:禁用re-entrancy。_FS_TIMEOUT和_SYNC_t没有效果。

/ 1:启用re-entrancy。还提供用户同步处理程序,

/ ff_req_grant(),ff_rel_grant(),ff_del_syncobj()和ff_cre_syncobj()

/函数,必须添加到项目中。样品中可用

/选项

/ syscall.c。

/

/? _FS_TIMEOUT定义超时时间单位的滴答声。

/ _SYNC_t定义了O

/ S依赖同步对象类型。例如处理、ID、OS_EVENT *

/ SemaphoreHandle_t等. .O / S的头文件定义需要

/包括在ff.c的范围。 */

#define _WORD_ACCESS??? 0

/* _WORD_ACCESS选项是一个只有依赖于平台的选择。

它定义了这个词/访问方法是用来体积上的数据。

/

/ 0:逐字节的访问。总是兼容所有平台。

/ 1:词的访问。不要选择这个,除非在下列条件。

/

/ *地址对齐内存访问总是允许所有指令。

/ *字节顺序的记忆是低位优先。

/

/如果是这样的情况,_WORD_ACCESS也可以减少代码的大小设置为1。

/下表显示允许设置某种类型的处理器

/

/? ARM7TDMI?? 0?? *2????????? ColdFire ??0??? *1???????? V850E????? 0??? *2

/? Cortex-M3? 0?? *3????????? Z80??????? 0/1???????????? V850ES???? 0/1

/? Cortex-M0? 0?? *2????????? x86??????? 0/1???????????? TLCS-870?? 0/1

/? AVR??????? 0/1???????? ????RX600(LE)? 0/1???????????? TLCS-900?? 0/1

/? AVR32????? 0?? *1????????? RL78?????? 0??? *2???????? R32C?????? 0??? *2

/? PIC18????? 0/1???????????? SH-2?????? 0??? *1??????? ?M16C?????? 0/1

/? PIC24????? 0?? *2????????? H8S??????? 0??? *1???????? MSP430???? 0??? *2

/? PIC32????? 0?? *1????????? H8/300H??? 0??? *1???????? 8051?????? 0/1

/

/

* 1:高位优先。  /

* 2:不支持不连续的内存访问。  /

* 3:一些编译器生成LDM(逻辑磁盘管理器 ) / STM mem_cpy(内存拷贝)函数。

*/

3.4?实现动态内存分配函数与时间函数

ff.h文件有动态内存的释放,动态内存申请,时间获取函数接口。

在diskio.c文件实现函数功能:

代码实现如下:

//动态内存分配

void* ff_memalloc (UINT msize)? ??????? ??????? ??? /* 分配内存块 */

{

return (void*)malloc(msize); //分配空间

}

//动态内存释放

void ff_memfree (void* mblock)?? ??????? ??????? ??? /* 空闲内存块 */

{

free(mblock);????????????? //释放空间

}

//返回FATFS时间

//获得时间

DWORD get_fattime (void)

{

//Get_RTC_Timer(); //获取一次RTC时间

return (RTC_Timer.year-1980)<<25|?? //年

RTC_Timer.month<<21|? //月

RTC_Timer.day<<16|??? //日

RTC_Timer.hour<<11|?? //时

RTC_Timer.minute<<5|? //分

RTC_Timer.sec;??????? //秒

}

/*

Return Value

Currnet local time is returned with packed into a DWORD value. The bit field is as follows:

bit31:25

Year origin from the 1980 (0..127)

bit24:21

Month (1..12)

bit20:16

Day of the month(1..31)

bit15:11

Hour (0..23)

bit10:5

Minute (0..59)

bit4:0

Second / 2 (0..29)

*/

3.5 修改堆栈空间

完成了上述的修改,还需要修改堆栈空间,因为长文件支持需要占用堆空间。

修改STM32启动文件如下:

3.6?编译工程测试

修改完毕之后,给开发板插上SD卡,调用API函数在SD卡创建一个文件,并写入数据,测试是否成功:

#include "ff.h"

FATFS fs;? // 用户定义的文件系统结构体

FIL? file;? // 用户定义的文件系统结构体

u8 buff[]="123 知识!!";

int main(void)

{

u32 data;??????????????? //检测SD卡容量

u8 i,res;

LED_Init();????????????? //LED灯初始化

Delay_Init();

KEY_Init();

USART1_Init(72,115200);

USART2_Init(36,115200);

FLASH_Init();

Set_Font_addr(); //字库地址初始化

FSMC_SRAM_Init();

LCD_Init();

RTC_Init();???? //RTC时钟初始化

while(SD_Init()) ???//检测不到SD卡,SD相关硬件初始化

{

i=!i;

LCD_ShowString(60,150,200,16,16,"SD Card Error!? Please Check SD Card!!",0xf800);

Delay_ms(500);

LED1(i)//DS0闪烁

}

f_mount(&fs,"0",1);? // 注册工作区,驱动器号 0,初始化后其他函数可使用里面的参数

printf("注册工作区!n");

if(f_mkfs("0",0,4096))? //格式化SD卡

{

printf("格式化失败!!n");

}

else

{

printf("格式化成功!!n");

}

res = f_open(&file, "/file.c", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);

if(res==0)

{

printf("文件创建成功!!n");

}

else

{

printf("文件创建失败!!n");

}

res =f_write(&file,buff,strlen((const char*)buff),&data);

if(res==0)

{

printf("数据写入成功!!n");

}

else

{

printf("数据写入失败!!n");

}

printf("成功写入%d字节数据n",data);

f_close(&file);? //关闭文件

//_FS_RPATH

while(1)

{

Delay_ms(1000);

LED1(1);

Delay_ms(500);

LED1(0);

}

}

  • 更多详细资料请联系.docx
    下载
意法半导体

意法半导体

意法半导体(ST)集团于1987年6月成立,是由意大利的SGS微电子公司和法国Thomson半导体公司合并而成。1998年5月,SGS-THOMSON Microelectronics将公司名称改为意法半导体有限公司。意法半导体是世界最大的半导体公司之一,公司销售收入在半导体工业五大高速增长市场之间分布均衡(五大市场占2007年销售收入的百分比):通信(35%),消费(17%),计算机(16%),汽车(16%),工业(16%)。 据最新的工业统计数据,意法半导体是全球第五大半导体厂商,在很多市场居世界领先水平。例如,意法半导体是世界第一大专用模拟芯片和电源转换芯片制造商,世界第一大工业半导体和机顶盒芯片供应商,而且在分立器件、手机相机模块和车用集成电路领域居世界前列.

意法半导体(ST)集团于1987年6月成立,是由意大利的SGS微电子公司和法国Thomson半导体公司合并而成。1998年5月,SGS-THOMSON Microelectronics将公司名称改为意法半导体有限公司。意法半导体是世界最大的半导体公司之一,公司销售收入在半导体工业五大高速增长市场之间分布均衡(五大市场占2007年销售收入的百分比):通信(35%),消费(17%),计算机(16%),汽车(16%),工业(16%)。 据最新的工业统计数据,意法半导体是全球第五大半导体厂商,在很多市场居世界领先水平。例如,意法半导体是世界第一大专用模拟芯片和电源转换芯片制造商,世界第一大工业半导体和机顶盒芯片供应商,而且在分立器件、手机相机模块和车用集成电路领域居世界前列.收起

查看更多

相关推荐