SD卡挂载FatFs文件系统

一、简介

实验目的:SD卡挂载FATFS文件系统,并生成.txt文件

MCU:ST32F103ZET6

SD卡:16G;SPI读写模式;

引脚定义:VCC:5V
                  GND:GND
                  MISO:PA6
                  MOSI:PA7
                  SCK:PA5
                  CS:PA4

实物图:

 二、工程源码

前面的文章有SD卡和SPI的源码,所以就展示需要改动的diskio.c和ffconf.h文件以及main.c文件:

diskio.c

/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/
 
#include "ff.h"			/* Obtains integer types */
#include "diskio.h"		/* Declarations of disk functions */
#include "SD.h"	
#include "usart.h"	
#include "SPI.h"	
#include "delay.h"	
 

#define SD_CARD      0 							//SD卡设备,0就是SD卡的设备编号

 
/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/
 
 
//查询当前驱动器状态
DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
		return RES_OK;

}
 
 
 
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/
//磁盘初始化
DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
		uint8_t res=0;
	
		res=SD_Init();																			//SD卡初始化
//		if(res)																						//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常(当然,如果你的SPI和SD卡配置没有问题,这个可有可无)
//		{
//				SPI1_SetSpeed(SPI_BaudRatePrescaler_256);			
//				SPI1_ReadWriteByte(0xff);											//提供额外的8个时钟
//				SPI1_SetSpeed(SPI_BaudRatePrescaler_2);
//		}
		
		if(res)return  STA_NOINIT;
		else return RES_OK; 																//初始化成功
		
}
 
 
 
/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/
//从存储设备的扇区读取设备
DRESULT disk_read (
	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
	BYTE *buff,		/* Data buffer to store read data */
	LBA_t sector,	/* Start sector in LBA */
	UINT count		/* Number of sectors to read */
)
{
	uint8_t res;
//	int result;
	if (!count)
	{
		return RES_PARERR;																//count不能等于0,否则返回参数错误
	}
	switch (pdrv) {
		
	case SD_CARD :
			 res=SD_ReadDisk(buff,sector,count);	 					//读SD卡
			 if(res == 0)
			 {
					return RES_OK;
			 }else{
					return RES_ERROR;
			 }
	default:
					return RES_ERROR;
	}
	 
}
 
 
 
/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/
//向存储设备的扇区写入数据
#if FF_FS_READONLY == 0
 
DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
	const BYTE *buff,	/* Data to be written */
	LBA_t sector,		/* Start sector in LBA */
	UINT count			/* Number of sectors to write */
)
{
	uint8_t res;

	if (!count)
	{
		return RES_PARERR;																			//count不能等于0,否则返回参数错误	
	}
	switch (pdrv) {
		
	case SD_CARD :
			 res=SD_WriteDisk((uint8_t*)buff,sector,count);				//写SD卡
			 if(res == 0)
			 {
					return RES_OK;
		   }else{
					return RES_ERROR;
			 } 
	}	
	if(res == 0x00)return RES_OK;	 
  else return RES_ERROR;	
}
 
#endif
 
 
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/
//控制设备特定功能和通用的读/写以外的其他功能
DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
	DRESULT res;

	if(pdrv==SD_CARD)																												//SD卡
	{
			switch (cmd) 
			{
				case SD_CARD :
						SD_CS(1);																										 // 选择 SD 卡		
						do{
							delay_ms(20);
						}while(SPI1_ReadWriteByte(0xFF)!=0xFF);											//等待SD卡准备好
						res=RES_OK;
						SD_CS(0);																										//取消选择
		        break;	 
		    case GET_SECTOR_SIZE:
						*(DWORD*)buff = 512; 																				//设置扇区大小512
		        res = RES_OK;
		        break;	 
		    case GET_BLOCK_SIZE:
						*(WORD*)buff = 8;																						//设置扇区大小8
		        res = RES_OK;
		        break;	 
		    case GET_SECTOR_COUNT:
		        *(DWORD*)buff = SD_GetSectorCount();												// 获取扇区总数(在主函数)	
		        res = RES_OK;
		        break;
		    default:
		        res = RES_PARERR;
		        break;
 
			}
 
	}
 
	return res;
}

