当前位置: 首页 > news >正文

STM32F4移植FATFS管理SD卡

说在开头

        本文是接上一篇文章后的学习笔记,上一篇推文主要介绍了SDIO的知识、如何使用SDIO驱动SD卡、SD卡数据读写。本文则主要介绍如何移植FATFS以及相关API的使用。其中我觉得最值得一看的就是如何遍历读取SD卡的文件名称及内容。

上一篇文章的链接在这:STM32F4单片机SDIO驱动SD卡-CSDN博客

1、下载源码

        下载地址为:http://elm-chan.org/fsw/ff/archives.html,这里使用的是FATFS-R0.14版本,但我也下载了​​​​​​​FATFS-R0.14a和FATFS-R0.14b源码,对比后内容大差不差。下载后解压,真正的源码是“source”文件夹里的7个c/h文件,文件的作用如下:

2、复制源码

        在工程根目录新建“Middlewares/Third_Party/FATFS-R0.14”文件夹,并将FATFS的7个源码文件复制到新建的文件夹中。

3、导入源码

        打开工程,添加FATFS源码文件进工程,同时添加编译路径。

4、配置FATFS

        修改ffcon.h文件,自定义相关配置,这里张贴出我使用的配置以及相关的注释

/*---------------------------------------------------------------------------/
/  FatFs Functional Configurations
/---------------------------------------------------------------------------*/

#define FFCONF_DEF	86606	/* Revision ID */

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

#define FF_FS_READONLY	0
/*
	是否以只读的方式运行FATFS,如果读写都要用就将值设为0
*/
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/  Read-only configuration removes writing API functions, f_write(), f_sync(),
/  f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/  and optional writing functions as well. */


#define FF_FS_MINIMIZE	0
/* This option defines minimization level to remove some basic API functions.
/
/   0: Basic functions are fully enabled.
/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/      are removed.
/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/   3: f_lseek() function is removed in addition to 2. */


#define FF_USE_STRFUNC	2
//#define FF_PRINT_LLI	0
//#define FF_PRINT_FLOAT	0
/*
	这个用来设置是否支持字符串类操作,比如f_putc,f_puts等
  0: Disable string functions.不启用字符串操作
  1: Enable without LF-CRLF conversion.启用无低频-CRLF转换
  2: Enable with LF-CRLF conversion. 启用带低频-CRLF转换
*/


#define FF_USE_FIND		0
/* This option switches filtered directory read functions, f_findfirst() and
/  f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */


#define FF_USE_MKFS		1
/* 用来定义是否使能格式化 */


#define FF_USE_FASTSEEK	1
/* 用来使能快速搜索功能(0:Disable or 1:Enable) */


#define FF_USE_EXPAND	0
/* This option switches f_expand function. (0:Disable or 1:Enable) */


