FATFS文件系统
折腾了差不多快三天,总算出点眉目,操作流程,打开,浏览,读写都没啥问题了。
char[] char* a这个C确实比较基础,调用<string.h>中的函数来完成操作,又熟悉了一遍吼吼
我们需要的两个主要文件:ff.c 和diskio.c 其中ff.c是我们所需要调用的所有方法,diskio.c是我们移植需要写的底层函数。
又走了不少弯路,不过也学到不少,神舟代码移植简单,但是功能不强大,不支持长文件名,并且版本居然是07的不是最新的我晕。而且原子的用动态内存来做,省资源,顺便加深对指针内存的认识,另外昨晚折腾char []也过去了吼吼。
因为在ffconf.h里面设置对长文件名的支持为方法3,所以必须实现ff_memalloc和ff_memfree这两个函数
同时因为在ffconf.h里面设置对长文件名的支持为方法3 必须实现:When enable LFN,
/ a Unicode handling functions ff_convert() and ff_wtoupper() must be added
/ to the project. */
这个转换函数在cc936.c文件中,
原子支持两个盘符,0:SD 1:FLASH,因为我还没有加入flash读写,所以先把flash代码屏蔽掉。
就是把之前SD卡初始化,读,写函数封装进去
1 //初始化磁盘 2 DSTATUS disk_initialize ( 3 BYTE drv /* Physical drive nmuber (0..) */ 4 ) 5 { 6 u8 res=0; 7 switch(drv) 8 { 9 case SD_CARD://SD卡 10 res = SD_Initialize();//SD_Initialize() 11 if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常 12 { 13 SD_SPI_SpeedLow(); 14 SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟 15 SD_SPI_SpeedHigh(); 16 } 17 break; 18 case EX_FLASH://外部flash 19 // SPI_Flash_Init(); 20 // if(SPI_FLASH_TYPE==W25Q64)FLASH_SECTOR_COUNT=2048*6;//W25Q64 21 // else FLASH_SECTOR_COUNT=2048*2; //其他 22 break; 23 default: 24 res=1; 25 } 26 if(res)return STA_NOINIT; 27 else return 0; //初始化成功 28 }
1 //读扇区 2 //drv:磁盘编号0~9 3 //*buff:数据接收缓冲首地址 4 //sector:扇区地址 5 //count:需要读取的扇区数 6 DRESULT disk_read ( 7 BYTE drv, /* Physical drive nmuber (0..) */ 8 BYTE *buff, /* Data buffer to store read data */ 9 DWORD sector, /* Sector address (LBA) */ 10 BYTE count /* Number of sectors to read (1..255) */ 11 ) 12 { 13 u8 res=0; 14 if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误 15 switch(drv) 16 { 17 case SD_CARD://SD卡 18 res=SD_ReadDisk(buff,sector,count); 19 if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常 20 { 21 SD_SPI_SpeedLow(); 22 SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟 23 SD_SPI_SpeedHigh(); 24 } 25 break; 26 case EX_FLASH://外部flash 27 // for(;count>0;count--) 28 // { 29 // SPI_Flash_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE); 30 // sector++; 31 // buff+=FLASH_SECTOR_SIZE; 32 // } 33 // res=0; 34 break; 35 default: 36 res=1; 37 } 38 //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值 39 if(res==0x00)return RES_OK; 40 else return RES_ERROR; 41 }
1 //写扇区 2 //drv:磁盘编号0~9 3 //*buff:发送数据首地址 4 //sector:扇区地址 5 //count:需要写入的扇区数 6 #if _READONLY == 0 7 DRESULT disk_write ( 8 BYTE drv, /* Physical drive nmuber (0..) */ 9 const BYTE *buff, /* Data to be written */ 10 DWORD sector, /* Sector address (LBA) */ 11 BYTE count /* Number of sectors to write (1..255) */ 12 ) 13 { 14 u8 res=0; 15 if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误 16 switch(drv) 17 { 18 case SD_CARD://SD卡 19 res=SD_WriteDisk((u8*)buff,sector,count); 20 break; 21 case EX_FLASH://外部flash 22 // for(;count>0;count--) 23 // { 24 // SPI_Flash_Write((u8*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE); 25 // sector++; 26 // buff+=FLASH_SECTOR_SIZE; 27 // } 28 // res=0; 29 break; 30 default: 31 res=1; 32 } 33 //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值 34 if(res == 0x00)return RES_OK; 35 else return RES_ERROR; 36 } 37 #endif /* _READONLY */
另外//获得时间
//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)
需要实时时钟我就没封装了这里,测试了 一下,很简单。这里配置好之后,新建文件就会有时间戳了。
一些其他的实用的函数:
1 //遍历文件 2 //path:路径 3 //返回值:执行结果 4 u8 mf_scan_files(u8 * path) 5 { 6 FRESULT res; 7 char *fn; /* This function is assuming non-Unicode cfg. */ 8 FILINFO fileinfo; 9 DIR dir; 10 11 #if _USE_LFN 12 fileinfo.lfsize = _MAX_LFN * 2 + 1; 13 fileinfo.lfname = mymalloc(SRAMIN,fileinfo.lfsize); 14 #endif 15 16 res = f_opendir(&dir,(const TCHAR*)path); //打开一个目录 17 if (res == FR_OK) 18 { 19 printf("\r\n"); 20 while(1) 21 { 22 res = f_readdir(&dir, &fileinfo); //读取目录下的一个文件 23 if (res != FR_OK || fileinfo.fname[0] == 0) break; //错误了/到末尾了,退出 24 //if (fileinfo.fname[0] == '.') continue; //忽略上级目录 25 #if _USE_LFN 26 fn = *fileinfo.lfname ? fileinfo.lfname : fileinfo.fname; 27 #else 28 fn = fileinfo.fname; 29 #endif /* It is a file. */ 30 printf("%s/", path);//打印路径 31 printf("%s fdate: %d dtime: %d\r\n", fn,fileinfo.fdate,fileinfo.ftime);//打印文件名 32 } 33 } 34 myfree(SRAMIN,fileinfo.lfname); 35 return res; 36 }
此函数遍历路径下的所有文件,其中_USE_LFN 表示使用长文件名
如果fileinfo.fname[0] == 0表示遍历完了
fileinfo.fattrib 文件属性,可以了解到文件属性是文件夹还是文件等等属性
1 //显示剩余容量 2 //drv:盘符 3 //返回值:剩余容量(字节) 4 u32 mf_showfree(u8 *drv) 5 { 6 FATFS *fs1; 7 u8 res; 8 DWORD fre_clust=0, fre_sect=0, tot_sect=0; 9 //得到磁盘信息及空闲簇数量 10 res = f_getfree((const TCHAR*)drv, &fre_clust, &fs1); 11 if(res==0) 12 { 13 tot_sect = (fs1->n_fatent - 2) * fs1->csize;//得到总扇区数 14 fre_sect = fre_clust * fs1->csize; //得到空闲扇区数 15 //#if _MAX_SS!=512 16 // tot_sect*=fs1->ssize/512; 17 // fre_sect*=fs1->ssize/512; 18 //#endif 19 if(tot_sect<20480)//总容量小于10M 20 { 21 /* Print free space in unit of KB (assuming 512 bytes/sector) */ 22 printf("\r\n磁盘总容量:%d KB\r\n" 23 "可用空间:%d KB\r\n", 24 tot_sect>>1,fre_sect>>1); 25 }else 26 { 27 /* Print free space in unit of KB (assuming 512 bytes/sector) */ 28 printf("\r\n磁盘总容量:%d MB\r\n" 29 "可用空间:%d MB\r\n", 30 tot_sect>>11,fre_sect>>11); 31 } 32 } 33 return fre_sect; 34 }
显示磁盘总容量以及所剩空间大小
1 //给文件设置时间戳 2 FRESULT set_timestamp ( char *obj, int year, int month, int mday, int hour, int min, int sec ) 3 { 4 FILINFO fno; 5 // printf("set_timestamp file name %s \r\n",obj); 6 fno.fdate = (WORD)(((year - 1980) * 512U) | month * 32U | mday); 7 fno.ftime = (WORD)(hour * 2048U | min * 32U | sec / 2U); 8 return f_utime(obj, &fno); 9 }
修改时间戳
一些常用操作 以下函数都是ff.c中
挂载一个磁盘:FATFS fs; f_mount(0, &fs) //0代表盘符
打开目录:f_opendir(&dirs, path) //DIR dirs;
读目录:f_readdir(&dirs, &finfo) // FILINFO finfo;
打开一个文件读写:
FIL fsrc
// res = f_open(&fsrc, filename2, FA_OPEN_EXISTING | FA_READ | FA_WRITE); ///新建一个文件可以用 FA_CREATE_ALWAYS代替 FA_OPEN_EXISTING
// res = f_read(&fsrc, buffer, 100, &br);
// printf("\n\r file contex is: \n\r%s\n\r", buffer);
// res = f_write(&fsrc, &armjishu, sizeof(armjishu), &bw);
// f_close(&fsrc);
删除一个文件:f_unlink(path)