//获得时间
//User defined function to give a current time to fatfs module      */
//31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */                                                                                                                                                                                                                                          
//15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */                                                                                                                                                                                                                                                
DWORD get_fattime (void)
{				 
	return 0;
}	
//这个函数是用来获取时间的,没有实现其功能,但是如果没有的话,就会报get_fattime函数缺失的错误,需要的话可以实现其功能。



ffconf.h

/*---------------------------------------------------------------------------/
/  Configurations of FatFs Module
/---------------------------------------------------------------------------*/

#define FFCONF_DEF	80286	/* Revision ID */									//版本号

/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/

#define FF_FS_READONLY	0	
/* 
这行代码定义了一个宏FF_FS_READONLY,其值为0,用于配置FatFs文件系统模块的读写模式。具体解释如下:

FF_FS_READONLY:
值为0:启用读写模式。系统将支持读取和写入操作。
值为1:启用只读模式。在只读模式下,系统将禁用写入相关的API函数,如f_write()、f_sync()、f_unlink()、f_mkdir()、f_chmod()、f_rename()、f_truncate()和f_getfree()。这意味着用户只能进行读取操作,无法修改或删除文件和目录。. */



#define FF_FS_MINIMIZE	0
/*
这行代码定义了一个宏FF_FS_MINIMIZE,其值为0,用于设置FatFs文件系统模块的功能最小化级别。具体解释如下:

FF_FS_MINIMIZE:
值为0:启用所有基本功能。所有API函数均可用。
值为1: 移除一些函数,如f_stat()、f_getfree()、f_unlink()、f_mkdir()、f_truncate()和f_rename()。
值为2: 在级别1的基础上,进一步移除f_opendir()、f_readdir()和f_closedir()函数。
值为3: 在级别2的基础上,移除f_lseek()函数。
选择不同的最小化级别可以减少代码体积或节省资源,具体取决于应用的需求*/




#define FF_USE_FIND		0
/* 
这段代码定义了一个宏 FF_USE_FIND,用于控制 FatFs 文件系统模块中目录读取函数的启用情况。具体来说,宏 FF_USE_FIND 的作用如下:

FF_USE_FIND:
值为 0:禁用过滤目录读取函数 f_findfirst() 和 f_findnext()。这意味着不会启用这些函数,目录读取将不支持基于过滤条件的查找。
值为 1:启用 f_findfirst() 和 f_findnext() 函数,允许使用这些函数进行目录中的文件查找。这提供了基本的文件筛选功能,可以根据文件名模式进行查找。
值为 2:在启用基本过滤功能的基础上,还支持 altname[] 的匹配。即,f_findfirst() 和 f_findnext() 函数不仅可以根据文件名模式进行查找,还可以根据备用名称进行匹配,提供更灵活的文件查找选项。
根据需求设置 FF_USE_FIND 的值,可以调整 FatFs 的文件查找功能的复杂程度。 */



#define FF_USE_MKFS		1	
/* 
FF_USE_MKFS 控制是否启用 f_mkfs() 函数:

0 表示禁用 f_mkfs(),即不允许格式化文件系统。
1 表示启用 f_mkfs(),允许通过该函数创建和格式化文件系统。 */



#define FF_USE_FASTSEEK	1
/* 
FF_USE_FASTSEEK 选项控制 FatFs 库中的快速寻址功能是否启用。具体来说:

#define FF_USE_FASTSEEK 0:禁用快速寻址功能。在这种设置下,文件的寻址(跳转到文件的特定位置)将不会使用额外的数据结构来加速。这可能会导致文件内位置跳转的速度较慢,但能节省内存。

#define FF_USE_FASTSEEK 1:启用快速寻址功能。开启后,FatFs 会使用额外的数据结构来加速文件的寻址操作,从而提高性能,但需要额外的内存开销。

选择启用或禁用此功能取决于你对性能的需求以及系统的内存限制。 */