#define FF_USE_CHMOD	0
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
/  (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */


#define FF_USE_LABEL	1
/* 用来设置是否支持磁盘盘符(磁盘名字)读取与设置。 f_getlabel() and f_setlabel(). */


#define FF_USE_FORWARD	0
/* This option switches f_forward() function. (0:Disable or 1:Enable) */


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

#define FF_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		2
#define FF_MAX_LFN		255
/* 用于设置是否支持长文件名,0:表示不支持长文件名,1~3 是支持长文件名,但是存储地方不一样.
The FF_USE_LFN switches the support for LFN (long file name).
/
/   0: Disable LFN. FF_MAX_LFN has no effect.
/   1: Enable LFN with static  working buffer on the BSS. Always NOT thread-safe.
/   2: Enable LFN with dynamic working buffer on the STACK.
/   3: Enable LFN with dynamic working buffer on the HEAP.
/
/  To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
/  requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
/  additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
/  The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
/  be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN
/  specification.
/  When use stack for the working buffer, take care on stack overflow. When use heap
/  memory for the working buffer, memory management functions, ff_memalloc() and
/  ff_memfree() exemplified in ffsystem.c, need to be added to the project. */


#define FF_LFN_UNICODE	0
/* This option switches the character encoding on the API when LFN is enabled.
/
/   0: ANSI/OEM in current CP (TCHAR = char)
/   1: Unicode in UTF-16 (TCHAR = WCHAR)
/   2: Unicode in UTF-8 (TCHAR = char)
/   3: Unicode in UTF-32 (TCHAR = DWORD)
/
/  Also behavior of string I/O functions will be affected by this option.
/  When LFN is not enabled, this option has no effect. */


#define FF_LFN_BUF		255
#define FF_SFN_BUF		12
/* This set of options defines size of file name members in the FILINFO structure
/  which is used to read out directory items. These values should be suffcient for
/  the file names to read. The maximum possible length of the read file name depends
/  on character encoding. When LFN is not enabled, these options have no effect. */


#define FF_STRF_ENCODE	3
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
/  f_putc(), f_puts and f_printf() convert the character encoding in it.
/  This option selects assumption of character encoding ON THE FILE to be
/  read/written via those functions.
/
/   0: ANSI/OEM in current CP
/   1: Unicode in UTF-16LE
/   2: Unicode in UTF-16BE
/   3: Unicode in UTF-8
*/


#define FF_FS_RPATH		0
/* This option configures support for relative path.
/
/   0: Disable relative path and remove related functions.
/   1: Enable relative path. f_chdir() and f_chdrive() are available.
/   2: f_getcwd() function is available in addition to 1.
*/


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

#define FF_VOLUMES		1
/* 用于设置 FATFS 支持的磁盘设备数目 (1-10) */


#define FF_STR_VOLUME_ID	0
#define FF_VOLUME_STRS		"RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
/  When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
/  number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
/  logical drives. Number of items must not be less than FF_VOLUMES. Valid
/  characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/  compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/  not defined, a user defined volume string table needs to be defined as:
/
/  const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/


#define FF_MULTI_PARTITION	0
/* This option switches support for multiple volumes on the physical drive.
/  By default (0), each logical drive number is bound to the same physical drive
/  number and only an FAT volume found on the physical drive will be mounted.
/  When this function is enabled (1), each logical drive number can be bound to
/  arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/  funciton will be available. */


#define FF_MIN_SS		512
/*扇区缓冲的最小值,一般设置为 512*/
#define FF_MAX_SS		512
/*扇区缓冲的最大值,一般设置为 512*/
/* This set of options configures the range of sector size to be supported. (512,
/  1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/  harddisk. But a larger value may be required for on-board flash memory and some
/  type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/  for variable sector size mode and disk_ioctl() function needs to implement
/  GET_SECTOR_SIZE command. */


#define FF_LBA64		0
/* 这个选项用于设置是否支持64-bit LBA,如果要支持那FF_FS_EXFAT也必须使能;
   STM32F4的SDIO接口不支持超过32G的卡,FF_FS_EXFAT必须为0,所以此项必须为0
This option switches support for 64-bit LBA. (0:Disable or 1:Enable)
/  To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */


#define FF_MIN_GPT		0x10000000
/* 只有使能FF_LBA64才有效;STM32F4的SDIO接口不支持超过32G的卡,FF_FS_EXFAT和FF_LBA64必须为0,所以此项无意义
Minimum number of sectors to switch GPT format to create partition in f_mkfs and
/  f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */


#define FF_USE_TRIM		0
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
/  To enable Trim function, also CTRL_TRIM command should be implemented to the
/  disk_ioctl() function. */



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

#define FF_FS_TINY		0
/*
	是否使用缩小版的FATFS
*/
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/  At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
/  Instead of private sector buffer eliminated from the file object, common sector
/  buffer in the filesystem object (FATFS) is used for the file data transfer. */


#define FF_FS_EXFAT		0
/* 用来设置是否使用exFAT文件系统,用于支持容量大于32G的SD卡。
   STM32F4的SDIO接口不支持超过32G的卡,所以此项必须为0
This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/  To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/  Note that enabling exFAT discards ANSI C (C89) compatibility. */


#define FF_FS_NORTC		0
#define FF_NORTC_MON	1
#define FF_NORTC_MDAY	1
#define FF_NORTC_YEAR	2019
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
/  any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/  the timestamp function. Every object modified by FatFs will have a fixed timestamp
/  defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/  To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/  added to the project to read current time form real-time clock. FF_NORTC_MON,
/  FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
/  These options have no effect in read-only configuration (FF_FS_READONLY = 1). */


#define FF_FS_NOFSINFO	0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/  option, and f_getfree() function at first time after volume mount will force
/  a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/  bit0=0: Use free cluster count in the FSINFO if available.
/  bit0=1: Do not trust free cluster count in the FSINFO.
/  bit1=0: Use last allocated cluster number in the FSINFO if available.
/  bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/


#define FF_FS_LOCK		0
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
/  and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
/  is 1.
/
/  0:  Disable file lock function. To avoid volume corruption, application program
/      should avoid illegal open, remove and rename to the open objects.
/  >0: Enable file lock function. The value defines how many files/sub-directories
/      can be opened simultaneously under file lock control. Note that the file
/      lock control is independent of re-entrancy. */


/* #include <somertos.h>	// O/S definitions */
#define FF_FS_REENTRANT	0
#define FF_FS_TIMEOUT	1000
#define FF_SYNC_t		NULL
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/  module itself. Note that regardless of this option, file access to different
/  volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/  and f_fdisk() function, are always not re-entrant. Only file/directory access
/  to the same volume is under control of this function.
/
/   0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
/   1: Enable re-entrancy. Also user provided synchronization handlers,
/      ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/      function, must be added to the project. Samples are available in
/      option/syscall.c.
/
/  The FF_FS_TIMEOUT defines timeout period in unit of time tick.
/  The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/  SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/  included somewhere in the scope of ff.h. */



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

5、修改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 "sdio.h"

/* 驱动器宏定义 */
#define SD_Card		0	/* Example: Map Ramdisk to physical drive 0 */

/*-----------------------------------------------------------------------*/
/* 获取驱动器的状态 ,可以直接返回RES_OK                                                     */
/*-----------------------------------------------------------------------*/

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



/*-----------------------------------------------------------------------*/
/* 磁盘初始化                                                   */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
	uint8_t ret = 0;
	
	switch (pdrv) {
	case SD_Card :
		ret = MX_SDIO_SD_Init();//SD卡初始化
		break;
	}
	if(ret) return STA_NOINIT;
	else return 0;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)  
 * @brief       读扇区
 * @param       pdrv   : 磁盘编号0~9
 * @param       buff   : 数据接收缓冲首地址
 * @param       sector : 扇区地址
 * @param       count  : 需要读取的扇区数
 * @retval      无
 */
