?
一、環境介紹
STM32程序開發IDE: keil5
STM32程序風格: 采用寄存器方式開發,注釋齊全,執行效率高,方便移植
硬件包含: 一塊STM32F103ZET6系統板、一個SPI接口的SD卡卡槽模塊、一張SD卡
這篇文章主要演示FATFS文件系統如何移植到自己的工程,并完成文件的讀寫。
因為SD卡采用的是SPI模擬時序,所以,其他單片機一樣可以照著移植,代碼都可以復制粘貼的。
![](https://file.elecfans.com//web2/M00/34/A3/pYYBAGImrryADoEjAAYIqYP9ePQ889.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
?
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
![](https://file.elecfans.com//web2/M00/34/9C/poYBAGImrr2Ae6CeAASAibYkP3o834.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
?
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
二、FATFS文件系統介紹
2.1 FATFS簡介
FatFs 是一種完全免費開源的 FAT 文件系統模塊,專門為小型的嵌入式系統而設計。它完全用標準C 語言編寫,所以具有良好的硬件平臺獨立性,可以移植到 8051、 PIC、 AVR、 SH、 Z80、 H8、 ARM 等系列單片機上而只需做簡單的修改。它支持 FATl2、 FATl6 和 FAT32,支持多個存儲媒介;有獨立的緩沖區,可以對多個文件進行讀/寫,并特別對 8 位單片機和 16 位單片機做了優化。
2.2 特點
- Windows兼容的FAT文件系統
- 不依賴于平臺,易于移植
- 代碼和工作區占用空間非常小
- 多種配置選項
- 多卷(物理驅動器和分區)
- 多ANSI/OEM代碼頁,包括DBCS
- 在ANSI/OEM或Unicode中長文件名的支持
- RTOS的支持
- 多扇區大小的支持
- 只讀,最少API,I/O緩沖區等等
2.3 移植性
fatfs模塊是ANSI C(C89)編寫的。 沒有平臺的依賴, 編譯器只要符合ANSI C標準就可以編譯。
fatf模塊假設大小的字符/短/長8/16/32位和int是16或32位。 這些數據類型在integer.h文件中定義。這些數據類型在大多數的編譯器中定義都符合要求。 如果現有的定義與編譯器有任何沖突發生時,需要自己解決。
2.4 源碼下載
FATFS文件系統官網下載地址:http://elm-chan.org/fsw/ff/00index_e.html
這是在STM32上移植好的工程,可以直接下載使用,這個只要是STM32F103系列的所以芯片都可以使用工程:https://download.csdn.net/download/xiaolong1126626497/19687693
![](https://file.elecfans.com//web2/M00/34/A3/pYYBAGImrr2AZl5jAABivJKQrsI572.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
FATFS有兩個版本,一個大版本,一個小版本。小版本主要用于8位機(內存小)使用。
下載圖:
![](https://file.elecfans.com//web2/M00/34/9C/poYBAGImrr6ASdumAACkA6UdQco897.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
2.5 FATFS源碼文件介紹
將下載的源碼解壓后可以得到兩個文件夾: doc 和 src。 doc 里面主要是對 FATFS 的介紹(離線文檔—英文和日文),而 src 里面才是我們需要的源碼。
其中,與平臺無關的是:
ffconf.h FATFS配置文件 ff.h 應用層頭文件 ff.c 應用層源文件 diskio.h 硬件層頭文件 interger.h 數據類型定義頭文件 option 可選的外部功能(比如支持中文等) |
與平臺相關的代碼:
diskio.c 底層接口文件(需要用戶提供)
FATFS 模塊在移植的時候,我們一般只需要修改 2 個文件,即 ffconf.h 和 diskio.c。
FATFS模塊的所有配置項都是存放在 ffconf.h 里面,我們可以通過配置里面的一些選項,來滿足自己的需求。
FATFS最頂層是應用層,使用者無需理會 FATFS 的內部結構和復雜的 FAT 協議,只需要調用FATFS 模塊提供給用戶的一系列應用接口函數,如 f_open, f_read, f_write 和 f_close 等,就可以像在 PC 上讀/寫文件那樣簡單。
中間層 FATFS 模塊, 實現了 FAT 文件讀/寫協議。 FATFS 模塊提供的是 ff.c 和 ff.h。除非有必要,使用者一般不用修改,使用時將頭文件直接包含進去即可。
需要我們編寫移植代碼的是 FATFS 模塊提供的底層接口,它包括存儲媒介讀/寫接口 ( disk、I/O) 和供給文件創建修改時間的實時時鐘。
三、 移植FATFS文件系統
移植之前,首先得準備一個能正常編譯的工程,并且工程里有SD卡的驅動代碼,提供了讀寫扇區這些函數才能進行FATFS文件系統的正常移植。
關于如何編寫SD卡驅動,SD卡的時序介紹、命令介紹等知識點下篇文章再講解。這篇文章重點是FATFS文件系統的移植過程。
3.1 新建工程
FATFS文件系統源碼下載下來,解壓之后,移植修改的步驟如下:
![](https://file.elecfans.com//web2/M00/34/A3/pYYBAGImrr6ACxsTAABcTkc9Xmc446.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
打開KEIL工程,添加FATFS文件源碼:
![](https://file.elecfans.com//web2/M00/34/9C/poYBAGImrr-Aa4rZAAGZlNN1Hmw405.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
![](https://file.elecfans.com//web2/M00/34/A3/pYYBAGImrr-AF1e5AAG2QFBAh9w548.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
加入.h文件主要是方便配。cc936.c 用于支持中文。
3.2 修改diskio.c文件
![](https://file.elecfans.com//web2/M00/34/9C/poYBAGImrr-AG-sAAAIExJBbO88656.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
注釋掉現在不需要的用到的文件,因為我們現在用的是SD卡,與USB,ATA,MMC卡沒關系。
并加入一個新的宏 :
#define SD 0
定義SD卡的物理驅動器號為0。
修改 disk_status函數,該函數主要是用來獲取磁盤狀態。現在未用到,可以直接函數體內代碼刪除。
修改截圖:
![](https://file.elecfans.com//web2/M00/34/A3/pYYBAGImrsCAcNKGAAHxUpfS_s8234.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
代碼示例:
#include "diskio.h" /* fatf底層API */ #include "sd.h" /* SD卡驅動頭文件 */ /* 定義每個驅動器的物理驅動器號*/ #define SD 0
/*-----------------------------------------------------------------------*/ /* 獲取設備(磁盤)狀態 */ /*-----------------------------------------------------------------------*/
DSTATUS disk_status ( BYTE pdrv /* 物理驅動識別 */ ) { return 0; //該函數現在無需用到,直接返回0 } |
修改disk_initialize函數,添加SD卡的初始化,其他不用到的代碼直接刪掉,該函數成功返回0,失敗返回1。
修改截圖:
![](https://file.elecfans.com//web2/M00/34/9C/poYBAGImrsGAAnwfAAGPL0NgH6U138.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
代碼示例:
/*-----------------------------------------------------------------------*/ /* 初始化磁盤驅動 */ /*-----------------------------------------------------------------------*/
DSTATUS disk_initialize ( BYTE pdrv /* 物理驅動識別 */ ) { DSTATUS stat; int result;
switch (pdrv) { case SD : //選擇SD卡 stat=SD_Init(); //初始化SD卡-用戶自己提供 } if(stat)return STA_NOINIT; //磁盤未初始化 return 0; //初始化成功 } |
修改disk_read函數,加入SD卡讀任意扇區的函數(需要用戶自己提供),其他不用到的選項可以刪掉。
![](https://file.elecfans.com//web2/M00/34/A3/pYYBAGImrsGAbAC8AAGiifWu8vc631.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
修改代碼如下:
/*-----------------------------------------------------------------------*/ /* 讀扇區 */ /*-----------------------------------------------------------------------*/ DRESULT disk_read ( BYTE pdrv, /* 物理驅動編號 - 范圍0-9*/ BYTE *buff, /* 數據緩沖區存儲讀取數據 */ DWORD sector, /* 扇區地址*/ UINT count /* 需要讀取的扇區數*/ ) { DRESULT res; int result; switch (pdrv) { case SD: res=SD_Read_Data((u8*)buff,sector,count); //讀SD扇區函數--用戶提供 return res; //在此處可以判錯誤 } return RES_PARERR; //無效參數 } |
修改disk_write 函數,添加寫扇區函數:
![](https://file.elecfans.com//web2/M00/34/9C/poYBAGImrsKAJMk3AAGXoIzLkK4251.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
代碼:
/*-----------------------------------------------------------------------*/ /* 寫扇區 */ /*-----------------------------------------------------------------------*/
#if _USE_WRITE DRESULT disk_write ( BYTE pdrv, /* 物理驅動號*/ const BYTE *buff, /* 要寫入數據的首地址 */ DWORD sector, /* 扇區地址 */ UINT count /* 扇區數量*/ ) { DRESULT res; int result;
switch (pdrv) { case SD: res=SD_Write_Data((u8*)buff,sector,count); //寫入扇區 return res; } return RES_PARERR; //無效參數 } #endif |
修改disk_ioctl 函數,填充ioctl命令功能。這些功能是標準的命令,在diskio.h有定義。
![](https://file.elecfans.com//web2/M00/34/A3/pYYBAGImrsKAOWY4AAG7oDJupDo366.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
代碼如下:
/*-----------------------------------------------------------------------*/ /* 其他函數 */ /*-----------------------------------------------------------------------*/
#if _USE_IOCTL DRESULT disk_ioctl ( BYTE pdrv, /* 物理驅動號 */ BYTE cmd, /* 控制碼 */ void *buff /* 發送/接收數據緩沖區地址 */ ) { DRESULT res; int result;
switch (pdrv) { case SD: switch(cmd) { case CTRL_SYNC: //等待寫過程 SD_CS(0); //選中SD卡 if(SD_Wait_Ready())result = RES_ERROR;/*等待卡準備好*/ else res = RES_OK; //成功 SD_CS(1); //釋放SD卡 break;
case GET_SECTOR_SIZE://獲取扇區大小 *(DWORD*)buff = 512; res = RES_OK; //成功 break;
case GET_BLOCK_SIZE: //獲取塊大小 *(WORD*)buff = 8; //塊大小(扇區為單位),一塊等于8個扇區 res = RES_OK; break;
case GET_SECTOR_COUNT: //獲取總扇區數量 *(DWORD*)buff = SD_Get_Sector_Count(); res = RES_OK; break;
default: //命令錯誤 res = RES_PARERR; break; } return res; } return RES_PARERR; //返回狀態 } |
diskio.c 文件修改完整代碼:
/*-----------------------------------------------------------------------*/ /*低級別磁盤I / O模塊框架fatf(C)ChaN)2014 *存儲控制模塊fatf模塊定義了一個API。 */ /*-----------------------------------------------------------------------*/
#include "diskio.h" /* fatf底層API */ #include "sd.h" /* SD卡驅動頭文件 */
/* 定義每個驅動器的物理驅動器號*/ #define SD 0
/*-----------------------------------------------------------------------*/ /* 獲取設備(磁盤)狀態 */ /*-----------------------------------------------------------------------*/
DSTATUS disk_status ( BYTE pdrv /* 物理驅動識別 */ ) { return 0; //該函數現在無需用到,直接返回0 }
/*-----------------------------------------------------------------------*/ /* 初始化磁盤驅動 */ /*-----------------------------------------------------------------------*/
DSTATUS disk_initialize ( BYTE pdrv /* 物理驅動識別 */ ) { DSTATUS stat; int result;
switch (pdrv) { case SD : //選擇SD卡 stat=SD_Init(); //初始化SD卡-用戶自己提供 } if(stat)return STA_NOINIT; //磁盤未初始化 return 0; //初始化成功 }
/*-----------------------------------------------------------------------*/ /* 讀扇區 */ /*-----------------------------------------------------------------------*/
DRESULT disk_read ( BYTE pdrv, /* 物理驅動編號 - 范圍0-9*/ BYTE *buff, /* 數據緩沖區存儲讀取數據 */ DWORD sector, /* 扇區地址*/ UINT count /* 需要讀取的扇區數*/ ) { DRESULT res; int result;
switch (pdrv) { case SD: res=SD_Read_Data((u8*)buff,sector,count); //讀SD扇區函數--用戶提供 return res; //在此處可以判錯誤 } return RES_PARERR; //無效參數 }
/*-----------------------------------------------------------------------*/ /* 寫扇區 */ /*-----------------------------------------------------------------------*/
#if _USE_WRITE DRESULT disk_write ( BYTE pdrv, /* 物理驅動號*/ const BYTE *buff, /* 要寫入數據的首地址 */ DWORD sector, /* 扇區地址 */ UINT count /* 扇區數量*/ ) { DRESULT res; int result;
switch (pdrv) { case SD: res=SD_Write_Data((u8*)buff,sector,count); //寫入扇區 return res; } return RES_PARERR; //無效參數 } #endif
/*-----------------------------------------------------------------------*/ /* 其他函數 */ /*-----------------------------------------------------------------------*/
#if _USE_IOCTL DRESULT disk_ioctl ( BYTE pdrv, /* 物理驅動號 */ BYTE cmd, /* 控制碼 */ void *buff /* 發送/接收數據緩沖區地址 */ ) { DRESULT res; int result;
switch (pdrv) { case SD: switch(cmd) { case CTRL_SYNC: //等待寫過程 SD_CS(0); //選中SD卡 if(SD_Wait_Ready())result = RES_ERROR;/*等待卡準備好*/ else res = RES_OK; //成功 SD_CS(1); //釋放SD卡 break;
case GET_SECTOR_SIZE://獲取扇區大小 *(DWORD*)buff = 512; res = RES_OK; //成功 break;
case GET_BLOCK_SIZE: //獲取塊大小 *(WORD*)buff = 8; //塊大小--一塊等于8個扇區 res = RES_OK; break;
case GET_SECTOR_COUNT: //獲取總扇區數量 *(DWORD*)buff = SD_Get_Sector_Count(); res = RES_OK; break;
default: //命令錯誤 res = RES_PARERR; break; } return res; } return RES_PARERR; //返回狀態 } #endif
//返回FATFS時間 //獲得時間 DWORD get_fattime (void) { return (DWORD)(2017-1980)<<25|??? //年 7<<21|??? //月 27<<16|??? //日 12<<11|??? //時 13<<5|??? //分 14; //秒 }
/* Return Value Currnet local time is returned with packed into a DWORD value. The bit field is as follows: bit31:25 Year origin from the 1980 (0..127) bit24:21 Month (1..12) bit20:16 Day of the month(1..31) bit15:11 Hour (0..23) bit10:5 Minute (0..59) bit4:0 Second / 2 (0..29) */ |
3.3修改ffconf.h文件
需要注意的一些宏配置:
#define _CODE_PAGE 936 //采用中文GBK編碼 (64行)
#define _USE_LFN 3 //動態的堆上工作 (93行)
#define _MAX_LFN 255 /*_USE_LFN選項開關LFN(長文件名)特性。
#define _VOLUMES 1 /* 支持的磁盤數量(邏輯驅動器)。 */ (142行)
#define _MIN_SS 512 (165行)
#define _MAX_SS 512 /*這些選項配置支持扇區大小的范圍。(512,1024, 4096*/
#define _FS_NORTC 0 /*啟用RTC時間功能*/ (202行)
#define _NORTC_MON 1
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2015 //年
/*需要實現:get_fattime()函數*/
ffconf.h 文件源碼(講解):
/*---------------------------------------------------------------------------/ / FatFs - FAT文件系統模塊配置文件 R0.11a (C)ChaN, 2015 /---------------------------------------------------------------------------*/
#define _FFCONF 64180 /* 版本識別*/
/*---------------------------------------------------------------------------/ / 功能配置 /---------------------------------------------------------------------------*/
#define _FS_READONLY 0 /* 這個選項開關只讀配置。(0:讀/寫或1:只讀) /只讀配置刪除編寫API函數,f_write(),f_sync(), / f_unlink(),f_mkdir(),f_chmod(),f_rename(),f_truncate(),f_getfree() /寫和可選的功能. */
#define _FS_MINIMIZE 0 /*此選項定義刪除一些基本的API函數極小化水平。 / / 0:所有基本功能都是激活的。 / 1:f_stat(),f_getfree(),f_unlink(),f_mkdir(),f_chmod(),f_utime(), / f_truncate()和f_rename()函數刪除。 / 2:f_opendir(),f_readdir()和f_closedir()中除了1。 / 3:f_lseek()函數刪除除了2。*/
#define _USE_STRFUNC 1 /*這個選項開關字符串函數,f_gets(),f_putc(),f_puts()和 / f_printf()。 / / 0:禁用字符串函數。 / 1:啟用沒有LF-CRLF轉換。 / 2:啟用LF-CRLF(回車換行)轉換。*/
#define _USE_FIND 0 /*這個選項開關過濾目錄讀取特性和相關功能, / f_findfirst()和f_findnext()。(0:禁用或1:啟用)*/
#define _USE_MKFS 1 /* 這個選項開關f_mkfs()函數。(0:禁用或1:啟用) */
#define _USE_FASTSEEK 1 /* 這個選項開關快速尋求功能。(0:禁用或1:啟用) */
#define _USE_LABEL 1 /* 磁盤卷標這個選項開關功能,f_getlabel()和f_setlabel()。 /(0:禁用或1:啟用) */
#define _USE_FORWARD 0 /* 這個選項開關f_forward()函數。(0:禁用或1:啟用) /啟用它,也_FS_TINY需要設置為1. */
/*---------------------------------------------------------------------------/ / 語言環境和名稱空間配置 /---------------------------------------------------------------------------*/
#define _CODE_PAGE 936 //采用中文GBK編碼 /*這個選項指定OEM代碼頁在目標系統上使用。 /不正確的代碼頁的設置會導致文件打開失敗. / / 1 - ASCII (沒有擴展字符。Non-LFN cfg。只有) / 437 - U.S. / 720 - 阿拉伯語 / 737 - 希臘語; / 771 - 阿富汗 / 775 - 波羅的海 / 850 - 拉丁1 / 852 - 拉丁2 / 855 - 西里爾字母 / 857 - 土耳其語 / 860 - 葡萄牙語 / 861 - 冰島語 / 862 - 希伯來人 / 863 - 加拿大法語 / 864 - 阿拉伯語 / 865 - 日耳曼民族的 / 866 - 俄語 / 869 - 希臘 2 / 932 - 日本人 (DBCS) / 936 - 簡體中文(DBCS) / 949 - 韓國人 (DBCS) / 950 - 繁體中文(DBCS) */
#define _USE_LFN 3 //動態的堆上工作 #define _MAX_LFN 255 /*_USE_LFN選項開關LFN(長文件名)特性。 / / 0:禁用LFN特性。_MAX_LFN沒有影響。 / 1:啟用LFN BSS靜態工作緩沖區。總是不是線程安全的。 / 2:啟用LFN與動態緩沖棧上的工作。 / 3:使LFN與動態緩沖區在堆上工作。 / / 當啟用LFN(長文件名)特性,Unicode(選項/ unicode.c)必須處理功能 /被添加到項目中。LFN工作緩沖區占用(_MAX_LFN + 1)* 2字節。 /當使用堆棧緩沖區,照顧堆棧溢出。當使用堆 /工作緩沖區內存,內存管理功能,ff_memalloc()和 / ff_memfree(),必須添加到項目中。 */
#define _LFN_UNICODE 0 /* 這個選項開關字符編碼的API。(0:ANSI / OEM或1:Unicode) 路徑名/使用Unicode字符串,并設置_LFN_UNICODE啟用LFN特性 /1。這個選項也會影響行為的字符串的I / O功能。 */
#define _STRF_ENCODE 3 /* 當_LFN(長文件名)_UNICODE是1,這個選項選擇文件的字符編碼 /通過字符串讀取/寫入I /O功能,f_gets(),f_putc(),f_puts和f_printf(). / / 0: ANSI/OEM / 1: UTF-16LE / 2: UTF-16BE / 3: UTF-8 / / 當_LFN_UNICODE = 0時,該選項沒有影響。*/
#define _FS_RPATH 0 /*這個選項配置相對路徑的功能。/ / 0:禁用相對路徑特性和刪除相關功能。 / 1:啟用相對路徑特性。f_chdir()和f_chdrive()是可用的。 / 2:f_getcwd()函數可用除了1。/ /注意,目錄項讀通過f_readdir()這個選項。 */
/*---------------------------------------------------------------------------/ / 驅動/卷配置 /---------------------------------------------------------------------------*/
#define _VOLUMES 1 /* 支持的磁盤數量(邏輯驅動器)。 */
#define _STR_VOLUME_ID 0 #define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" /* STR_VOLUME_ID選項開關卷ID字符串功能。 /當_STR_VOLUME_ID設置為1時,也可以使用預先定義的字符串在路徑名稱/數量。 為每個_VOLUME_STRS定義驅動ID字符串 /邏輯驅動器。條目的數量必須等于_VOLUMES。有效字符 /驅動ID字符串:a - z和0 - 9。*/
#define _MULTI_PARTITION 0 /* 這個選項開關多分區的特性。在默認情況下(0),每個邏輯驅動器 /號綁定到相同的物理驅動器號 /物理驅動器將被安裝。當啟用分區特性(1), /每個邏輯驅動器號是綁定到任意物理驅動器和分區 /中列出VolToPart[]。還f_fdisk()函數可用. */
#define _MIN_SS 512 #define _MAX_SS 512 /* 這些選項配置支持扇區大小的范圍。(512,1024, / 2048或4096)總是為大多數系統設置兩個512,卡和所有類型的內存 /硬盤。但是可能需要更大的值為車載閃存和一些 /類型的光學媒體。當_MAX_SS大于_MIN_SS,fatf配置 /變量扇區大小和GET_SECTOR_SIZE命令必須執行disk_ioctl()函數. */
#define _USE_TRIM 0 /* 這個選項開關ATA-TRIM特性。(0:禁用或1:啟用) /啟用削減特性,也應該實現CTRL_TRIM命令 / disk_ioctl()函數。*/
#define _FS_NOFSINFO 0 /* 如果你需要知道正確的自由空間體積FAT32,設置一些0 /選項,f_getfree()函數在第一次后體積將迫使山 /全脂肪掃描。位1控制使用的集群數量分配。/ / bit0 = 0:使用免費的集群計算FSINFO如果可用。 / bit0 = 1:不相信自由FSINFO集群計算。 / bit1 = 0:最后使用集群可用FSINFO如果數量分配。 / bit1 = 1:不相信最后分配FSINFO集群數量. */
/*---------------------------------------------------------------------------/ / 系統配置列表 /---------------------------------------------------------------------------*/
#define _FS_TINY 0 /* 這個選項開關小緩沖區配置。(0:正常或1:小) /小配置,文件對象的大小(FIL)_MAX_SS減少字節。而不是私人部門從文件對象,緩沖了 /公共部門緩沖文件系統中的對象(fatf)是用于該文件 /數據傳輸. */
#define _FS_NORTC 0 #define _NORTC_MON 1 #define _NORTC_MDAY 1 #define _NORTC_YEAR 2015 //年 /* _FS_NORTC選項開關時間戳的特性。如果系統沒有/ RTC函數或不需要有效的時間戳,_FS_NORTC 1設置為禁用/ 時間戳的特性。所有對象修改fatf將有一個固定的時間戳。/ 固定的時間定義為_NORTC_MON _NORTC_MDAY _NORTC_YEAR。
/當啟用時間戳特性(_FS_NORTC = = 0),需要實現get_fattime()函數。/ 添加到項目RTC讀當前時間形式。_NORTC_MON, / _NORTC_MDAY和_NORTC_YEAR沒有效果。 /這些選項沒有影響只讀配置(_FS_READONLY = = 1)。 */
#define _FS_LOCK 0 /* _FS_LOCK選項開關控制復制的文件打開的文件鎖定功能 /和非法操作打開對象。這個選項_FS_READONLY時必須是0 /是1。/ / 0:禁用文件鎖定功能。為了避免體積腐敗、應用程序 /應該避免非法打開,刪除和重命名的開放對象。 / > 0:啟用文件鎖定功能。值定義了多少文件/子目錄 可以同時打開的/文件鎖的控制之下。注意,這個文件獨立于re-entrancy /鎖功能。 */
#define _FS_REENTRANT 0 #define _FS_TIMEOUT 1000 #define _SYNC_t HANDLE /* _FS_REENTRANT選項開關re-entrancy fatf的(線程安全) /模塊本身。注意,不管這個選項,文件訪問不同 /體積始終是凹角和音量控制功能,f_mount(),f_mkfs() /和f_fdisk()函數,總是不凹角。只有文件/目錄的訪問 /相同的體積是這個功能的控制。 / / 0:禁用re-entrancy。_FS_TIMEOUT和_SYNC_t沒有效果。 / 1:啟用re-entrancy。還提供用戶同步處理程序, / ff_req_grant(),ff_rel_grant(),ff_del_syncobj()和ff_cre_syncobj() /函數,必須添加到項目中。樣品中可用 /選項 / syscall.c。 / / _FS_TIMEOUT定義超時時間單位的滴答聲。 / _SYNC_t定義了O / S依賴同步對象類型。例如處理、ID、OS_EVENT * / SemaphoreHandle_t等. .O / S的頭文件定義需要 /包括在ff.c的范圍。 */
#define _WORD_ACCESS 0 /* _WORD_ACCESS選項是一個只有依賴于平臺的選擇。 它定義了這個詞/訪問方法是用來體積上的數據。 / / 0:逐字節的訪問。總是兼容所有平臺。 / 1:詞的訪問。不要選擇這個,除非在下列條件。 / / *地址對齊內存訪問總是允許所有指令。 / *字節順序的記憶是低位優先。 / /如果是這樣的情況,_WORD_ACCESS也可以減少代碼的大小設置為1。 /下表顯示允許設置某種類型的處理器。 / / ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2 / Cortex-M3 0 *3 Z80 0/1 V850ES 0/1 / Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1 / AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 / AVR32 0 *1 RL78 0 *2 R32C 0 *2 / PIC18 0/1 SH-2 0 *1 M16C 0/1 / PIC24 0 *2 H8S 0 *1 MSP430 0 *2 / PIC32 0 *1 H8/300H 0 *1 8051 0/1 / / * 1:高位優先。/ * 2:不支持不連續的內存訪問。/ * 3:一些編譯器生成LDM(邏輯磁盤管理器 ) / STM mem_cpy(內存拷貝)函數。 */ |
3.4實現動態內存分配函數與時間函數
ff.h文件有動態內存的釋放,動態內存申請,時間獲取函數接口。
![](https://file.elecfans.com//web2/M00/34/9C/poYBAGImrsKAOP9_AAGoqzEkXv4293.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
在diskio.c文件實現函數功能:
![](https://file.elecfans.com//web2/M00/34/A3/pYYBAGImrsOAJF2oAAGoypmPht4607.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
代碼實現如下:
//動態內存分配 void* ff_memalloc (UINT msize) /* 分配內存塊 */ { return (void*)malloc(msize); //分配空間 }
//動態內存釋放 void ff_memfree (void* mblock) /* 空閑內存塊 */ { free(mblock); //釋放空間 }
//返回FATFS時間 //獲得時間 DWORD get_fattime (void) { //Get_RTC_Timer(); //獲取一次RTC時間 return (RTC_Timer.year-1980)<<25|?? //年 RTC_Timer.month<<21|? //月 RTC_Timer.day<<16|??? //日 RTC_Timer.hour<<11|?? //時 RTC_Timer.minute<<5|? //分 RTC_Timer.sec; //秒 }
/* Return Value Currnet local time is returned with packed into a DWORD value. The bit field is as follows: bit31:25 Year origin from the 1980 (0..127) bit24:21 Month (1..12) bit20:16 Day of the month(1..31) bit15:11 Hour (0..23) bit10:5 Minute (0..59) bit4:0 Second / 2 (0..29) */ |
3.5 修改堆棧空間
完成了上述的修改,還需要修改堆棧空間,因為長文件支持需要占用堆空間。
修改STM32啟動文件如下:
![](https://file.elecfans.com//web2/M00/34/9C/poYBAGImrsOAIYzlAAEmuJfM9nw707.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70)
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](http://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
?
3.6編譯工程測試
修改完畢之后,給開發板插上SD卡,調用API函數在SD卡創建一個文件,并寫入數據,測試是否成功:
#include "ff.h" FATFS fs; // 用戶定義的文件系統結構體 FIL file; // 用戶定義的文件系統結構體 u8 buff[]="123 知識!!"; int main(void) { u32 data; //檢測SD卡容量 u8 i,res; LED_Init(); //LED燈初始化 Delay_Init(); KEY_Init(); USART1_Init(72,115200); USART2_Init(36,115200); FLASH_Init(); Set_Font_addr(); //字庫地址初始化 FSMC_SRAM_Init(); LCD_Init(); RTC_Init(); //RTC時鐘初始化 while(SD_Init()) //檢測不到SD卡,SD相關硬件初始化 { i=!i; LCD_ShowString(60,150,200,16,16,"SD Card Error! Please Check SD Card!!",0xf800); Delay_ms(500); LED1(i)//DS0閃爍 }
f_mount(&fs,"0",1); // 注冊工作區,驅動器號 0,初始化后其他函數可使用里面的參數 printf("注冊工作區!\n");
if(f_mkfs("0",0,4096)) //格式化SD卡 { printf("格式化失敗!!\n"); } else { printf("格式化成功!!\n"); } res = f_open(&file, "/file.c", FA_OPEN_ALWAYS | FA_READ | FA_WRITE); if(res==0) { printf("文件創建成功!!\n"); } else { printf("文件創建失敗!!\n"); } res =f_write(&file,buff,strlen((const char*)buff),&data); if(res==0) { printf("數據寫入成功!!\n"); } else { printf("數據寫入失敗!!\n"); } printf("成功寫入%d字節數據\n",data); f_close(&file); //關閉文件 //_FS_RPATH
while(1) { Delay_ms(1000); LED1(1); Delay_ms(500); LED1(0); } } |
?
-
STM32
+關注
關注
2272文章
10925瀏覽量
357637 -
SPI
+關注
關注
17文章
1724瀏覽量
92147 -
FATFS
+關注
關注
0文章
44瀏覽量
18387 -
keil5
+關注
關注
6文章
45瀏覽量
20738 -
系統移植
+關注
關注
0文章
16瀏覽量
4840
發布評論請先 登錄
相關推薦
STM32CubeMx入門教程(10):Fatfs文件系統的應用
![<b class='flag-5'>STM32</b>CubeMx入門教程(10):<b class='flag-5'>Fatfs</b><b class='flag-5'>文件系統</b>的應用](https://file1.elecfans.com/web2/M00/8C/8C/wKgZomSuIAuAZTmqAAEd9wepNl0753.jpg)
FATFS文件系統如何移植工程
【技術精選】嵌入式STM32原創征文活動精選文章
MSP430、STM32、8051單片機fatfs 文件系統移植 W25Q128
![MSP430、<b class='flag-5'>STM32</b>、8051單片機<b class='flag-5'>fatfs</b> <b class='flag-5'>文件系統</b><b class='flag-5'>移植</b> W25Q128](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
手把手教你在flash上移植fatfs文件系統(含實時操作系統)
![手把手教你在flash上<b class='flag-5'>移植</b><b class='flag-5'>fatfs</b><b class='flag-5'>文件系統</b>(含實時操作<b class='flag-5'>系統</b>)](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
文件系統FatFs的移植
![<b class='flag-5'>文件系統</b><b class='flag-5'>FatFs</b>的<b class='flag-5'>移植</b>](https://file.elecfans.com/web2/M00/8B/E4/poYBAGPY5VeABIapAABj_H1EbK8460.jpg)
評論