#define FF_USE_EXPAND	0
/* 
这段代码定义了 FF_USE_EXPAND,用于控制是否启用 f_expand 函数:

FF_USE_EXPAND = 0:禁用 f_expand 函数。
FF_USE_EXPAND = 1:启用 f_expand 函数。 */



#define FF_USE_CHMOD	
/* 
这段代码定义了 FF_USE_CHMOD,用于控制是否启用文件属性操作函数:

FF_USE_CHMOD = 0:禁用 f_chmod() 和 f_utime() 函数,这些函数用于修改文件属性和修改时间。
FF_USE_CHMOD = 1:启用 f_chmod() 和 f_utime() 函数。
启用 FF_USE_CHMOD 时,FF_FS_READONLY 也需要设置为 0,即文件系统必须不是只读的。*/



#define FF_USE_LABEL	0
/* 
这段代码定义了 FF_USE_LABEL,用于控制是否启用卷标操作函数:

FF_USE_LABEL = 0:禁用卷标函数 f_getlabel() 和 f_setlabel()。
FF_USE_LABEL = 1:启用卷标函数 f_getlabel() 和 f_setlabel()。
这些函数用于获取和设置卷标。 */



#define FF_USE_FORWARD	0
/* 
这段代码定义了 FF_USE_FORWARD,用于控制是否启用 f_forward() 函数:

FF_USE_FORWARD = 0:禁用 f_forward() 函数。
FF_USE_FORWARD = 1:启用 f_forward() 函数。
f_forward() 是用于在文件中定位的功能,通常用于在文件中前进到指定位置。 */



#define FF_USE_STRFUNC	0
#define FF_PRINT_LLI		1
#define FF_PRINT_FLOAT	1
#define FF_STRF_ENCODE	3
/* 
这段代码配置了字符串函数的选项:

FF_USE_STRFUNC:控制是否启用字符串函数(如 f_gets(), f_putc(), f_puts(), f_printf()):
0:禁用所有字符串函数。
1:启用字符串函数,不进行 LF-CRLF 转换。
2:启用字符串函数,并进行 LF-CRLF 转换。
FF_PRINT_LLI:是否支持 long long 类型作为 f_printf() 的参数。

1:启用对 long long 的支持。
FF_PRINT_FLOAT:是否支持浮点数作为 f_printf() 的参数。

1:支持浮点数。
2:支持更精确的浮点数。
FF_STRF_ENCODE:指定文件中字符编码的假设。

0:ANSI/OEM 编码。
1:UTF-16LE 编码。
2:UTF-16BE 编码。
3:UTF-8 编码。
*/



/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/

#define FF_CODE_PAGE	936									//如果需要支持简体中文,需要把ffconf.h中的_CODE_PAGE的宏改成936
/* This option specifies the OEM code page to be used on the target system.
/  Incorrect code page setting can cause a file open failure.
/
/   437 - U.S.
/   720 - Arabic
/   737 - Greek
/   771 - KBL
/   775 - Baltic
/   850 - Latin 1
/   852 - Latin 2
/   855 - Cyrillic
/   857 - Turkish
/   860 - Portuguese
/   861 - Icelandic
/   862 - Hebrew
/   863 - Canadian French
/   864 - Arabic
/   865 - Nordic
/   866 - Russian
/   869 - Greek 2
/   932 - Japanese (DBCS)
/   936 - Simplified Chinese (DBCS)
/   949 - Korean (DBCS)
/   950 - Traditional Chinese (DBCS)
/     0 - Include all code pages above and configured by f_setcp()
*/