/*-----------------------------------------------------------------------*/

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 ret = 0;
	if(!count) return RES_PARERR;//读取扇区的数量不能为0

	switch (pdrv) 
	{
		case SD_Card :
		{
			ret = sd_read_disk(buff, sector, count);//如果读取失败就将SD卡重新初始化
			while(ret)
			{
				MX_SDIO_SD_Init();//SD卡初始化
				ret = sd_read_disk(buff, sector, count);
			}
			break;		
		}
	
		default :
			ret = 1;
	}
	if(ret == 0) return RES_OK;
	else 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 ret = 0;
	if(!count) return RES_PARERR;//读取扇区的数量不能为0

	switch (pdrv) 
	{
		case SD_Card :
		{
				ret = sd_write_disk((uint8_t *)buff, sector, count);//如果读取失败就将SD卡重新初始化
				while(ret)
				{
					MX_SDIO_SD_Init();//SD卡初始化
					ret = sd_write_disk((uint8_t *)buff, sector, count);
				}
				break;		
		}
		default :
			ret = 1;
	}
	if(ret == 0) return RES_OK;
	else return RES_ERROR;
}

#endif


/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions  
 * @brief       获取其他控制参数
 * @param       pdrv   : 磁盘编号0~9
 * @param       ctrl   : 控制代码
 * @param       buff   : 发送/接收缓冲区指针
 * @retval      无*/
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
	DRESULT res = RES_PARERR;

	if(pdrv == SD_Card)
	{
		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 = sd_card_info_handle.LogBlockSize;
					res = RES_OK;
					break;

			case GET_SECTOR_COUNT://获取扇区的数量
					*(DWORD *)buff = sd_card_info_handle.LogBlockNbr;
					res = RES_OK;
					break;

			default:
					res = RES_PARERR;
					break;
		}	
	}
	return res;
}

