編譯環境
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