#define FF_USE_LFN		0
#define FF_MAX_LFN		255
/*
这段代码配置了长文件名(LFN,Long File Name)的支持选项:

FF_USE_LFN:控制是否启用长文件名(LFN)支持。

0:禁用长文件名(LFN)。此时,FF_MAX_LFN 没有作用。
1:启用长文件名(LFN),使用静态工作缓冲区(存储在 BSS 区域)。此配置下的 LFNs 不支持多线程。
2:启用长文件名(LFN),使用动态工作缓冲区(存储在栈上)。请注意栈溢出问题。
3:启用长文件名(LFN),使用动态工作缓冲区(存储在堆上)。需要添加内存管理函数(ff_memalloc() 和 ff_memfree())到项目中。
FF_MAX_LFN:定义了工作缓冲区的大小,单位为 UTF-16 代码单元。范围从 12 到 255,推荐设置为 255 以完全支持长文件名规范。这个值决定了用于存储长文件名的缓冲区大小。

注意:
启用长文件名支持需要将 ffunicode.c 添加到项目中。
启用 LFN 时,工作缓冲区的大小为 (FF_MAX_LFN + 1) * 2 字节,并且当启用 exFAT 时,还需要额外的 (FF_MAX_LFN + 44) / 15 * 32 字节。
使用栈或堆作为工作缓冲区时,需要考虑相关的资源管理和内存分配策略。 */



#define FF_LFN_UNICODE	2
/* 
FF_LFN_UNICODE 配置了在启用长文件名(LFN)时的字符编码方式:

0:使用 ANSI/OEM 编码,当前代码页(TCHAR 为 char)。
1:使用 UTF-16 编码(TCHAR 为 WCHAR)。
2:使用 UTF-8 编码(TCHAR 为 char)。
3:使用 UTF-32 编码(TCHAR 为 DWORD)。
这会影响 API 和字符串 I/O 函数的行为,具体取决于所选择的编码方式*/



#define FF_LFN_BUF		255
#define FF_SFN_BUF		12
/* 
这些宏定义了 FILINFO 结构中用于存储文件名的缓冲区大小。这些设置在读取目录项时用来存储文件名:

FF_LFN_BUF:定义了用于存储长文件名(LFN)的缓冲区大小。这个大小需要足够大,以确保可以读取和存储文件系统中可能出现的最长文件名。在启用长文件名(LFN)时,设置为 255 表示能够支持较长的文件名。
FF_SFN_BUF:定义了用于存储短文件名(SFN)的缓冲区大小。短文件名通常遵循 8.3 格式,即最大长度为 8 个字符的文件名加上一个 3 字符的扩展名。设置为 12 提供了足够的空间来存储这些短文件名。
注意事项:

当长文件名(LFN)未启用时,这些选项将不会生效。
文件名的最大长度取决于字符编码方式,具体取决于 FF_LFN_UNICODE 的设置。
根据 FF_LFN_UNICODE 的设置,文件名的实际长度可能会有所不同。例如,如果使用 UTF-8 编码,可能需要处理变长字符。. */



#define FF_FS_RPATH		0
/* 
FF_FS_RPATH 配置了对相对路径的支持:

0:禁用相对路径,并移除相关函数。
1:启用相对路径,提供 f_chdir() 和 f_chdrive() 函数。
2:在 1 的基础上,还提供 f_getcwd() 函数,用于获取当前工作目录。
选择合适的设置可以根据需求决定是否需要对路径进行相对处理。*/



/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/

#define FF_VOLUMES		1							
/* 
FF_VOLUMES 用于指定系统支持的逻辑驱动器数量:

当前设置为 1,意味着系统只支持 1 个逻辑驱动器。
可以将其设置为 1 到 10 之间的值,以支持更多的逻辑驱动器。
这影响文件系统如何挂载和管理驱动器。增加此值可以允许更多的驱动器在系统中使用。 */



#define FF_STR_VOLUME_ID	0
#define FF_VOLUME_STRS		"RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* 
在你的代码中,_STR_VOLUME_ID 选项用于定义如何表示卷标(volume ID)。

_STR_VOLUME_ID = 0: 使用数字 ID(例如,"0"、"1"、"2")来标识卷。
_STR_VOLUME_ID = 1: 使用字符串 ID,字符串由 _VOLUME_STRS 定义。例如,你可以用 "RAM"、"NAND"、"CF" 等作为卷标。
确保 _VOLUME_STRS 中的字符串数量与系统中逻辑卷的数量一致。*/