/**
 * @brief       获得时间
 * @param       无
 * @retval      时间
 * @note        时间编码规则如下:
 *              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;
}

6、FATFS的使用

        这里我就直接贴代码了,里面有详细的注释

/*以下代码放在main.c文件开头*/
#include "ff.h"

/*目录深度链表,每打开一个目录就新建一个节点,每关闭一个目录就删除一个节点*/
typedef struct _dir_list_ 
{
	struct _dir_list_ *next;
	uint8_t dir_name[30];//文件夹名称
}Dir_list;

uint8_t deep_count = 0;//记录当前的深度
FATFS  fs[FF_VOLUMES]; //创建磁盘对象结构体,有几个磁盘就创建几个结构体
FILINFO file_infos = { NULL };//一个用于存储文件信息的结构体变量
Dir_list *dir_lists = { NULL };//文件夹列表

/**
 * @brief       获取磁盘剩余容量
 * @param       pdrv : 磁盘编号("0:"~"9:")
 * @param       total: 总容量 (KB)
 * @param       free : 剩余容量 (KB)
 * @retval      0, 正常; 其他, 错误代码
 */
uint8_t exfuns_get_free(uint8_t *pdrv, uint32_t *total, uint32_t *free)
{
    FATFS *fs1;
    uint8_t res;
    uint32_t fre_clust = 0, fre_sect = 0, tot_sect = 0;
    
    /* 得到磁盘信息及空闲簇数量 */
    res = (uint32_t)f_getfree((const TCHAR *)pdrv, (DWORD *)&fre_clust, &fs1);

    if (res == 0)
    {
        tot_sect = (fs1->n_fatent - 2) * fs1->csize;    /* 得到总扇区数 */
        fre_sect = fre_clust * fs1->csize;              /* 得到空闲扇区数 */
        
#if FF_MAX_SS!=512                                      /* 扇区大小不是512字节,则转换为512字节 */
        tot_sect *= fs1->ssize / 512;
        fre_sect *= fs1->ssize / 512;
#endif
        
        *total = tot_sect >> 1;                         /* 单位为KB */
        *free = fre_sect >> 1;                          /* 单位为KB */
    }

    return res;
}

/**********************************************************************************************
函数功能:获取文件内容
入口参数:
	Path:文件完整路径
	mode:打开文件的模式,可选值有FA_READ、FA_WRITE、FA_CREATE_NEW等
返回值:
	无
**********************************************************************************************/
void Get_file_date(TCHAR *Path, uint8_t mode)
{
	uint32_t file_len = 0;//获取文件大小
	uint8_t *file_date = 0;//储存文件内容
	uint16_t i = 0;
	uint32_t br = 0;
	FIL files = { NULL };//一个用于指向文件的结构体
	
	if(f_open(&files, Path, mode) == FR_OK)//打开文件
	{
		file_len = f_size(&files);//获取文件长度
		printf("open %s succeed, file len = %d\n", Path, file_len);
		
		file_date = malloc(file_len);//为读取文件内容分配内存
		
		for(i=0;i<(file_len/512);i++)
		{
			if(f_read(&files, &file_date[i*512], 512, &br) != FR_OK)
			{
				printf("read %s failed \n",Path);
				break;
			}
		}
		if(file_len%512)
		{
			if(f_read(&files, &file_date[i*512], (file_len%512), &br) != FR_OK)
			{
				printf("read %s failed \n",Path);
			}						
		}
		f_close(&files);//关闭文件
		printf("file date:");
		HAL_UART_Transmit(&huart1, file_date, file_len, 1000);//打印文件内容
		printf("\r\n");
		
		memset(file_date, 0, file_len);//清空文件内容缓冲区
		file_len = 0;//清空文件长度
		free(file_date);//释放文件内容缓冲区
		
		memset(&files, 0, sizeof(files));
	}
	else printf("open %s failed \n",Path);
}

