编译环境

STM32CubeMX………: 6.2.1
MDK……………………: 5.27.1.0
Firmware Package……: V1.9.0
硬件 ……………………: 安富莱V7开发板

STM32CubeMX配置

时钟根据需要设置即可,除SD分频系数,不影响其他功能,另外开启串口1外设。

注意分频系数,与使用SD卡速度有关。

在Platform Setting下设置SD卡插入检测引脚。

代码修改

在fatfs.c下新增加以下代码

#include "string.h"
#include "stdio.h"
DIR DirInf;
FILINFO FileInf;static void DispMenu(void);
static void ViewRootDir(void);
static void CreateNewFile(void);
static void ReadFileData(void);
static void CreateDir(void);
static void DeleteDirFile(void);
static void WriteFileTest(void);
/* FatFs API的返回值 */
static const char * FR_Table[]=
{"FR_OK:成功",                                            /* (0) Succeeded */"FR_DISK_ERR:底层硬件错误",                           /* (1) A hard error occurred in the low level disk I/O layer */"FR_INT_ERR:断言失败",                                  /* (2) Assertion failed */"FR_NOT_READY:物理驱动没有工作",                         /* (3) The physical drive cannot work */"FR_NO_FILE:文件不存在",                                /* (4) Could not find the file */"FR_NO_PATH:路径不存在",                               /* (5) Could not find the path */"FR_INVALID_NAME:无效文件名",                          /* (6) The path name format is invalid */"FR_DENIED:由于禁止访问或者目录已满访问被拒绝",         /* (7) Access denied due to prohibited access or directory full */"FR_EXIST:文件已经存在",                              /* (8) Access denied due to prohibited access */"FR_INVALID_OBJECT:文件或者目录对象无效",                /* (9) The file/directory object is invalid */"FR_WRITE_PROTECTED:物理驱动被写保护",                   /* (10) The physical drive is write protected */"FR_INVALID_DRIVE:逻辑驱动号无效",                        /* (11) The logical drive number is invalid */"FR_NOT_ENABLED:卷中无工作区",                             /* (12) The volume has no work area */"FR_NO_FILESYSTEM:没有有效的FAT卷",                    /* (13) There is no valid FAT volume */"FR_MKFS_ABORTED:由于参数错误f_mkfs()被终止",            /* (14) The f_mkfs() aborted due to any parameter error */"FR_TIMEOUT:在规定的时间内无法获得访问卷的许可",      /* (15) Could not get a grant to access the volume within defined period */"FR_LOCKED:由于文件共享策略操作被拒绝",              /* (16) The operation is rejected according to the file sharing policy */"FR_NOT_ENOUGH_CORE:无法分配长文件名工作区",             /* (17) LFN working buffer could not be allocated */"FR_TOO_MANY_OPEN_FILES:当前打开的文件数大于_FS_SHARE", /* (18) Number of open files > _FS_SHARE */"FR_INVALID_PARAMETER:参数无效"                       /* (19) Given parameter is invalid */
};
void fatfs_test(uint8_t cmd)
{printf("\r\n");switch (cmd){case '1':printf("【1 - ViewRootDir】\r\n");ViewRootDir();      /* 显示SD卡根目录下的文件名 */break;case '2':printf("【2 - CreateNewFile】\r\n");CreateNewFile();    /* 创建一个新文件,写入一个字符串 */break;case '3':printf("【3 - ReadFileData】\r\n");ReadFileData();        /* 读取根目录下armfly.txt的内容 */break;case '4':printf("【4 - CreateDir】\r\n");CreateDir();      /* 创建目录 */break;case '5':printf("【5 - DeleteDirFile】\r\n");DeleteDirFile(); /* 删除目录和文件 */break;case '6':printf("【6 - TestSpeed】\r\n");WriteFileTest();  /* 速度测试 */break;default:DispMenu();break;}}
/*
*********************************************************************************************************
*   函 数 名: DispMenu
*   功能说明: 显示操作提示菜单
*   形    参:无
*   返 回 值: 无
*********************************************************************************************************
*/
static void DispMenu(void)
{printf("\r\n------------------------------------------------\r\n");printf("请选择操作命令,打开SD卡模拟U盘操作期间不支持再调用命令1-6:\r\n");printf("1 - 显示根目录下的文件列表\r\n");printf("2 - 创建一个新文件armfly.txt\r\n");printf("3 - 读armfly.txt文件的内容\r\n");printf("4 - 创建目录\r\n");printf("5 - 删除文件和目录\r\n");printf("6 - 读写文件速度测试\r\n");printf("a - 打开SD卡模拟U盘\r\n");printf("b - 关闭SD卡模拟U盘\r\n");
}/*
*********************************************************************************************************
*   函 数 名: ViewRootDir
*   功能说明: 显示SD卡根目录下的文件名
*   形    参:无
*   返 回 值: 无
*********************************************************************************************************
*/
extern SD_HandleTypeDef hsd1;
static void ViewRootDir(void)
{FRESULT result;uint32_t cnt = 0;FILINFO fno;/* 挂载文件系统 */result = f_mount(&SDFatFS, SDPath, 0);   /* Mount a logical drive */if (result != FR_OK){printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);}/* 打开根文件夹 */result = f_opendir(&DirInf, SDPath); /* 如果不带参数,则从当前目录开始 */if (result != FR_OK){printf("打开根目录失败  (%s)\r\n", FR_Table[result]);return;}printf("属性        |  文件大小 | 短文件名 | 长文件名\r\n");for (cnt = 0; ;cnt++){result = f_readdir(&DirInf, &FileInf);      /* 读取目录项,索引会自动下移 */if (result != FR_OK || FileInf.fname[0] == 0){break;}if (FileInf.fname[0] == '.'){continue;}/* 判断是文件还是子目录 */if (FileInf.fattrib & AM_DIR){printf("(0x%02d)目录  ", FileInf.fattrib);}else{printf("(0x%02d)文件  ", FileInf.fattrib);}f_stat(FileInf.fname, &fno);/* 打印文件大小, 最大4G */printf(" %10d", (int)fno.fsize);printf("  %s\r\n", (char *)FileInf.fname);  /* 长文件名 */}/* 打印卡速度信息 */if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED){printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");           }else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED){printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");            }else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED){printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");   }    /* 卸载文件系统 */f_mount(NULL, SDPath, 0);
}
/*
*********************************************************************************************************
*   函 数 名: CreateNewFile
*   功能说明: 在SD卡创建一个新文件,文件内容填写“www.armfly.com”
*   形    参:无
*   返 回 值: 无
*********************************************************************************************************
*/
char FsWriteBuf[1024] = {"FatFS Write Demo \r\n www.armfly.com \r\n"};
static void CreateNewFile(void)
{FRESULT result;uint32_t bw;char path[32];/* 挂载文件系统 */result = f_mount(&SDFatFS, SDPath, 0);           /* Mount a logical drive */if (result != FR_OK){printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);}/* 打开文件 */sprintf(path, "%sarmfly.txt", SDPath);result = f_open(&SDFile, path, FA_CREATE_ALWAYS | FA_WRITE);if (result == FR_OK){printf("armfly.txt 文件打开成功\r\n");}else{printf("armfly.txt 文件打开失败  (%s)\r\n", FR_Table[result]);}/* 写一串数据 */result = f_write(&SDFile, FsWriteBuf, strlen(FsWriteBuf), &bw);if (result == FR_OK){printf("armfly.txt 文件写入成功\r\n");}else{printf("armfly.txt 文件写入失败  (%s)\r\n", FR_Table[result]);}/* 关闭文件*/f_close(&SDFile);/* 卸载文件系统 */f_mount(NULL, SDPath, 0);
}
/*
*********************************************************************************************************
*   函 数 名: ReadFileData
*   功能说明: 读取文件armfly.txt前128个字符,并打印到串口
*   形    参:无
*   返 回 值: 无
*********************************************************************************************************
*/
char FsReadBuf[1024];
static void ReadFileData(void)
{FRESULT result;uint32_t bw;char path[64];/* 挂载文件系统 */result = f_mount(&SDFatFS, SDPath, 0);           /* Mount a logical drive */if (result != FR_OK){printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);}/* 打开文件 */sprintf(path, "%sarmfly.txt", SDPath);result = f_open(&SDFile, path, FA_OPEN_EXISTING | FA_READ);if (result !=  FR_OK){printf("Don't Find File : armfly.txt\r\n");return;}/* 读取文件 */result = f_read(&SDFile, FsReadBuf, sizeof(FsReadBuf), &bw);if (bw > 0){FsReadBuf[bw] = 0;printf("\r\narmfly.txt 文件内容 : \r\n%s\r\n", FsReadBuf);}else{printf("\r\narmfly.txt 文件内容 : \r\n");}/* 关闭文件*/f_close(&SDFile);/* 卸载文件系统 */f_mount(NULL, SDPath, 0);
}/*
*********************************************************************************************************
*   函 数 名: CreateDir
*   功能说明: 在SD卡根目录创建Dir1和Dir2目录,在Dir1目录下创建子目录Dir1_1
*   形    参:无
*   返 回 值: 无
*********************************************************************************************************
*/
static void CreateDir(void)
{FRESULT result;char path[64]; /* 挂载文件系统 */result = f_mount(&SDFatFS, SDPath, 0);          /* Mount a logical drive */if (result != FR_OK){printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);}/* 创建目录/Dir1 */sprintf(path, "%sDir1", SDPath);result = f_mkdir(path);if (result == FR_OK){printf("f_mkdir Dir1 Ok\r\n");}else if (result == FR_EXIST){printf("Dir1 目录已经存在(%d)\r\n", result);}else{printf("f_mkdir Dir1 失败 (%s)\r\n", FR_Table[result]);return;}/* 创建目录/Dir2 */sprintf(path, "%sDir2", SDPath);result = f_mkdir(path);if (result == FR_OK){printf("f_mkdir Dir2 Ok\r\n");}else if (result == FR_EXIST){printf("Dir2 目录已经存在(%d)\r\n", result);}else{printf("f_mkdir Dir2 失败 (%s)\r\n", FR_Table[result]);return;}/* 创建子目录 /Dir1/Dir1_1      注意:创建子目录Dir1_1时,必须先创建好Dir1 */sprintf(path, "%sDir1/Dir1_1", SDPath);result = f_mkdir(path); /* */if (result == FR_OK){printf("f_mkdir Dir1_1 成功\r\n");}else if (result == FR_EXIST){printf("Dir1_1 目录已经存在 (%d)\r\n", result);}else{printf("f_mkdir Dir1_1 失败 (%s)\r\n", FR_Table[result]);return;}/* 卸载文件系统 */f_mount(NULL, SDPath, 0);
}/*
*********************************************************************************************************
*   函 数 名: DeleteDirFile
*   功能说明: 删除SD卡根目录下的 armfly.txt 文件和 Dir1,Dir2 目录
*   形    参:无
*   返 回 值: 无
*********************************************************************************************************
*/
static void DeleteDirFile(void)
{FRESULT result;uint8_t i;char path[64]; /* 挂载文件系统 */result = f_mount(&SDFatFS, SDPath, 0);            /* Mount a logical drive */if (result != FR_OK){printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);}/* 删除目录/Dir1 【因为还存在目录非空(存在子目录),所以这次删除会失败】*/sprintf(path, "%sDir1", SDPath);result = f_unlink(path);if (result == FR_OK){printf("删除目录Dir1成功\r\n");}else if (result == FR_NO_FILE){printf("没有发现文件或目录 :%s\r\n", "/Dir1");}else{printf("删除Dir1失败(错误代码 = %d) 文件只读或目录非空\r\n", result);}/* 先删除目录/Dir1/Dir1_1 */sprintf(path, "%sDir1/Dir1_1", SDPath);result = f_unlink(path);if (result == FR_OK){printf("删除子目录/Dir1/Dir1_1成功\r\n");}else if ((result == FR_NO_FILE) || (result == FR_NO_PATH)){printf("没有发现文件或目录 :%s\r\n", "/Dir1/Dir1_1");}else{printf("删除子目录/Dir1/Dir1_1失败(错误代码 = %d) 文件只读或目录非空\r\n", result);}/* 先删除目录/Dir1 */sprintf(path, "%sDir1", SDPath);result = f_unlink(path);if (result == FR_OK){printf("删除目录Dir1成功\r\n");}else if (result == FR_NO_FILE){printf("没有发现文件或目录 :%s\r\n", "/Dir1");}else{printf("删除Dir1失败(错误代码 = %d) 文件只读或目录非空\r\n", result);}/* 删除目录/Dir2 */sprintf(path, "%sDir2", SDPath);result = f_unlink(path);if (result == FR_OK){printf("删除目录 Dir2 成功\r\n");}else if (result == FR_NO_FILE){printf("没有发现文件或目录 :%s\r\n", "/Dir2");}else{printf("删除Dir2 失败(错误代码 = %d) 文件只读或目录非空\r\n", result);}/* 删除文件 armfly.txt */sprintf(path, "%sarmfly.txt", SDPath);result = f_unlink(path);if (result == FR_OK){printf("删除文件 armfly.txt 成功\r\n");}else if (result == FR_NO_FILE){printf("没有发现文件或目录 :%s\r\n", "armfly.txt");}else{printf("删除armfly.txt失败(错误代码 = %d) 文件只读或目录非空\r\n", result);}/* 删除文件 speed1.txt */for (i = 0; i < 20; i++){sprintf(path, "%sSpeed%02d.txt", SDPath, i);/* 每写1次,序号递增 */    result = f_unlink(path);if (result == FR_OK){printf("删除文件%s成功\r\n", path);}else if (result == FR_NO_FILE){printf("没有发现文件:%s\r\n", path);}else{printf("删除%s文件失败(错误代码 = %d) 文件只读或目录非空\r\n", path, result);}}/* 卸载文件系统 */f_mount(NULL, SDPath, 0);
}/*
*********************************************************************************************************
*   函 数 名: WriteFileTest
*   功能说明: 测试文件读写速度
*   形    参:无
*   返 回 值: 无
*********************************************************************************************************
*/
#define TEST_FILE_LEN           (2*1024*1024)   /* 用于测试的文件长度 */
#define BUF_SIZE                (4*1024)        /* 每次读写SD卡的最大数据长度 */
uint8_t g_TestBuf[BUF_SIZE];
static void WriteFileTest(void)
{FRESULT result;char path[64]; uint32_t bw;uint32_t i,k;uint32_t runtime1,runtime2,timelen;uint8_t err = 0;static uint8_t s_ucTestSn = 0;for (i = 0; i < sizeof(g_TestBuf); i++){g_TestBuf[i] = (i / 512) + '0';}/* 挂载文件系统 */result = f_mount(&SDFatFS, SDPath, 0);            /* Mount a logical drive */if (result != FR_OK){printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);}/* 打开文件 */sprintf(path, "%sSpeed%02d.txt", SDPath, s_ucTestSn++); /* 每写1次,序号递增 */  result = f_open(&SDFile, path, FA_CREATE_ALWAYS | FA_WRITE);/* 写一串数据 */printf("开始写文件%s %dKB ...\r\n", path, TEST_FILE_LEN / 1024);runtime1 = HAL_GetTick(); /* 读取系统运行时间 */for (i = 0; i < TEST_FILE_LEN / BUF_SIZE; i++){result = f_write(&SDFile, g_TestBuf, sizeof(g_TestBuf), &bw);if (result == FR_OK){if (((i + 1) % 8) == 0){printf(".");}}else{err = 1;printf("%s文件写失败\r\n", path);break;}}runtime2 = HAL_GetTick();   /* 读取系统运行时间 */if (err == 0){timelen = (runtime2 - runtime1);printf("\r\n  写耗时 : %dms   平均写速度 : %dB/S (%dKB/S)\r\n",timelen,(TEST_FILE_LEN * 1000) / timelen,((TEST_FILE_LEN / 1024) * 1000) / timelen);}f_close(&SDFile);      /* 关闭文件*//* 开始读文件测试 */result = f_open(&SDFile, path, FA_OPEN_EXISTING | FA_READ);if (result !=  FR_OK){printf("没有找到文件: %s\r\n", path);return;}printf("开始读文件 %dKB ...\r\n", TEST_FILE_LEN / 1024);runtime1 = HAL_GetTick();   /* 读取系统运行时间 */for (i = 0; i < TEST_FILE_LEN / BUF_SIZE; i++){result = f_read(&SDFile, g_TestBuf, sizeof(g_TestBuf), &bw);if (result == FR_OK){if (((i + 1) % 8) == 0){printf(".");}/* 比较写入的数据是否正确,此语句会导致读卡速度结果降低到 3.5MBytes/S */for (k = 0; k < sizeof(g_TestBuf); k++){if (g_TestBuf[k] != (k / 512) + '0'){err = 1;printf("Speed1.txt 文件读成功,但是数据出错\r\n");break;}}if (err == 1){break;}}else{err = 1;printf("Speed1.txt 文件读失败\r\n");break;}}runtime2 = HAL_GetTick();   /* 读取系统运行时间 */if (err == 0){timelen = (runtime2 - runtime1);printf("\r\n  读耗时 : %dms   平均读速度 : %dB/S (%dKB/S)\r\n", timelen,(TEST_FILE_LEN * 1000) / timelen, ((TEST_FILE_LEN / 1024) * 1000) / timelen);}/* 关闭文件*/f_close(&SDFile);/* 卸载文件系统 */f_mount(NULL, SDPath, 0);
}