#define FF_MULTI_PARTITION	0
/* 
FF_MULTI_PARTITION 配置了对物理驱动器上多个分区的支持:

0:禁用对多个分区的支持。在这种情况下,每个逻辑驱动器号绑定到相同的物理驱动器号,并且仅在该物理驱动器上找到的 FAT 卷会被挂载。
1:启用对多个分区的支持。这样,每个逻辑驱动器号可以绑定到任意物理驱动器和分区,这些驱动器和分区在 VolToPart[] 中列出。此外,还将提供 f_fdisk() 函数,用于分区管理。
启用多分区支持可以让文件系统管理更多的分区和驱动器,提高灵活性,但也增加了配置和管理的复杂性。 */



#define FF_MIN_SS		512
#define FF_MAX_SS		4096								
/*
FF_MIN_SS 和 FF_MAX_SS 的定义如下:

FF_MIN_SS: 设定最小扇区大小。这个值通常设置为 512 字节,以支持大多数系统、通用的存储卡和硬盘。

FF_MAX_SS: 设定最大扇区大小。此值可以设置为 512、1024、2048 或 4096 字节。你当前将其设置为 4096 字节,适用于需要较大扇区的设备,如某些板载闪存或光盘。

说明
当 FF_MAX_SS 大于 FF_MIN_SS 时,FatFs 文件系统被配置为支持可变扇区大小模式。在这种情况下,disk_ioctl() 函数需要实现 GET_SECTOR_SIZE 命令,以允许系统处理不同的扇区大小。

设置适当的扇区大小可以优化文件系统的性能和兼容性,尤其是在处理不同类型的存储介质时。 */



#define FF_LBA64		0
/* 
FF_LBA64 用于控制是否支持 64 位逻辑块地址(LBA):

0 表示禁用 64 位 LBA。
1 表示启用 64 位 LBA,但需要同时启用 exFAT 文件系统(FF_FS_EXFAT == 1)。
启用 64 位 LBA 允许支持更大的存储容量,但必须确保文件系统也支持该功能。 */



#define FF_MIN_GPT		0x10000000
/* 
FF_MIN_GPT 定义了在 f_mkfs 和 f_fdisk 函数中切换到 GPT 分区格式的最小扇区数:

设置为 0x10000000(即 268,435,456 扇区),表示当分区大小达到此值时,系统可以切换到 GPT(GUID 分区表)格式。
如果 FF_LBA64 为 0,则此选项无效,因为 GPT 需要 64 位 LBA 支持才能工作。 */



#define FF_USE_TRIM		0
/*
FF_USE_TRIM 控制是否支持 ATA-TRIM:

0 表示禁用 ATA-TRIM 功能。
1 表示启用 ATA-TRIM 功能,但需要在 disk_ioctl() 函数中实现 CTRL_TRIM 命令。
启用 ATA-TRIM 可以帮助提高固态硬盘的性能和寿命。*/



/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/

#define FF_FS_TINY		0
/* 
这段代码定义了 FF_FS_TINY,用于选择缓冲区配置:

FF_FS_TINY = 0:使用正常缓冲区配置。
FF_FS_TINY = 1:使用紧凑缓冲区配置,文件对象(FIL)的大小会减少 FF_MAX_SS 字节,文件数据传输使用文件系统对象(FATFS)中的公共扇区缓冲区。 */



#define FF_FS_EXFAT		0
/* 
这段代码定义了 FF_FS_EXFAT,用于控制是否支持exFAT文件系统:

FF_FS_EXFAT = 0:禁用exFAT支持。
FF_FS_EXFAT = 1:启用exFAT支持。
要启用exFAT,必须同时启用长文件名(LFN),即 FF_USE_LFN 必须设置为 1 或更高。同时,启用exFAT会导致不兼容ANSI C(C89) */



