一、简介
实验目的: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);
}
}