
第十五节 SD文件系统的学习! ^% ~# F# [/ t5 U 详细内容请看附件/ n4 }) w3 D( R8 y9 C8 c8 [ 本节我们通过科星F107开发板的SPI接口对SD卡进行数据的读写。主要学习的内容就是SPI的配置与文件系统的移植。这里我们用到的文件系统是FatFs, FatFS 是一个通用的文件系统模块,用于在小型嵌入式系统中实现FAT文件系统。 FatFs 的编写遵循ANSI C,因此不依赖于硬件平台。它可以嵌入到便宜的微控制器中,如 8051, PIC, AVR, SH, Z80, H8, ARM 等等,不需要做任何修改。 最顶层是应用层,使用者无需理会FatFs Module 的内部结构和复杂的FAT 协议,只需 : Z2 I& }9 c) F- k; j要调用FatFs Module 提供给用户的一系列应用接口函数,如f_open,f_read,f_write 和f_close K6 D9 q; E* ?. t! L, n等,就可以像在PC 上读/写文件那样简单。 中间层FatFs Module 实现了FAT 文件读/写协议。FatFs Module 的完全版提供的是ff.c、 ff.h,简化版Tiny-FatFs 提供的是tff.c、tff.h。除非有必要,使用者一般不用修改,使用时将 需要版本的头文件直接包含进去即可。 ' X# S5 e" l& P! |( }/ d1 ~需要使用者编写移植代码的是FatFs Module 提供的底层接口,它包括存储媒介读/写 ; [( u4 E1 E P8 ?4 I6 m% H) ~* L接口Disk I/O 和供给文件创建修改时间的实时时钟。
0 F2 |( S- z' i5 S* t% k. H; `4 S
, J0 N9 L2 S& P4 I! `9 X 程序的编写 下面我们开始代码的编写: % Y, z: V6 \3 D8 W' X) D* i1、 主函数的编写 ' Q6 m0 A! n- h7 iint main(void) { 6 S& f) N6 t6 w( f RCC_Configuration(); 6 _* q1 ~% x- w o! j GPIO_Configuration(); ' U' h8 e# B, c USART_Configuration(); 2 n6 l+ g& K3 e f w SPI_Configuration(); O( M- m" _# \8 R: E9 D! X: @ FATFS_TEST(); //FATFS常用功能测试函数 : p( O9 P0 o$ S9 `; u while (1) $ E. E* i* L0 ~3 Q+ k8 y6 S- o { ( Y: A' N, D9 q0 P: v# J } } 8 p; l# Q2 c7 w t7 g2 Y: ?这里新接触的配置函数就是SPI的配置了,也是使用库提供的结构体对SPI进行定义,更多的SPI的介绍,我们这里就不多说了,MCU的芯片手册写的也很清楚了,这里复制过来也没啥意思。下面我们看一下SPI的配置函数,代码如下: . e9 P- h1 K. r0 W; Cvoid SPI_Configuration(void) { 8 M- n% S2 u2 o% g SPI_InitTypeDef SPI_InitStructure; 4 j0 ?. }4 `/ k1 P/* SPI3 Config */ ! X0 t3 z) N$ \ //一开始SD初始化阶段,SPI<i>时钟频率必须<span lang="EN-US" style="color:#4F81BD;mso-themecolor:accent1">SD卡驱动函数的编写 这里使用文件SD_driver.c和SD_driver.h来写出SD读写的一些驱动函数。 3 M6 n4 P: G- ~) {' M+ s函数列表如下: /* Private define ------------------------------------------------------------*/ 9 I0 q, l' R5 S; j) a Y/* SD卡类型定义 */ 6 [- }2 t* x) x4 D# g#define SD_TYPE_MMC 0 $ F: X& j" ^4 N/ d) z1 H#define SD_TYPE_V1 1 4 g. [! _+ @7 x0 E! |% g g, J#define SD_TYPE_V2 2 #define SD_TYPE_V2HC 4 8 ]1 k' h0 _% ~9 k /* SPI总线速度设置*/ #define SPI_SPEED_LOW 0 #define SPI_SPEED_MID 1 9 h5 l( J f v9 R( G1 ~- ~ i#define SPI_SPEED_HIGH 2 8 H2 K: @. z0 ^) H8 n" [/* SD传输数据结束后是否释放总线宏定义 */ #define NO_RELEASE 0 3 s' [) I _5 \6 K, N: x#define RELEASE 1 $ Y( @" }8 z/ p# c5 m( r% {7 `* {" ?& M9 C8 U) W& e6 _4 i /* SD卡指令表 */ h( o# b) v5 E. e' k% {, S#define CMD0 0 //卡复位 #define CMD9 9 //命令9 ,读CSD数据 #define CMD10 10 //命令10,读CID数据 ! _0 i8 {4 O6 [: }: ?#define CMD12 12 //命令12,停止数据传输 #define CMD16 16 //命令16,设置SectorSize 应返回0x00 8 p# {9 N. d- [1 t$ Y- T- A#define CMD17 17 //命令17,读sector 7 j) r# n" b' P- l1 w#define CMD18 18 //命令18,读Multi sector ( h1 B% }$ w& X v/ B% `/ ^#define ACMD23 23 //命令23,设置多sector写入前预先擦除N个block ) ~7 }$ V# S R, S2 }1 y/ d#define CMD24 24 //命令24,写sector " m: b4 [* _( d! |#define CMD25 25 //命令25,写Multi sector #define ACMD41 41 //命令41,应返回0x00 & i5 S1 l( _# l+ c0 d8 @#define CMD55 55 //命令55,应返回0x01 5 ~0 }( v D* K" L% I6 B#define CMD58 58 //命令58,读OCR信息 #define CMD59 59 //命令59,使能/禁止CRC,应返回0x00 7 ^7 M/ v, z+ F* S) }$ K/ J. J$ Q9 U1 U) K9 w9 j /* Private macro -------------------------------------------------------------*/ / K1 x% s" f* l6 L# J; t- r//SD卡CS片选使能端操作: #define SD_CS_ENABLE() GPIO_ResetBits(GPIOD,GPIO_Pin_2) //选中SD卡 #define SD_CS_DISABLE() GPIO_SetBits(GPIOD,GPIO_Pin_2) //不选中SD卡 * ~3 W. P9 P! Q#define SD_PWR_ON() GPIO_ResetBits(GPIOD,GPIO_Pin_10) //SD卡上电 : H" v# h: \/ k0 Q4 I) g1 @#define SD_PWR_OFF() GPIO_SetBits(GPIOD,GPIO_Pin_10) //SD卡断电 #define SD_DET() 1 // !GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2) //检测有卡 7 W7 B9 _" i7 g4 L& ] //1-有 0-无 . J* r" W [' a6 s- z5 f% V/* Private function prototypes -----------------------------------------------*/ * H$ q/ p% D1 }! |) g0 E//void SPI_Configuration(void); 0 {: U- O, f6 L. F0 q, _. T; fvoid SPI_SetSpeed(u8 SpeedSet); , {; y" o- s/ T' c2 w u8 SPI_ReadWriteByte(u8 TxData); //SPI总线读写一个字节 u8 SD_WaitReady(void); //等待SD卡就绪 - M% Y8 t0 C- e) v& Yu8 SD_SendCommand(u8 cmd, u32 arg, u8 crc); //SD卡发送一个命令 " T5 k. h! U% F- ^ n* k3 uu8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc); $ j1 k. _& M: R5 X6 a+ T2 A4 y hu8 SD_Init(void); //SD卡初始化 % j6 } ^! `* ^6 e3 b // : g1 V, y% E9 j+ Iu8 SD_ReceiveData(u8 *data, u16 len, u8 release);//SD卡读数据 u8 SD_GetCID(u8 *cid_data); //读SD卡CID u8 SD_GetCSD(u8 *csd_data); //读SD卡CSD u32 SD_GetCapacity(void); //取SD卡容量 5 z1 y3 E8 H, G* X. {4 V8 `u8 SD_ReadSingleBlock(u32 sector, u8 *buffer); //读一个sector u8 SD_WriteSingleBlock(u32 sector,const u8 *buffer); //写一个sector 7 W% a* o5 d0 }u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count); //读多个sector u8 SD_WriteMultiBlock(u32 sector,const u8 *data, u8 count);//写多个sector / R6 R( l( d, a% _0 b* o( W W! E& I% F9 Y7 I5 U7 ] 3、 文件系统的移植 FatFs文件系统主要有以下函数: . T# ]4 b5 k3 |6 `/*-函数详细的解释请查阅附录,点击链接也可以到----*/ - n8 ~0 a J) |5 m, ^! V/* FatFs module application interface */ 6 l- I; ^7 O4 T; L) s/ k/ V& f FRESULT 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 */ 4、 底层接口I/O函数的编写 ( W1 c+ K- V5 r1 \+ k3 ^% F底层驱动是必须由用户自己完成的,函数均放在文件diskio.c中,函数如下: : b/ N( E2 c& Y! h$ r/* Prototypes for disk control functions */ ! e& S3 M8 K$ t/ {3 }* C; vDSTATUS disk_initialize (BYTE); DSTATUS disk_status (BYTE); DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE); b1 S) X6 r, H4 ADRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE); ; I' x+ r6 Q- n# ZDRESULT disk_ioctl (BYTE, BYTE, void*); ' C H \8 T4 W cDWORD 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、 应用层函数的编写 我们这个例程要实现的8个功能如下: 每一个功能都对应一个函数,各个函数如下: 9 k' \ Y) H3 W* `7 c. X1 t! [// 0 读取磁盘容量 The f_getfree function gets number of the free clusters D1 k# U1 H0 F* Ivoid Test_f_getfree(void); # B) H W/ u# c: Q3 s& i. [//1 读磁盘目录 The f_readdir function reads directory entries. % y9 j: o6 C- ^! gvoid Test_f_readdir(void); //2 创建目录 The f_mkdir function creates a new directory void Test_f_mkdir(void); 2 x4 g& L) l! S8 O. P% l; L//3 读取文件 The f_read function reads data from a file. void Test_f_read(void); ! I1 a' C) y Z, \6 X; d6 ]# a//4 文件拷贝 The f_write writes data to a file. 2 H& B: U: J0 ^( Bvoid Test_f_write(void); ( Y j0 J# L8 t$ v' @//5 重命名 Rename file or directory void Test_f_rename(void); //6 删除文件 The f_unlink removes file or directory " a+ c& M( z+ ]# K* ~$ dvoid Test_f_unlink(void); + P5 J# w6 z: I: n//7 格式化 The f_mkfs fucntion creates a file system on the drive. void Test_f_mkfs(void); 这8个函数的调用是通过一个二维的函数指针数组完成的,该数组如下: void *FATFS_Function[][2]= { 5 F0 _# e/ k! [* E (void*)Test_f_getfree, "磁盘容量", (void*)Test_f_readdir, "读目录 ", ( J r$ b' L* c: H; P% _ (void*)Test_f_mkdir, "创建路径", ' R- m# y' v- k. P (void*)Test_f_read, "读文件 ", (void*)Test_f_write, "文件拷贝", ' V- q: z# S4 o/ o. I8 y (void*)Test_f_rename, "重命名 ", y& m& V W4 P2 I! c (void*)Test_f_unlink, "删除文件", (void*)Test_f_mkfs, "格式化 ", 0x00,0x00 % \) @6 ~3 H; c8 r t/ R& W5 @1 G}; , }9 v* X# H4 V; a2 ?8 Z这8个函数完成的功能都是调用FatFs文件系统里的函数,FatFs文件系统的函数前面已经列出了列表,在本节最后面我们也附上了函数的详细定义及用法,请查阅。下面我们着重分析一下这几个应用函数: " P0 o+ K9 A4 s; K7 r; r0)//The f_getfree function gets number of the free clusters % I2 u, {9 d! M1 f: ?6 B Cvoid Test_f_getfree(void) : T+ p) g; @- ?* Q! c9 Z{ 0 i! t; S2 M5 `4 j! i6 }2 d FATFS fs; FATFS *pfs; 3 N3 A7 F2 v$ ^3 |/ I2 v DWORD clust; * [# Q+ I; ^6 F$ k0 P/ X- d FRESULT res; // FatFs function common result code . K% D8 [4 X/ i [+ K, e- a9 d7 F) ]7 ?; u$ q/ ]$ ~) ^0 T9 F //检测磁盘是否插好 if( disk_detect_OK()==FALSE ) return; pfs=&fs;//指向 % r7 p' ^0 t- f! ~7 X// Register a work area for logical drive 0 $ h- G! N: \! V- L, O; b//温馨提示:该函数是文件系统FatFs里的函数,详细说明请查阅本章节最后的附录,可以用Ctrl+F快捷键,弹出搜索框,输入该函数名,找到该函数。以下类似函数均可以这样找到详细说明,不再赘述。该类函数我们会标记红色,并加粗,请留意。比如f_mount, 解释如下: 7 T# o* V1 D/ [6 s( q & }( H! E7 `2 h f_mount(0, &fs); & _9 W J( ]% X2 ^5 q4 U/ @; [$ ~+ E) I% c( B // 获取空闲簇Get free clusters ,空闲簇的值存在clust 1 o. U0 P" t' ^$ d res = f_getfree("/", &clust, &pfs);//必须是根目录,默认磁盘0 . m/ D+ J7 b8 M# ^ if ( res==FR_OK ) { // Get free space 这里是打印显示出 SD卡总的空间大小以及剩余空间大小 c$ t) a" h! ~ //计算方法: // 总空间大小 最大簇数×每簇的扇区数÷2÷1024 // 剩余空间大小 空闲簇数×每簇的扇区数÷2÷1024 + X3 x3 y2 o2 ]1 r3 f- c' J+ } printp("\r\n%d MB total disk space.\r\n%d MB available on the disk.\r\n", 5 [+ G! T5 ]7 v0 r (DWORD)(pfs->max_clust - 2) * pfs->csize /2/1024, , b7 W" Q- F1 T& _# k; {1 G clust * pfs->csize /2/1024); % Y0 C$ I: G, p } 7 c7 }# {$ u- ?" @$ t1 o2 T6 h2 g else - m/ s( ~0 D6 n3 C0 P die(res);//测试函数执行结果分析 + k) f5 {! }5 Z; ~% ]; [' C // Unregister a work area before discard it f_mount(0, NULL); 7 {# w4 a, C. t2 ]} & ^4 b% p/ k1 h, _0 P//1 读取目录 The f_readdir function reads directory entries. void Test_f_readdir(void) { FATFS fs; // Work area (file system object) for logical drive char path[20]; * A7 V- o0 u5 S# w7 D% {1 k //检测磁盘是否插好 8 Z8 |" C0 l* X1 F t3 e$ p if( disk_detect_OK()==FALSE ) return; $ I. o3 {% [; ~; b5 e5 v; H2 [8 i9 s) g" i% b f_mount(0, &fs); // Register a work area for logical drive 0 printp("\r\nread directory:>/");//默认输出主目录下的文件 " x% k/ |- a3 b: ]7 ^# n$ @9 m0 S& ~- P1 n ^+ W5 q' j USART_Scanf_Name(path);//通过串口输入路径名 0 F! j( N8 v% C9 D //扫描当前路径下子文件夹,并输出到串口 8 h7 v' N9 j, R. l4 @ scan_current_folder(path); % G- V7 }0 S9 _8 ^7 O! {' Z$ d //扫描当前路径下文件,并输出到串口 scan_current_files(path); f_mount(0, NULL);// Unregister a work area before discard it 4 V' r! x9 ?: u S2 A( c1 X& [% l} $ H2 p2 ~& _- I9 z9 P //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 } D* Q1 i3 N' _5 P //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); 4 W4 t9 K: N4 T' C: c6 P 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 ); //time_start=Time_GetCalendarTime();//记录开始读时间 //unix_start=Time_ConvCalendarToUnix(time_start); ( t Y3 q# |1 I+ O- g5 ~6 D3 N //输出提示.. 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页笔记+源码