#define FF_FS_NORTC		0
#define FF_NORTC_MON	1
#define FF_NORTC_MDAY	1
#define FF_NORTC_YEAR	2022
/* 
这段代码解释了 FF_FS_NORTC 宏选项在 FatFs 文件系统模块中的作用,主要涉及时间戳功能的启用与禁用:
FF_FS_NORTC:

值为 1:禁用时间戳功能。如果系统没有实时时钟(RTC)或不需要有效的时间戳,可以将此选项设置为 1。在这种情况下,所有由 FatFs 修改的对象将具有固定的时间戳,该时间戳由 FF_NORTC_MON、FF_NORTC_MDAY 和 FF_NORTC_YEAR 定义,均为本地时间。
值为 0:启用时间戳功能。在这种模式下,需要实现 get_fattime() 函数来从实时时钟读取当前时间。FF_NORTC_MON、FF_NORTC_MDAY 和 FF_NORTC_YEAR 将不再起作用,因为实际时间戳将从 RTC 中读取。
注意:

这些选项对只读配置 (FF_FS_READONLY = 1) 没有影响。在只读模式下,文件系统不会进行任何修改操作,因此不需要时间戳功能。
总结来说,FF_FS_NORTC 控制 FatFs 是否使用实时时钟来为文件系统对象生成时间戳。如果系统没有 RTC,或者时间戳不重要,可以通过将 FF_FS_NORTC 设置为 1 来简化配置。如果需要动态时间戳功能,则需要设置为 0 并实现时间读取功能。 */



#define FF_FS_NOFSINFO	0
/*
这段代码定义了 FF_FS_NOFSINFO,控制FAT32文件系统如何处理FSINFO中的信息。bit0 和 bit1 是设置选项:

bit0=0:使用FSINFO中的自由簇计数。
bit0=1:不信任FSINFO中的自由簇计数,强制进行完整FAT扫描。
bit1=0:使用FSINFO中的最后分配簇编号。
bit1=1:不信任FSINFO中的最后分配簇编号。*/


#define FF_FS_LOCK		0
/* 
这段代码定义了一个宏 FF_FS_LOCK,用于配置 FatFs 文件系统模块中的文件锁定功能。具体功能如下:

FF_FS_LOCK:
值为 0:禁用文件锁定功能。在这种模式下,FatFs 不会管理文件的锁定状态,因此应用程序必须自行避免非法的文件打开、删除或重命名操作,以防止数据损坏或其他问题。适用于只读模式(即 FF_FS_READONLY 为 1)的情况下。
值大于 0:启用文件锁定功能。此值定义了在文件锁定控制下可以同时打开的文件/子目录的最大数量。启用文件锁定可以防止重复打开文件或进行非法操作(如同时打开同一文件的多个实例),从而避免潜在的冲突和数据损坏。
启用文件锁定功能时,FF_FS_LOCK 的值表示系统允许的最大并发文件操作数,而文件锁定功能与线程安全性(FF_FS_REENTRANT)是独立配置的。这意味着即使在启用线程安全功能时,文件锁定仍然可以提供额外的保护。 */



#define FF_FS_REENTRANT	0
#define FF_FS_TIMEOUT	1000
/* 
这段代码定义了两个宏,用于配置 FatFs 文件系统模块的线程安全性和超时时间:

FF_FS_REENTRANT:

值为 0:禁用线程安全功能。这意味着 FatFs 模块在多线程环境下可能会出现竞争条件,文件访问不受线程安全控制。
值为 1:启用线程安全功能。在这种模式下,用户必须提供同步处理程序(如 ff_mutex_create()、ff_mutex_delete()、ff_mutex_take() 和 ff_mutex_give())。这些处理程序用于在多线程环境下管理对 FatFs 的访问,防止数据竞争。
FF_FS_TIMEOUT:

定义了超时时间,单位为操作系统的时间刻度(tick)。当启用线程安全功能时,FatFs 可能会等待某些同步操作完成,FF_FS_TIMEOUT 指定了等待的最长时间。
启用线程安全时,需实现适当的同步处理程序,以确保 FatFs 在多线程环境中的可靠性。*/



/*--- End of configuration options ---*/

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"	
#include "ff.h"	
#include "diskio.h"
#include "SD.h"
#include "SPI.h"

FATFS fs;


void WritetoSD(BYTE write_buff[],uint8_t bufSize);
char SD_FileName[] = "屌爆了.txt";
uint8_t WriteBuffer[] = "01 write buff to sd \r\n";


uint8_t write_cnt =0;	//写SD卡次数

BYTE work[FF_MAX_SS];

///