工程链接

https://download.csdn.net/download/qq992035949/19212701

STM32CubeMX学习--SD_FATFS相关推荐

  1. STM32CubeMX学习笔记(15)——电源管理(PWR)低功耗睡眠模式

    一.低功耗模式简介 系统提供了多个低功耗模式,可在 CPU 不需要运行时(例如等待外部事件时)节省功耗.由用户根据应用选择具体的低功耗模式,以在低功耗.短启动时间和可用唤醒源之间寻求最佳平衡. 睡眠模 ...

  2. STM32CubeMX学习笔记(24)——通用定时器接口使用(电容按键检测)

    一.电容按键简介 电容器(简称为电容)就是可以容纳电荷的器件,两个金属块中间隔一层绝缘体就可以构成一个最简单的电容.如图 32-1(俯视图),有两个金属片,之间有一个绝缘介质,这样就构成了一个电容.这 ...

  3. STM32CubeMX学习笔记(25)——FatFs文件系统使用(操作SPI Flash)

    一.FatFs简介 FatFs 是面向小型嵌入式系统的一种通用的 FAT 文件系统.它完全是由 ANSI C 语言编写并且完全独立于底层的 I/O 介质.因此它可以很容易地不加修改地移植到其他的处理器 ...

  4. STM32CubeMX学习(一) USB HID 双向通信

    STM32CubeMX学习(一) USB HID 双向通信 简介 CubeMX新建工程(串口+LED) 测试串口和LED 设置USB HID 测试USB HID通信 结论 简介 利用正点原子F407探 ...

  5. STM32CubeMX学习笔记(38)——FSMC接口使用(TFT-LCD屏显示)

    一.TFT-LCD简介 TFT-LCD(Thin Film Transistor-Liquid Crystal Display) 即薄膜晶体管液晶显示器.TFT-LCD 与无源 TN-LCD. STN ...

  6. STM32CubeMX学习笔记(9)——I2C接口使用(读写EEPROM AT24C02)

    一.I2C简介 I2C(Inter-Integrated Circuit ,内部集成电路) 总线是一种由飞利浦 Philip 公司开发的串行总线.是两条串行的总线,它由一根数据线(SDA)和一根 时钟 ...

  7. STM32CubeMX学习笔记(16)——电源管理(PWR)低功耗停止模式

    一.低功耗模式简介 系统提供了多个低功耗模式,可在 CPU 不需要运行时(例如等待外部事件时)节省功耗.由用户根据应用选择具体的低功耗模式,以在低功耗.短启动时间和可用唤醒源之间寻求最佳平衡. 睡眠模 ...

  8. STM32CubeMX学习笔记(22)——CRC接口使用

    一.CRC简介 CRC(Cyclic Redundancy Check),即循环冗余校验,是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者 ...

  9. STM32CubeMX 学习(5)输入捕获实验

    个人学习记录 文章目录 一.新建工程 二.选择芯片型号 三.配置时钟 四.配置调试模式 五.定时器(输入捕获)参数配置 六.生成 Keil 工程 七.中断函数写在哪 八.测试示例 一.新建工程 二.选 ...