/**********************************************************************************************
函数功能:按深度打印文件夹名称
入口参数:
	dir_name:文件夹名称
	nDepth:文件夹的深度
返回值:
	无
**********************************************************************************************/
void Print_Dir(TCHAR *dir_name, uint8_t nDepth)
{
	for(int i=0; i<7*nDepth; i++){
		printf(" ");
	}
	printf("|—<< %s >>\n", dir_name);
}

/**********************************************************************************************
函数功能:按深度打印文件名称
入口参数:
	file_name:文件名称
	nDepth:文件的深度
返回值:
	无
**********************************************************************************************/
void Printf_FileName(TCHAR *file_name, uint8_t nDepth)
{
	char file_addr[100] = "", str[100] = "";//定义两个字符串
	
	Dir_list *udir_list = { NULL };//文件夹列表
	for(udir_list = dir_lists; udir_list != NULL; udir_list=udir_list->next)
	{
		sprintf(str, "%s/%s",udir_list->dir_name, file_addr);
		strcpy(file_addr, str);
	}	
	strcat(file_addr,file_name);
	
	for(int i=0; i<7*nDepth; i++){
	printf(" ");
	}
	printf("|***( %s )\n", file_addr);//file_name

	/*不打印最前面的System Volume Information文件夹的内容*/
	if(strncmp("System Volume Information",(char *)dir_lists->dir_name,strlen("System Volume Information"))!=0)  Get_file_date(file_addr, FA_READ);//|FA_WRITE
	
	memset(file_addr, 0, sizeof(file_addr));
	memset(str, 0, sizeof(str));
}

/**********************************************************************************************
函数功能:以文件树的形式打印当前路径下指定深度的所有文件/文件夹名称
入口参数:
	Path:指定路径
	nMaxDepth:最大深度
返回值:
	0:成功;
  1:失败;
**********************************************************************************************/
uint8_t Scan_file(TCHAR *Path, uint8_t nMaxDepth)
{
	DIR dir = { NULL };
	FRESULT res = f_opendir(&dir, Path);
	uint8_t sta = 0;
	Dir_list *udir_list = malloc(sizeof(Dir_list));;
	
	if(res == FR_OK)
	{
		/*新建节点*/
		strcpy((char *)udir_list->dir_name, Path);//复制路径名称
		udir_list->next = dir_lists;
		dir_lists = udir_list;
		udir_list = 0;
		
		Print_Dir(Path, deep_count);
		deep_count++;
			
		do
		{
			res = f_readdir(&dir, &file_infos);
			
			if(res == FR_OK)
			{
				if(file_infos.fname[0])
				{
					if((file_infos.fattrib & AM_DIR) == 0)
					{
						/* 目标为文件,打印文件名 */
						Printf_FileName(file_infos.fname, deep_count);
					}
					else
					{
						/*目标为文件夹,打印文件夹名称,并执行递归 */
						if(deep_count < nMaxDepth)/* 在寻址深度内,进行递归 */
						{							
							sta = Scan_file(file_infos.fname, nMaxDepth);
							if(sta != 0)  break;
						}
					}
				}else break;
			}else printf("f_readdir defeat, res=%d\n", res);
		}while(res == FR_OK);
		
		if(res == FR_OK && sta == 0 && deep_count > 0)
		{
			deep_count--;
		}
		
		/*删除节点*/
		udir_list = dir_lists;
		dir_lists = dir_lists->next;
		memset(udir_list, 0, sizeof(Dir_list));
		free(udir_list);
		
		f_closedir(&dir);
	}
	else printf("f_opendir defeat, res=%d\n", res);

	return sta;
}