/
		


	int main(void)
	{	
		

		
	
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
		uart_init(115200);
		delay_init();	    	
		
//
		WritetoSD(WriteBuffer,sizeof(WriteBuffer));		

			
			
			delay_ms(500);
			WriteBuffer[0] = WriteBuffer[0] +10;
			WriteBuffer[1] = WriteBuffer[1] +10;
			write_cnt ++;
			
			while(write_cnt > 10)
			{	
				printf(" while \r\n");
				delay_ms(500);
			}				

}







void WritetoSD(BYTE write_buff[],uint8_t bufSize)
{
	
	FIL file;
	uint8_t res=0;
	UINT Bw;	
	
	res = SD_Init();		//SD卡初始化
	printf("res = %d\r\n",res);
	
	if(res == 1)
	{
		printf("SD卡初始化失败! \r\n");		
	}
	else
	{
		printf("SD卡初始化成功! \r\n");		
	}
	
	res=f_mount(&fs,"0:",1);		//挂载
	
//	if(test_sd == 0)		//用于测试格式化
	if(res == FR_NO_FILESYSTEM)		//没有文件系统,格式化
	{
//		test_sd =1;				//用于测试格式化
		printf("没有文件系统! \r\n");		
		res = f_mkfs("", 0, work, sizeof(work));		//格式化sd卡
		if(res == FR_OK)
		{
			printf("格式化成功! \r\n");		
			res = f_mount(NULL,"0:",1); 		//格式化后先取消挂载
			res = f_mount(&fs,"0:",1);			//重新挂载	
			if(res == FR_OK)
			{
				printf("SD卡已经成功挂载,可以进进行文件写入测试!\r\n");
			}	
		}
		else
		{
			printf("格式化失败! \r\n");		
		}
	}
	else if(res == FR_OK)
	{
		printf("挂载成功! \r\n");		
	}
	else
	{
		printf("挂载失败! \r\n");
	}	
	
	res = f_open(&file,SD_FileName,FA_OPEN_ALWAYS |FA_WRITE);
	if((res & FR_DENIED) == FR_DENIED)
	{
		printf("卡存储已满,写入失败!\r\n");		
	}
	
	f_lseek(&file, f_size(&file));//确保写词写入不会覆盖之前的数据
	if(res == FR_OK)
	{
		printf("打开成功/创建文件成功! \r\n");		
		res = f_write(&file,write_buff,bufSize,&Bw);		//写数据到SD卡
		if(res == FR_OK)
		{
			printf("文件写入成功! \r\n");			
		}
		else
		{
			printf("文件写入失败! \r\n");
		}		
	}
	else
	{
		printf("打开文件失败!\r\n");
	}	
	
	f_close(&file);						//关闭文件		
	f_mount(NULL,"0:",1);		 //取消挂载
	
}


void Get_SDCard_Capacity(void)
{
	FRESULT result;
	FATFS FS;
	FATFS *fs;
	DWORD fre_clust,AvailableSize,UsedSize;  
	uint16_t TotalSpace;
	uint8_t res;
	
	res = SD_Init();		//SD卡初始化
	if(res == 1)
	{
		printf("SD卡初始化失败! \r\n");		
	}
	else
	{
		printf("SD卡初始化成功! \r\n");		
	}
	
	/* 挂载 */
	res=f_mount(&FS,"0:",1);		//挂载
	if (res != FR_OK)
	{
		printf("FileSystem Mounted Failed (%d)\r\n", result);
	}

	res = f_getfree("0:", &fre_clust, &fs);  /* 根目录 */
	if ( res == FR_OK ) 
	{
		TotalSpace=(uint16_t)(((fs->n_fatent - 2) * fs->csize ) / 2 /1024);
		AvailableSize=(uint16_t)((fre_clust * fs->csize) / 2 /1024);
		UsedSize=TotalSpace-AvailableSize;              
		/* Print free space in unit of MB (assuming 512 bytes/sector) */
		printf("\r\n%d MB total drive space.\r\n""%d MB available.\r\n""%d MB  used.\r\n",TotalSpace, AvailableSize,UsedSize);
	}
	else 
	{
		printf("Get SDCard Capacity Failed (%d)\r\n", result);
	}		
} 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值