基于SD卡的FatFs文件系统(FatFs移植到STM32)
平臺:STM32ZET6(核心板)+ST-LINK/V2+SD卡+USB串口線
工程介紹:主要文件在USER組中,bsp_sdio_sdcard.c,bsp_sdio_sdcard.h和main.c,另外FatFs是用來后面移植文件系統使用的,對于本節內容暫時不需要。bsp_sdio_sdcard.c和bsp_sdio_sdcard.h文件主要參考教材《STM32庫開發實戰指南——基于STM32F03》。另外就是本教材用到的FatFs系統源代碼,這里溫馨提示一下,關于FatFs目前網上筆者找到的最新版的參考資料不是太多,所以筆者在用最新版做的時候,一些函數原型發生了變化,雖然變化不大,也給我造成了一定的阻礙,所以建議大家下載稍微老一點的版本,這樣資料較多,出問題好解決,我最終用的版本是R0.09,因為在使用函數f_mkfs()的過程中遇到問題,無法格式化SD卡,最終選擇較老的版本。本文有些內容來自于其他網友總結,在此表示感謝。
整體的項目和上一節中的SDIO讀寫SD卡類似,細節上在添加了FatFs組,專門存放FatFs移植的內容。對于移植過程,就是對diskio.c文件的修改的過程。這個文件完成了與底層有多的操作,我們只需要實現一下函數即可,不同的平臺函數實現略有不同,但是提供給用戶最終的接口是相同的,也正是因為這一點,使得FatFs文件系統有了很好的可移植性。
再次申明一下,FatFs文件系統與存儲設備的接口函數再diskio.c文件中,我們只需要完善該文件即可。這也就是所謂的軟件移植裁剪過程吧。我們需要完善五個函數disk_status,disk_initialize,disk_read,disk_write,disk_ioctl等,還有一個獲取時間戳的函數,可以直接return 0;
1.宏定義
#define SD_CARD?? ? 0 ?//SD卡,卷標為0
#define EX_FLASH 1?? ?//外部flash,卷標為1,為以后外部Flash擴展預留的
?
#define SD_BLOCKSIZE 512
?
//聲明外部變量
extern SD_CardInfo SDCardInfo;
2.dis_status 獲取磁盤的狀態
//獲得磁盤狀態
DSTATUS disk_status (
?? ?BYTE pdrv?? ??? ?/* Physical drive nmuber to identify the drive */
)
{
?? ?DSTATUS status = STA_NOINIT;
?? ?switch(pdrv)
?? ?{
?? ??? ?case SD_CARD://SD卡
?? ??? ??? ?status &= ~STA_NOINIT;
? ?? ??? ?break;
?? ??? ?case EX_FLASH://外部flash
??? ??? ??? ?break;
?? ??? ?default:
?? ??? ??? ?status = STA_NOINIT;
?? ??? ??? ?break;
?? ?}
?? ?return status;
} ?
3. disk_initialize 初始化磁盤,當遇到無法掛載SD卡,或者其他問題時,優先檢查該函數,該函數會調用SD_Init函數,需要檢查
SD_Init函數的返回結果是否為SD_OK。
//初始化磁盤
DSTATUS disk_initialize (
?? ?BYTE pdrv?? ??? ??? ??? ?/* Physical drive nmuber to identify the drive */
)
{
?? ?DSTATUS status = STA_NOINIT;
?? ?switch(pdrv)
?? ?{
?? ??? ?case SD_CARD://SD卡
?? ??? ??? ?if(SD_OK == SD_Init())//SD卡初始化?
?? ??? ??? ?{
?? ??? ??? ??? ?status &= ~STA_NOINIT;
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ?{
?? ??? ??? ??? ?status = STA_NOINIT;
?? ??? ??? ?}
? ?? ??? ?break;
?? ??? ?case EX_FLASH://外部flash
??? ??? ??? ?break;
?? ??? ?default:
?? ??? ??? ?status = STA_NOINIT;
?? ??? ??? ?break;
?? ?}
?? ?return status;
}?
4. disk_read 讀取SD卡
//讀扇區
//pdrv:磁盤編號0~9
//*buff:數據接收緩沖首地址
//sector:扇區地址
//count:需要讀取的扇區數
DRESULT disk_read (
?? ?BYTE pdrv,?? ??? ?/* Physical drive nmuber to identify the drive */
?? ?BYTE *buff,?? ??? ?/* Data buffer to store read data */
?? ?DWORD sector,?? ?/* Sector address in LBA */
?? ?UINT count?? ??? ?/* Number of sectors to read */
)
{
?? ?DRESULT status = RES_PARERR;
?? ?SD_Error SD_Status = SD_OK;
?? ?
?? ?switch(pdrv)
?? ?{
?? ??? ?case SD_CARD://SD卡
?? ??? ??? ?if((DWORD)buff & 3)
?? ??? ??? ?{
?? ??? ??? ??? ?DRESULT res = RES_OK;
?? ??? ??? ??? ?DWORD scratch[SD_BLOCKSIZE / 4];
?? ??? ??? ??? ?
?? ??? ??? ??? ?while(count--)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?res = disk_read(SD_CARD, (void*)scratch, sector++, 1);
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?if(res != RES_OK)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?memcpy(buff, scratch, SD_BLOCKSIZE);
?? ??? ??? ??? ??? ?buff += SD_BLOCKSIZE;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?return res;
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ??? ?SD_Status = SD_ReadMultiBlocks(buff, sector*SD_BLOCKSIZE,SD_BLOCKSIZE,count);
?? ??? ??? ?
?? ??? ??? ?if(SD_Status == SD_OK)
?? ??? ??? ?{
?? ??? ??? ??? ?//檢查傳輸是否完成
?? ??? ??? ??? ?SD_Status = SD_WaitReadOperation();
?? ??? ??? ??? ?while(SD_GetStatus() != SD_TRANSFER_OK);
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ??? ?if(SD_Status != SD_OK)
?? ??? ??? ?{
?? ??? ??? ??? ?status = RES_PARERR;
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ?{
?? ??? ??? ??? ?status = RES_OK;
?? ??? ??? ?}
? ?? ??? ?break;
?? ??? ?case EX_FLASH://外部flash
??? ??? ??? ?break;
?? ??? ?default:
?? ??? ??? ?status = RES_PARERR;
?? ??? ??? ?break;
?? ?}
?? ?return status;
}
5.disk_write 寫數據到SD卡
//寫扇區
//pdrv:磁盤編號0~9
//*buff:發送數據首地址
//sector:扇區地址
//count:需要寫入的扇區數
#if _USE_WRITE
DRESULT disk_write (
?? ?BYTE pdrv,?? ??? ??? ?/* Physical drive nmuber to identify the drive */
?? ?const BYTE *buff,?? ?/* Data to be written */
?? ?DWORD sector,?? ??? ?/* Sector address in LBA */
?? ?UINT count?? ??? ??? ?/* Number of sectors to write */
)
{
?? ?DRESULT status = RES_PARERR;
?? ?SD_Error SD_Status = SD_OK;
?? ?
?? ?//檢查參數
?? ?if(!count)
?? ?{
?? ??? ?return RES_PARERR;
?? ?}
?? ?
?? ?switch(pdrv)
?? ?{
?? ??? ?case SD_CARD://SD卡
?? ??? ??? ?if((DWORD)buff & 3)
?? ??? ??? ?{
?? ??? ??? ??? ?DRESULT res = RES_OK;
?? ??? ??? ??? ?DWORD scratch[SD_BLOCKSIZE / 4];
?? ??? ??? ??? ?
?? ??? ??? ??? ?while(count--)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?memcpy(scratch, buff, SD_BLOCKSIZE);
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?res = disk_write(SD_CARD, (void*)scratch, sector++, 1);
?? ??? ??? ??? ??? ?if(res != RES_OK)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?buff += SD_BLOCKSIZE;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?return res;
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ??? ?SD_Status = SD_WriteMultiBlocks((uint8_t *)buff, sector*SD_BLOCKSIZE,SD_BLOCKSIZE,count);
?? ??? ??? ?
?? ??? ??? ?if(SD_Status == SD_OK)
?? ??? ??? ?{
?? ??? ??? ??? ?//檢查傳輸是否完成
?? ??? ??? ??? ?SD_Status = SD_WaitReadOperation();
?? ??? ??? ??? ?while(SD_GetStatus() != SD_TRANSFER_OK);
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ??? ?if(SD_Status != SD_OK)
?? ??? ??? ?{
?? ??? ??? ??? ?status = RES_PARERR;
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ?{
?? ??? ??? ??? ?status = RES_OK;
?? ??? ??? ?}
? ?? ??? ?break;
?? ??? ?case EX_FLASH://外部flash
??? ??? ??? ?break;
?? ??? ?default:
?? ??? ??? ?status = RES_PARERR;
?? ??? ??? ?break;
?? ?}
?? ?return status;
}
6.disk_ioctl 函數,獲取SD卡的某些參數,如塊大小等。
//其他表參數的獲得
//pdrv:磁盤編號0~9
//ctrl:控制代碼
//*buff:發送/接收緩沖區指針
#if _USE_IOCTL
DRESULT disk_ioctl (
?? ?BYTE pdrv,?? ??? ?/* Physical drive nmuber (0..) */
?? ?BYTE cmd,?? ??? ?/* Control code */
?? ?void *buff?? ??? ?/* Buffer to send/receive control data */
)
{
?? ?DRESULT res = RES_ERROR;?? ??? ??? ??? ??? ??? ? ??? ??? ??? ? ? ??
?? ?switch(pdrv)//SD卡
?? ?{
?? ??? ?case SD_CARD:
?? ? ? ?switch(cmd)
?? ? ? ?{
?? ??? ? ? ?case GET_SECTOR_SIZE:
?? ??? ??? ??? ??? ?*(WORD*)buff = SD_BLOCKSIZE;?
?? ??? ? ? ? ?break;?? ??
?? ??? ? ? ?case GET_BLOCK_SIZE:
?? ??? ??? ??? ??? ?*(DWORD*)buff = SDCardInfo.CardBlockSize;
?? ??? ? ? ? ?break;?? ??
?? ??? ? ? ?case GET_SECTOR_COUNT:
?? ??? ? ? ? ?*(DWORD*)buff = SDCardInfo.CardCapacity / SD_BLOCKSIZE;
?? ??? ? ? ? ?break;
?? ??? ? ? ?case CTRL_SYNC:
?? ??? ? ? ? ?break;
?? ? ? ?}
?? ??? ? ?res = RES_OK;
?? ??? ??? ?break;
?? ??? ?case EX_FLASH://外部flash
??? ??? ??? ?break;
?? ??? ?default:
?? ??? ??? ?res = RES_PARERR;
?? ??? ??? ?break;
?? ?}
? return res;
}
7.get_fattime函數,獲取時間戳。沒有實現。
//獲得時間 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
DWORD get_fattime (void)
{
?? ?//返回當前時間戳
?? ?return 0;
}
8.另外需要修改ffconf.h文件,另外注意,新版本的該文件都會在宏的前面加上FF前綴,例如對于_USE_LEN,新版本的可能是
FF_USE_LLEN,本節的內容都是按照舊版本來說的,因此宏沒有以FF為前綴。
#define _USE_LEN 2 ?//長文件名支持,默認不支持長文件名
#define _USE_MKFS 1 ?//格式化功能選擇,使能FatFs的格式化功能
#define _CODE_PAGE 936 ?//語言功能選擇,需要同時把語言文件添加到工程中,為支持簡體中文,我們需要添加cc963.c文件
#define _VOLUMES 2 ?//物理設備數量,這里設置為2,包括SD卡和預留的外部Flash芯片
#define _MIN_SS 512 ? //指定扇區大小的最小值
#define _MAX_SS 4096 ?//指定扇區大小的最大值
以上就完成了FatFs的移植過程,接下來是對功能的測試,直接上代碼了。
測試:
//FAT功能測試:格式化測試,文件寫入測試,文件讀取測試(基本功能)
FATFS fs; //FatFs文件系統對象
FIL fnew; //文件對象
FRESULT res_sd;//文件操作結果
UINT fnum; //文件成功讀寫數量
BYTE ReadBuffer[1024] = {0};
BYTE WriteBuffer[] = "成功移植了FatFs文件系統!\r\n"; //寫緩存區
main 主函數,包含格式化測試和文件讀寫測試。
int main()
{
?? ?//串口配置
?? ?USART_Config();
?? ?
?? ?//初始化LED
?? ?LED_GPIO_Config();
?? ?
?? ?//初始化SD卡
?? ?if(SD_Init() == SD_OK)
?? ?{
?? ??? ?printf("SD卡初始化成功,即將掛載SD卡。\r\n");
?? ?}
?? ?
?? ?//掛載SD卡
?? ?res_sd = f_mount(&fs, "0:", 1);
?? ?
?? ?//***********************格式化測試****************************
?? ?if(res_sd == FR_NO_FILESYSTEM)
?? ?{
?? ??? ?printf("SD卡沒有文件系統,即將進行格式化...\r\n");
?? ??? ?//格式化
?? ??? ?res_sd = f_mkfs("0:", 0, 0);
?? ??? ?
?? ??? ?if(res_sd == FR_OK)
?? ??? ?{
?? ??? ??? ?printf("SD卡成功格式化!\r\n");
?? ??? ??? ?//格式化后先取消掛載
?? ??? ??? ?res_sd = f_mount(NULL, "0:", 1);
?? ??? ??? ?//再重新掛載
?? ??? ??? ?res_sd = f_mount(&fs, "0:", 1);
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?printf("文件格式化失敗!錯誤代碼:%d\r\n",res_sd);
?? ??? ??? ?while(1);
?? ??? ?}
?? ?}
?? ?else if(res_sd != FR_OK)
?? ?{
?? ??? ?printf("掛載文件系統失敗!可能是因為文件初始化失敗!錯誤代碼:%d\r\n", res_sd);
?? ?}
?? ?else
?? ?{
?? ??? ?printf("文件系統掛載成功, 可進行讀寫測試!\r\n");
?? ?}
?? ?
?? ?//***********************寫測試****************************
?? ?//打開文件,如果文件不存在則創建它
?? ?printf("即將進行文件寫入測試....\r\n");
?? ?//打開文件,若不存在就創建
?? ?res_sd = f_open(&fnew, "0:FatFs讀寫測試文件.txt", FA_CREATE_ALWAYS | FA_WRITE);
?? ?//文件打開成功
?? ?if(res_sd == FR_OK)
?? ?{
?? ??? ?printf("打開文件成功!開始寫入數據!\r\n");
?? ??? ?res_sd= f_write(&fnew, WriteBuffer, sizeof(WriteBuffer), &fnum);
?? ??? ?
?? ??? ?if(res_sd == FR_OK)
?? ??? ?{
?? ??? ??? ?printf("數據寫入成功!\r\n");
?? ??? ??? ?printf("數據:%s。共寫入%d個字符\r\n", WriteBuffer, fnum);
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?printf("數據寫入失敗!\r\n");
?? ??? ?}
?? ??? ?
?? ??? ?//關閉文件
?? ??? ?f_close(&fnew);
?? ?}
?? ?
?? ?//***********************讀測試****************************
?? ?//打開文件,如果文件不存在則創建它
?? ?printf("即將進行文件讀取測試....\r\n");
?? ?//打開文件,若不存在就創建
?? ?res_sd = f_open(&fnew, "0:FatFs讀寫測試文件.txt", FA_OPEN_EXISTING | FA_READ);
?? ?//文件打開成功
?? ?if(res_sd == FR_OK)
?? ?{
?? ??? ?printf("打開文件成功!開始讀取數據!\r\n");
?? ??? ?res_sd= f_read(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
?? ??? ?
?? ??? ?if(res_sd == FR_OK)
?? ??? ?{
?? ??? ??? ?printf("數據讀取成功!\r\n");
?? ??? ??? ?printf("數據:%s\r\n", ReadBuffer);
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?printf("數據讀取失敗!\r\n");
?? ??? ?}
?? ??? ?
?? ??? ?//關閉文件
?? ??? ?f_close(&fnew);
?? ?}
?? ?
?? ?scan_files("FatFs讀寫測試文件.txt");
?? ?
?? ?//其他功能測試
?? ?file_check();
?? ?
?? ?//多項功能測試
?? ?miscellaneous();
?? ?
?? ?//取消掛載文件系統
?? ?f_mount(NULL, "0:", 1);
?? ?
?? ?while(1);
}
補充,如有需要可以借鑒,其他功能測試。
//多項功能測試
static FRESULT miscellaneous()
{
?? ?DIR dir;
?? ?FATFS *pfs;
?? ?DWORD fre_clust, fre_sect, tot_sect;
?? ?
?? ?printf("\r\n*************************設備信息獲取***************************\r\n");
?? ?//獲取設備信息和空簇大小
?? ?res_sd = f_getfree("0:", &fre_clust, &pfs);
?? ?
?? ?//計算得到總的扇區個數和空扇區個數
?? ?tot_sect = (pfs->n_fatent - 2) * pfs->csize;
?? ?fre_sect = fre_clust * pfs->csize;
?? ?
?? ?printf("設備總空間:%10lu KB\r\n可用空間:%10lu KB。\r\n", tot_sect*4, fre_sect*4);
?? ?
?? ?printf("\r\n*************************文件定位和格式化寫入功能測試***************************\r\n");
?? ?//打開文件,若不存在就創建
?? ?res_sd = f_open(&fnew, "0:FatFs多項功能測試文件.txt", FA_CREATE_ALWAYS | FA_WRITE | FA_READ);
?? ?//文件打開成功
?? ?if(res_sd == FR_OK)
?? ?{
?? ??? ?printf("打開文件成功!開始讀取數據!\r\n");
?? ??? ?res_sd= f_write(&fnew, WriteBuffer, sizeof(WriteBuffer), &fnum);
?? ??? ?
?? ??? ?if(res_sd == FR_OK)
?? ??? ?{
?? ??? ??? ?printf("數據寫入成功!\r\n");
?? ??? ??? ?printf("數據:%s\r\n", WriteBuffer);
?? ??? ??? ?//文件定位,定位到文件末尾,f_size獲取文件大小
?? ??? ??? ?res_sd = f_lseek(&fnew, f_size(&fnew) - 1);
?? ??? ??? ?if(res_sd == FR_OK)
?? ??? ??? ?{
?? ??? ??? ??? ?//在原文件中追加一行內容
?? ??? ??? ??? ?f_printf(&fnew, "在原文件中追加一行內容。\n");
?? ??? ??? ??? ?f_printf(&fnew, "設備總空間:%10lu KB\r\n可用空間:%10lu KB。\r\n", tot_sect*4, fre_sect*4);
?? ??? ??? ??? ?
?? ??? ??? ??? ?//文件定位到起始位置
?? ??? ??? ??? ?res_sd = f_lseek(&fnew, 0);
?? ??? ??? ??? ?
?? ??? ??? ??? ?if(res_sd == FR_OK)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?//打開文件,若不存在就創建
?? ??? ??? ??? ??? ?res_sd = f_open(&fnew, "0:FatFs多項功能測試文件.txt", FA_OPEN_EXISTING | FA_READ);
?? ??? ??? ??? ??? ?//文件打開成功
?? ??? ??? ??? ??? ?if(res_sd == FR_OK)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?printf("打開文件成功!開始讀取數據!\r\n");
?? ??? ??? ??? ??? ??? ?res_sd= f_read(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?if(res_sd == FR_OK)
?? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ?printf("數據讀取成功!\r\n");
?? ??? ??? ??? ??? ??? ??? ?printf("數據:%s\r\n", ReadBuffer);
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ?printf("數據讀取失敗!\r\n");
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?//關閉文件
?? ??? ??? ??? ??? ??? ?f_close(&fnew);
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?printf("數據讀取失敗!\r\n");
?? ??? ?}
?? ??? ?
?? ??? ?//關閉文件
?? ??? ?f_close(&fnew);
?? ?}
?? ?printf("\r\n*************************目錄創建和重命名功能測試***************************\r\n");
?? ?//嘗試打開目錄
?? ?res_sd = f_opendir(&dir, "0:TestDir");
?? ?if(res_sd != FR_OK)
?? ?{
?? ??? ?//打開目錄失敗,開始創建目錄
?? ??? ?res_sd = f_mkdir("0:TestDir");
?? ?}
?? ?else
?? ?{
?? ??? ?//如果目錄已經存在,關閉它
?? ??? ?res_sd = f_closedir(&dir);
?? ??? ?//刪除文件
?? ??? ?f_unlink("0:FatFs讀寫測試文件.txt");
?? ?}
?? ?
?? ?if(res_sd == FR_OK)
?? ?{
?? ??? ?//重命名并移動文件
?? ??? ?res_sd = f_rename("0:FatFs多項功能測試文件.txt", "0:/TestDir/FatFs多項功能測試文件.txt");
?? ??? ?
?? ??? ?if(res_sd == FR_OK)
?? ??? ?{
?? ??? ??? ?printf("重命名并移動文件成功!\r\n");
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?printf("重命名并移動文件失敗!\r\n");
?? ??? ?}
?? ?}
}
?
//文件信息獲取
static FRESULT file_check()
{
?? ?//文件信息
?? ?static FILINFO fno;
?? ?
?? ?//獲取文件信息,必須確保文件存在
?? ?res_sd = f_stat("0:FatFs讀寫測試文件.txt", &fno);
?? ?
?? ?if(res_sd == FR_OK)
?? ?{
?? ??? ?printf("0:FatFs讀寫測試文件.txt的信息如下:\r\n");
?? ??? ?printf("文件大小:%ld\r\n", fno.fsize);
?? ??? ?printf("時間戳:%u/%02u/%02u, %02u:%02u\r\n", (fno.fdate >> 9) + 1980, fno.fdate >> 5 & 15, fno.fdate & 31, fno.ftime >> 11, fno.ftime >> 5 &63);
?? ??? ?printf("屬性:%c%c%c%c%c\r\n",?
?? ??? ?(fno.fattrib & AM_DIR) ? 'D' : '-', //目錄
?? ??? ?(fno.fattrib & AM_RDO) ? 'R' : '-', //只讀
?? ??? ?(fno.fattrib & AM_HID) ? 'H' : '-', //隱藏
?? ??? ?(fno.fattrib & AM_SYS) ? 'S' : '-', //系統文件
?? ??? ?(fno.fattrib & AM_ARC) ? 'A' : '-');//檔案文件
?? ?}
}
?
//路徑掃描
static FRESULT scan_files(char* path)
{
?? ?FRESULT res;//在遞歸過程中被修改,不用全局變量
?? ?FILINFO fno;
?? ?DIR dir;
?? ?int i;
?? ?char* fn;
?? ?
?? ?#if _USE_LEN//長文件名支持
?? ?//簡體中文需要兩個字節保存一個字
?? ?static char lfn[_MAX_LFN*2+1];
?? ?fno.lfname = lfn;
?? ?fno.lfsize = sizeof(lfn);
?? ?#endif
?? ?
?? ?//打開目錄
?? ?res = f_opendir(&dir, path);
?? ?if(res == FR_OK)
?? ?{
?? ??? ?i = strlen(path);
?? ??? ?while(1)
?? ??? ?{
?? ??? ??? ?//讀取目錄下的內容
?? ??? ??? ?res = f_readdir(&dir, &fno);
?? ??? ??? ?if(res != FR_OK || fno.fname[0] == 0)
?? ??? ??? ?{
?? ??? ??? ??? ?break;
?? ??? ??? ?}
?? ??? ??? ?#if _USE_LEN
?? ??? ??? ?fn = *fno.lfname ? fno.lfname : fno.fname;
?? ??? ??? ?#else
?? ??? ??? ?fn = fno.fname;
?? ??? ??? ?#endif
?? ??? ??? ?
?? ??? ??? ?//點表示當前目錄,跳過
?? ??? ??? ?if(*fn == '.')
?? ??? ??? ??? ?continue;
?? ??? ??? ?//目錄,遞歸讀取
?? ??? ??? ?if(fno.fattrib & AM_DIR)
?? ??? ??? ?{
?? ??? ??? ??? ?//合成完整目錄名
?? ??? ??? ??? ?sprintf(&path[i], "/%s", fn);
?? ??? ??? ??? ?
?? ??? ??? ??? ?//遞歸遍歷
?? ??? ??? ??? ?res = scan_files(path);
?? ??? ??? ??? ?
?? ??? ??? ??? ?path[i] = 0;
?? ??? ??? ??? ?if(res != FR_OK)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?else
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?printf("%s/%s\r\n", path, fn);//輸出文件名,可以在這里提取特定格式的文件路徑
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ?}
?? ?return res;
}
感謝大家的耐心閱讀,如果有問題,歡迎一起討論。
————————————————
版權聲明:本文為CSDN博主「CallMeJacky」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/zyxhangiian123456789/article/details/79098483
總結
以上是生活随笔為你收集整理的基于SD卡的FatFs文件系统(FatFs移植到STM32)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tee 和 ree分别是什么意思?
- 下一篇: 如何根据CSD寄存器计算SD卡容量(cs