
第十五节 SD文件系统的学习 详细内容请看附件 本节我们通过科星F107开发板的SPI接口对SD卡进行数据的读写。主要学习的内容就是SPI的配置与文件系统的移植。这里我们用到的文件系统是FatFs, FatFS 是一个通用的文件系统模块,用于在小型嵌入式系统中实现FAT文件系统。 FatFs 的编写遵循ANSI C,因此不依赖于硬件平台。它可以嵌入到便宜的微控制器中,如 8051, PIC, AVR, SH, Z80, H8, ARM 等等,不需要做任何修改。 - M4 {* r% [9 }9 I; g 1 d. ?+ J+ ]* B* a 最顶层是应用层,使用者无需理会FatFs Module 的内部结构和复杂的FAT 协议,只需 + R) \* s# s8 h8 N. G/ y# y/ r要调用FatFs Module 提供给用户的一系列应用接口函数,如f_open,f_read,f_write 和f_close $ @! ?2 H& W7 x) A' n等,就可以像在PC 上读/写文件那样简单。 " }0 j1 m7 e% n9 {5 a8 i0 `( A& q中间层FatFs Module 实现了FAT 文件读/写协议。FatFs Module 的完全版提供的是ff.c、 ff.h,简化版Tiny-FatFs 提供的是tff.c、tff.h。除非有必要,使用者一般不用修改,使用时将 需要版本的头文件直接包含进去即可。 7 V3 f; M* {* j: l, ^需要使用者编写移植代码的是FatFs Module 提供的底层接口,它包括存储媒介读/写 7 r* }! A; i1 N* L0 t) c2 Q u2 w接口Disk I/O 和供给文件创建修改时间的实时时钟。 ; o- T) f! C% e+ L% U; B9 e0 |! l; d. U: ^" J( |5 W- P7 D
程序的编写 下面我们开始代码的编写: 8 e' `1 X* n' {1、 主函数的编写 . k6 `2 @) W1 q- `& {int main(void) # y M& p! [2 x{ : K L4 u0 X9 G6 t8 \1 q RCC_Configuration(); GPIO_Configuration(); ! O8 y0 C, r; [7 v4 e USART_Configuration(); Y* k5 j( s) u9 S) B: U. q/ H7 s SPI_Configuration(); 7 }7 g8 F8 _& Y& n' }3 F; z) S6 X FATFS_TEST(); //FATFS常用功能测试函数 * b2 `* N3 l/ C1 s* M3 [" s while (1) { 8 H- O' j' k$ t d1 f# u! ^ } ; q3 _0 X: k6 |& N2 u( ~2 A. |} # z" i! H2 V0 v8 k" ^这里新接触的配置函数就是SPI的配置了,也是使用库提供的结构体对SPI进行定义,更多的SPI的介绍,我们这里就不多说了,MCU的芯片手册写的也很清楚了,这里复制过来也没啥意思。下面我们看一下SPI的配置函数,代码如下: 1 j. X3 b7 U3 D$ M& E4 G. _9 i$ p: Ovoid SPI_Configuration(void) + H% p2 X* B5 X# W$ K- X( m% N{ SPI_InitTypeDef SPI_InitStructure; 3 o1 Z3 ?! O9 l/ z; b- P9 w/* SPI3 Config */ ) H* R( U- _; C1 x0 w- r/ Y //一开始SD初始化阶段,SPI<i>时钟频率必须<span lang="EN-US" style="color:#4F81BD;mso-themecolor:accent1">SD卡驱动函数的编写 这里使用文件SD_driver.c和SD_driver.h来写出SD读写的一些驱动函数。 函数列表如下: ' k/ [& z: S% ]0 k8 f/* Private define ------------------------------------------------------------*/ & M9 e' N8 W+ H' U; h* h/* SD卡类型定义 */ #define SD_TYPE_MMC 0 / W! `- \, h' H# Z) ~8 v#define SD_TYPE_V1 1 " F/ e% {4 `" ~3 E. ~#define SD_TYPE_V2 2 #define SD_TYPE_V2HC 4 2 E" D2 C. _/ A6 V& n# c' `/* SPI总线速度设置*/ / }; _+ X$ |2 N! k2 k#define SPI_SPEED_LOW 0 #define SPI_SPEED_MID 1 & k( z A/ {4 M2 t9 r! L8 E#define SPI_SPEED_HIGH 2 /* SD传输数据结束后是否释放总线宏定义 */ #define NO_RELEASE 0 / S. K* M( |" g6 ?7 f#define RELEASE 1 ! n) \( `% U$ b* k! [( i/* SD卡指令表 */ 2 j: _) @ C0 Q" a#define CMD0 0 //卡复位 : j% S! z6 K) A+ \9 V#define CMD9 9 //命令9 ,读CSD数据 #define CMD10 10 //命令10,读CID数据 #define CMD12 12 //命令12,停止数据传输 " z' R: U( s6 i, i. b0 K! ~: \#define CMD16 16 //命令16,设置SectorSize 应返回0x00 " }* L$ D+ p- _- K7 }* H#define CMD17 17 //命令17,读sector #define CMD18 18 //命令18,读Multi sector #define ACMD23 23 //命令23,设置多sector写入前预先擦除N个block ; C- e) H# M7 y+ w! B4 ^* @#define CMD24 24 //命令24,写sector #define CMD25 25 //命令25,写Multi sector #define ACMD41 41 //命令41,应返回0x00 #define CMD55 55 //命令55,应返回0x01 #define CMD58 58 //命令58,读OCR信息 #define CMD59 59 //命令59,使能/禁止CRC,应返回0x00 . j) H. ^& w: E& r+ W; J. z1 _/* Private macro -------------------------------------------------------------*/ 0 U3 z: W8 D' d9 k//SD卡CS片选使能端操作: 8 H% I6 x3 I9 f) M* w#define SD_CS_ENABLE() GPIO_ResetBits(GPIOD,GPIO_Pin_2) //选中SD卡 ! U/ [- `- M( ^/ {#define SD_CS_DISABLE() GPIO_SetBits(GPIOD,GPIO_Pin_2) //不选中SD卡 #define SD_PWR_ON() GPIO_ResetBits(GPIOD,GPIO_Pin_10) //SD卡上电 ' v& `6 d* Y2 M4 j. w+ X#define SD_PWR_OFF() GPIO_SetBits(GPIOD,GPIO_Pin_10) //SD卡断电 #define SD_DET() 1 // !GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2) //检测有卡 //1-有 0-无 5 z5 E/ \& ?7 u; {1 y9 a; }* g, `; b /* Private function prototypes -----------------------------------------------*/ * ?" r3 f; R3 b* Q5 [9 v//void SPI_Configuration(void); void SPI_SetSpeed(u8 SpeedSet); 5 @- c1 K& m8 T2 c: M. j* b& } u8 SPI_ReadWriteByte(u8 TxData); //SPI总线读写一个字节 7 ]3 q' {% Q3 C U8 Z7 [# @u8 SD_WaitReady(void); //等待SD卡就绪 u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc); //SD卡发送一个命令 u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc); u8 SD_Init(void); //SD卡初始化 // ' ]0 G1 c. V) Du8 SD_ReceiveData(u8 *data, u16 len, u8 release);//SD卡读数据 u8 SD_GetCID(u8 *cid_data); //读SD卡CID / I, M& {/ S/ f; ]; m% ju8 SD_GetCSD(u8 *csd_data); //读SD卡CSD u32 SD_GetCapacity(void); //取SD卡容量 u8 SD_ReadSingleBlock(u32 sector, u8 *buffer); //读一个sector , Y0 Z) Y w2 f) j. V2 ?! W+ fu8 SD_WriteSingleBlock(u32 sector,const u8 *buffer); //写一个sector u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count); //读多个sector u8 SD_WriteMultiBlock(u32 sector,const u8 *data, u8 count);//写多个sector , P' ^4 N0 p$ K) ~ k2 W 3、 文件系统的移植 FatFs文件系统主要有以下函数: % J/ T! [2 l5 L* K! t) g/*-函数详细的解释请查阅附录,点击链接也可以到----*/ 0 s5 C. i1 s9 q' R0 F/* FatFs module application interface */ ! ]3 o) _9 E6 Z) J/ tFRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */ FRESULT f_open (FIL*, const char*, BYTE); /* Open or create a file */ FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */ FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */ FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */ FRESULT f_close (FIL*); /* Close an open file object */ FRESULT f_opendir (DIR*, const char*); /* Open an existing directory */ FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */ FRESULT f_stat (const char*, FILINFO*); /* Get file status */ FRESULT f_getfree (const char*, DWORD*, FATFS**); /* Get number of free clusters on the drive */ FRESULT f_truncate (FIL*); /* Truncate file */ FRESULT f_sync (FIL*); /* Flush cached data of a writing file */ FRESULT f_unlink (const char*); /* Delete an existing file or directory */ FRESULT f_mkdir (const char*); /* Create a new directory */ FRESULT f_chmod (const char*, BYTE, BYTE); /* Change file/dir attriburte */ FRESULT f_utime (const char*, const FILINFO*); /* Change file/dir timestamp */ FRESULT f_rename (const char*, const char*); /* Rename/Move a file or directory */ FRESULT f_mkfs (BYTE, BYTE, WORD); /* Create a file system on the drive */ ! `8 k3 I) B9 ]$ S; }4、 底层接口I/O函数的编写 0 k' Q4 k" Q7 e# Y; q$ b; G/ b/ ^$ ^, K底层驱动是必须由用户自己完成的,函数均放在文件diskio.c中,函数如下: 3 z* |$ u) Y/ X$ U- r9 F, R9 a# q/* Prototypes for disk control functions */ DSTATUS disk_initialize (BYTE); - |4 Z2 z4 F! A4 YDSTATUS disk_status (BYTE); ) A4 e, Z% ^1 ?3 M0 Q9 m7 g, dDRESULT disk_read (BYTE, BYTE*, DWORD, BYTE); 7 Z" d a0 x/ L! F, I5 A5 {" Z/ ADRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE); % I$ ?. I5 R( E# b% \DRESULT disk_ioctl (BYTE, BYTE, void*); 7 l: K9 A0 }' x/ ]& ~% f! m$ s5 ADWORD get_fattime (void); 6 个接口函数的详细信息如下图所示。 Disk I/O 函数结构图 因为FatFs 模块完全与磁盘I/O 层分开,因此需要下面的函数来实现底层物理磁盘的读写与获取当前时间。底层磁盘I/O 模块并不是FatFs 的一部分,并且必须由用户提供。下面的函数位于diskio.c 中。 1)disk_initialize 2) disk_status 3) disk_read 4)disk_write 5)disk_ioctl 6) get_fattime 5、 应用层函数的编写 a/ o. n( N9 U" c9 j我们这个例程要实现的8个功能如下: " h. c4 T; z5 K7 Q6 @ 每一个功能都对应一个函数,各个函数如下: * p, M1 M( ]2 H; b( y4 q( C$ G// 0 读取磁盘容量 The f_getfree function gets number of the free clusters * @/ A" Q$ j! q$ D U: uvoid Test_f_getfree(void); . `6 [$ k9 Y% [, e8 a5 c5 P//1 读磁盘目录 The f_readdir function reads directory entries. void Test_f_readdir(void); # [# B9 N" g* G+ b+ k# P//2 创建目录 The f_mkdir function creates a new directory % H$ z: Y4 j- Qvoid Test_f_mkdir(void); //3 读取文件 The f_read function reads data from a file. 5 m9 P! l* H6 B& bvoid Test_f_read(void); //4 文件拷贝 The f_write writes data to a file. * T) m+ t" h- E4 L5 M4 kvoid Test_f_write(void); 8 `# F- L, `4 V$ E//5 重命名 Rename file or directory . W/ e9 y \6 r, Zvoid Test_f_rename(void); 0 k! T- r, G, h: C) d0 n ]; o" y4 U8 f# {) g//6 删除文件 The f_unlink removes file or directory 8 @3 b; }0 f E0 @$ e/ ?6 lvoid Test_f_unlink(void); 1 H. d1 g' K6 }7 |% z//7 格式化 The f_mkfs fucntion creates a file system on the drive. G( t% N& D; q4 ?7 x/ Y% }void Test_f_mkfs(void); 4 w* j0 w# k- m/ g ! I' Y: j: C( v& \- b5 s+ L 这8个函数的调用是通过一个二维的函数指针数组完成的,该数组如下: ) G, g! s, ?& Fvoid *FATFS_Function[][2]= { : O7 j8 X' }1 ?2 h+ g, e (void*)Test_f_getfree, "磁盘容量", (void*)Test_f_readdir, "读目录 ", 3 |( q0 m4 [4 c& o; ^% \% U* K (void*)Test_f_mkdir, "创建路径", (void*)Test_f_read, "读文件 ", ' r* m4 [0 N, {! C" u; h4 R (void*)Test_f_write, "文件拷贝", (void*)Test_f_rename, "重命名 ", ! q) ]6 Y4 U! H (void*)Test_f_unlink, "删除文件", (void*)Test_f_mkfs, "格式化 ", . n4 J0 h! T- D0 d9 ~' }, w5 i 0x00,0x00 }; # \4 C8 O9 ?4 c这8个函数完成的功能都是调用FatFs文件系统里的函数,FatFs文件系统的函数前面已经列出了列表,在本节最后面我们也附上了函数的详细定义及用法,请查阅。下面我们着重分析一下这几个应用函数: 0)//The f_getfree function gets number of the free clusters void Test_f_getfree(void) 4 O" E% \: p6 T{ FATFS fs; FATFS *pfs; 6 T |( [6 U8 v; x DWORD clust; 1 {+ \; r) Z5 U% [8 M" H0 v FRESULT res; // FatFs function common result code //检测磁盘是否插好 ; I) |. G8 @; ^' L) } if( disk_detect_OK()==FALSE ) # R9 W; q( R" B# {) ? return; pfs=&fs;//指向 7 _, R# s( I3 ]// Register a work area for logical drive 0 //温馨提示:该函数是文件系统FatFs里的函数,详细说明请查阅本章节最后的附录,可以用Ctrl+F快捷键,弹出搜索框,输入该函数名,找到该函数。以下类似函数均可以这样找到详细说明,不再赘述。该类函数我们会标记红色,并加粗,请留意。比如f_mount, 解释如下: + h4 o! P% M, K9 R+ h5 P f_mount(0, &fs); ( k ~" f- Q9 F$ Q& a6 a// 获取空闲簇Get free clusters ,空闲簇的值存在clust * U* }& ~' O. n7 K res = f_getfree("/", &clust, &pfs);//必须是根目录,默认磁盘0 6 T. u7 `4 i5 \( q if ( res==FR_OK ) ' d+ ^ I+ b' n1 y( P7 T9 G { // Get free space 这里是打印显示出 SD卡总的空间大小以及剩余空间大小 //计算方法: // 总空间大小 最大簇数×每簇的扇区数÷2÷1024 * g" l- Q. U. U8 O$ a# ]) D; Z// 剩余空间大小 空闲簇数×每簇的扇区数÷2÷1024 printp("\r\n%d MB total disk space.\r\n%d MB available on the disk.\r\n", (DWORD)(pfs->max_clust - 2) * pfs->csize /2/1024, clust * pfs->csize /2/1024); } else die(res);//测试函数执行结果分析 // Unregister a work area before discard it f_mount(0, NULL); , {1 C9 u. Y$ t6 [: x' A} 3 `+ P8 G- X2 s# M. W) e* Y! R //1 读取目录 The f_readdir function reads directory entries. void Test_f_readdir(void) ) |+ U* e% ?+ E- ?0 K. k{ 9 q8 U* A6 k5 q0 G" J6 c FATFS fs; // Work area (file system object) for logical drive char path[20]; 6 j. _2 Z9 ~$ l/ |& G. h" Z6 d //检测磁盘是否插好 if( disk_detect_OK()==FALSE ) . m- A. @+ c$ t! j) r$ p( E return; f_mount(0, &fs); // Register a work area for logical drive 0 / r2 H6 t4 F$ q n, B5 s' n printp("\r\nread directory:>/");//默认输出主目录下的文件 ' |4 {# n; A j USART_Scanf_Name(path);//通过串口输入路径名 ( `1 _4 l$ S6 a$ ?' x7 F //扫描当前路径下子文件夹,并输出到串口 scan_current_folder(path); //扫描当前路径下文件,并输出到串口 7 k2 O3 U ^, A( \1 M$ e scan_current_files(path); 9 g% D Z2 m7 h f_mount(0, NULL);// Unregister a work area before discard it 6 I/ ^/ Y1 N1 s8 B8 f$ Y* k8 X} & |$ z% ]4 b9 z* d5 U2 }5 y) J) T/ G//2 读取目录 The f_mkdir function creates a new directory void Test_f_mkdir(void) { FATFS fs; // Work area (file system object) for logical drive FRESULT res; // FatFs function common result code char path[20]; //检测磁盘是否插好 if( disk_detect_OK()==FALSE ) return; f_mount(0, &fs); // Register a work area for logical drive 0 printp("\r\nmake directory:>"); USART_Scanf_Name(path);//通过串口输入路径名 res = f_mkdir(path); die(res);//测试函数执行结果分析 f_mount(0, NULL);// Unregister a work area before discard it } * e& z$ P: ?4 D! }# D 6 E8 |! w! F. \ //3 读文件 The f_read function reads data from a file. void Test_f_read(void) { //用来记录读文件起始时间、结束时间 struct tm time_start,time_end ; //用来记录读文件起始时间、结束时间 ,unix时间格式,用来记录时间差。 time_t unix_start,unix_end,interval; char path[20]; //检测磁盘是否插好 if( disk_detect_OK()==FALSE ) return; //printp("\r\nread filebbbb:>"); // Register a work area for logical drive 0 f_mount(0, &fs); printp("\r\nread file:>"); USART_Scanf_Name(path);//通过串口输入文件路径名 //Open source file res = f_open(&fsrc, path, FA_OPEN_EXISTING | FA_READ); die(res); //buffer空间设大一点,会提高读的速度。 //如果文件实际大小512byte, //设为buffer[512]时,只需要循坏一次,如果设为buffer[1],需要循坏512次。 //下面两行主要是去除1s误差。 //Read_File_Flag = 0; //while( Read_File_Flag==0 ); ( C" l, r& b' a( ]% z- t& R! T9 o8 s( K //time_start=Time_GetCalendarTime();//记录开始读时间 //unix_start=Time_ConvCalendarToUnix(time_start); //输出提示.. if( res==FR_OK ) printp("\r\nread file start time :%02d:%02d:%02d\r\nplease waiting...\r\n", time_start.tm_hour, time_start.tm_min, time_start.tm_sec); for (;;) { //清除缓存 <span lang="EN-US"> for(i=0;iRTC函数的编写 |
15ç§æF107å¼åæ¿å¦ä¹ ç¬è®°âSDå¡ä¸æä»¶ç³»ç»FatFsçå¦ä¹ .pdf
下载2.25 MB, 下载次数: 949
求助一个STM32F103VCT6与AT45DB081芯片通讯添加文件管理系统FATFS,SPI2的接口的示例
回复:STM32 FatFs文件系统 移植,SD读写数据 58页笔记+源码
15ç§æF107å¼åæ¿å¦ä¹ ç¬è®°æºç âSDå¡ä¸æä»¶ç³»ç»FatFsçå¦ä¹ .rar
2013-11-20 09:58 上传
点击文件名下载附件
863.7 KB, 下载次数: 886
RE:STM32 FatFs文件系统 移植,SD读写数据 58页笔记+源码
RE:STM32 FatFs文件系统 移植,SD读写数据 58页笔记+源码
RE:STM32 FatFs文件系统 移植,SD读写数据 58页笔记+源码
RE:STM32 FatFs文件系统 移植,SD读写数据 58页笔记+源码
RE:STM32 FatFs文件系统 移植,SD读写数据 58页笔记+源码
回复:STM32 FatFs文件系统 移植,SD读写数据 58页笔记+源码
回复:STM32 FatFs文件系统 移植,SD读写数据 58页笔记+源码