最新文章

  1. bootstrap-wysiwyg中JS控件富文本的用法
  2. UR #3 核聚变反应强度( gcd )
  3. 学了redis我能拿你做什么
  4. 前端常见知识点五之Fetch
  5. Silverlight, B/S or C/S?
  6. 【Android开发】消息处理类(Handler)与消息类(Message)介绍
  7. Web页面获取用户控件页面中服务器控件的值
  8. java 单文件上传_java – JIRA中的单个文件上传
  9. WINDOWS对文件签名,算法如何由sha1改为sha256/sha512
  10. HTTPS请求过程图解
  11. 浅谈Attention注意力机制
  12. VS-( 图片的上传 )
  13. TTL、Ping包最大字节数、网络时延、抖动、丢包率,看完瞬间变大神!
  14. 厦大C在线实验题3 分数约简
  15. 批量保存拼多多批发商城商品主图及视频
  16. Java读取接口数据并保存到数据库
  17. Unity程序在VR一体机(Android)上卡死(闪退)后怎么办?——用adb查看android上某Unity app的debug信息
  18. C语言编程100题-5.8
  19. bzoj2592 Symmetry
  20. warning: React does not recognize the xxx prop on a DOM element

热门文章

  1. Loj #6503. 「雅礼集训 2018 Day4」Magic
  2. 在网上卖药需要什么资质?入驻平台需要什么条件
  3. sklearn随机森林模型参数解释
  4. 使用css选择器实现表格隔行换色
  5. 2019年了,我似乎长进不大,小斧子还得卖力砍啊
  6. 361页13万字“智慧公安”系统工程设计方案
  7. 大数据对教育行业重要作用有哪些?
  8. python execjs是如何请求网页的_python运行js---execjs 使用
  9. 物联网协议选型-MQTT/AMQP/CoAP/HTTP/LwM2M
  10. 如何在Excel中创建一个折线图?