/*以下代码替换main函数*/
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint8_t res = 0;
	uint32_t total, free;//SD卡的总容量和剩余容量

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();

	while(MX_SDIO_SD_Init())
	{
		HAL_Delay(10);
	}
  /* USER CODE BEGIN 2 */
	show_sdcard_info();//打印SD卡信息

	/*一维数组在记得加取地址符*/
	res = f_mount(&fs[0], "0:", 1);                                                         /* 挂载SD卡 */
	if (res == FR_NO_FILESYSTEM)                                                                 /* FLASH磁盘,FAT文件系统错误,重新格式化FLASH */
	{
			printf("SD Disk Formatting...\n");
			res = f_mkfs("0:", 0, 0, FF_MAX_SS);                                         /* 格式化FLASH,1:,盘符;0,使用默认格式化参数 */

			if (res == 0)
			{
					f_setlabel((const TCHAR *)"0:ALIENTEK");                                 /* 设置Flash磁盘的名字为:ALIENTEK */
					printf("SD Disk Format Finish\n");
			}
			else
			{
					printf("SD Disk Format Error\n");
			}

			HAL_Delay(1000);
	}	

	while (exfuns_get_free((uint8_t *)"0:", &total, &free))                          /* 得到SD卡的总容量和剩余容量 */
	{
		printf("SD Card Fatfs Error!\n");
		HAL_Delay(1000);
	}

	printf("FATFS OK!\nSD Total Size: %d MB\nSD  Free Size: %d MB\n",(total >> 10),(free >> 10));

	Scan_file((TCHAR *)"0:", 5);//扫描所有文件并且打印文件内容
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

注意:记得适当修改堆栈的大小,因为里面有一部分内容使用的动态申请内存

7、测试结果

如果不想要打印文件内容,直接屏蔽“Printf_FileName”函数内的“Get_file_date(file_addr, FA_READ);”语句即可。

上次和本次推文的源代码在这:

相关文章:

  • AI测试引擎中CV和ML模型的技术架构
  • 【Linux】VIM 编辑器,编辑加速引擎
  • 赚钱的底层逻辑
  • 开关二极管热插拔保护方案
  • MySQL-存储引擎和索引
  • [dp11_最长子序列(不连续)] 最长数对链 | 最长定差子序列 最长的斐波那契子序列的长度
  • Nginx底层架构(非常清晰)
  • redis系列--1.redis是什么
  • qt(vs2010) 手动配置moc生成规则
  • 数据大屏只能撑撑场面?
  • Uniapp:本地存储
  • 卫星电话扬帆智慧海洋,构筑蓝海通信新生态
  • 48V/2kW储能电源纯正弦波逆变器详细设计方案-可量产
  • 【7】深入学习Buffer缓冲区-Nodejs开发入门
  • CS5346 - Annotation in Visualization (可视化中的注释)
  • 【Python爬虫】简单案例介绍3
  • 详细解读 box-sizing: border-box;
  • 大模型——Crawl4AI入门指南
  • 【高性能缓存Redis_中间件】三、redis 精通:性能优化与生产实践
  • 从零开始:前端开发者的SEO优化入门与实战
  • 江苏银行去年净赚超318亿增超10%,不良贷款率持平
  • 一季度全社会用电量同比增长2.5%,3月增速显著回升
  • 中国正在俄罗斯国内生产武器?外交部:坚决反对无端指责和政治操弄
  • 黄仁勋:英伟达坚定不移服务中国市场,AI将在每个行业引发颠覆性变革
  • 【社论】让民营企业在上海大显身手
  • 北京航空航天大学强基计划今年新增4个招生培养方向