标题: [资料] 自己移植的SD卡的FATFS文件系统,FATFS R0.09 (MDK STM32f103) [打印本页] 作者: Gegu 时间: 2016-4-28 10:03 标题: [资料] 自己移植的SD卡的FATFS文件系统,FATFS R0.09 (MDK STM32f103) 自己移植的SD卡的FATFS文件系统,采用最新版FATFS R0.09,并且有详细的中文注释,和操作测试程序,完整的MDK STM32F103工程。下载即可使用。 O7 y$ |" Y8 Z& G; }5 i) H" M- p/*----------------------------------------------------------------------------/4 \& d: P3 l. Y7 p" d9 E/ N' N
/ FatFs - FAT file system module R0.09 (C)ChaN, 2011% r2 f: ]4 q' i- R7 G- k, L0 Q9 l m* `
/-----------------------------------------------------------------------------// |. Y7 `7 R. f- h1 G
/ FatFs module is a generic FAT file system module for small embedded systems. 9 L5 F+ u" w$ N! X/ This is a free software that opened for education, research and commercial- [& J# s- | K$ ^% s0 p+ M3 I
/ developments under license policy of following terms.1 u2 ~0 \ q4 |1 h% \# g
/ - {5 @ h. A+ v/ Copyright (C) 2011, ChaN, all right reserved.# A- ~6 n8 X/ M8 V5 F2 s
/; Y- S) P; G: L1 L, b* `
/ * The FatFs module is a free software and there is NO WARRANTY.# s" i( D* i7 l) P' }
/ * No restriction on use. You can use, modify and redistribute it for7 h8 a% G' q* N3 R3 S; [/ B9 z* ^
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. + P$ r8 r! K5 A* f/ * Redistributions of source code must retain the above copyright notice. . c, e) _& G1 ^( r/ & O* L+ x5 s1 _+ W/-----------------------------------------------------------------------------/ ; a* j) T# h0 q- w9 C7 m: ] P3 S; u
6 E# U( J; U: {5 Z
/*--------------File Info------------------------------------------------------- 0 a9 P4 Z! y" a7 i6 p0 s** 文 件 名: FATFS_Function.c$ d0 R9 [/ l4 y( k
** 作 者:~风中的叶~ 整理 # C7 ^1 f$ x% z) E' b$ w** 最后修改日期: 2012.01.18$ \7 X. d: ?) Q, f( y! l
** 版 本: V1.04 p' }/ b I1 [4 ~6 u" e
** 描 述: FATFS常用功能测试函数 .连接PC机串口,观察超级终端输出' O, V8 B# |4 S2 g+ C- Q
**------------------------------------------------------------------------------ 6 Z, A, K+ W' k3 A/ P7 ^2 y** Created by: Dt.' p. H% S& M; m) k/ j0 w- Z
** Created date: 8 _1 C) I) U- [/ v*******************************************************************************/ " {. N+ T( [7 N L#include "TEST_FATFS.h" 6 Z& j. a1 h- s; o#include "string.h" N5 _. t1 {% l# f5 y3 ~4 E7 H/ R+ J+ M, U* h, [7 u/ ~
#ifdef TEST_FATFS_EN# V% J8 Y: x2 M5 T7 r
7 y+ ?2 l& Z5 g3 Z; s H+ z7 }/ n9 Q" r8 ]: |3 E3 V0 x) }6 @+ z
//检测磁盘是否插好 : z$ j5 ^; G7 X. x. s- l4 s" K/ CBOOL disk_detect_OK(void) y. [# }* D) g9 U5 l{ 7 U. @, a5 C% _- H if( disk_status(0)==STA_NODISK )/* Physical drive nmuber (0..) */ ! u& v! o0 e0 q: u3 q& g { % W c$ R; {( U) k& B. f1 a printf("\r\n\r\n%48s\r\n","<未检测到磁盘,请检查SD卡是否插好...>");) [9 `1 `5 J# R1 I' u d) j
return FALSE; ! Z4 a" E, }! }# r6 | } : x) v$ P3 z. m0 p0 r return TRUE;+ s7 k7 `( M+ d0 C M; }; Y, z
}& _, X N$ H4 @; d0 e
7 F/ [ t+ o/ z J9 d3 W7 f4 u
- n. l) ^- T7 V# d* \, R * c" W% Y( q3 S }//测试函数执行结果分析 4 C1 J+ s2 V' ~1 X( ] M2 Cvoid die(FRESULT res)8 F) A3 f% V1 X8 X& G/ `
{ d S5 X- E. y8 {/ h switch(res) - o1 }5 f2 Q R7 f6 l3 a {# u R. F- H# v% O2 c; o" A- c1 }$ ~
case FR_OK: //The function succeeded. + c4 F5 d1 |( u4 o5 p* \# U {1 J/ ?0 \* |; V t
printf("\r\nThe function succeeded!\r\n");/ f0 [4 Z, w9 U9 H% r. d
break;/ u0 W; v! m4 w- K" X' N' V2 f
} 9 M# ]6 Q4 N& P( }, Y' N* s; n case FR_NOT_READY://The disk drive cannot work due to no medium in the drive or any other reason0 C3 L% ]; j2 n2 X. j
{5 p4 o5 ?% _' M' T& [ B5 @
printf("\r\nThe disk drive cannot work due to no medium in the drive or any other reason!\r\n"); $ T7 @" P4 f) x. `- p break; ) p8 t; I! ?. m; Z. @) f; U- Y } 0 T K) u$ m/ v" o* H case FR_NO_FILE://Could not find the file. ; p5 M. h' B' L' I' h5 s& x {- d/ D/ I n* [! t9 K. [, q2 n
printf("\r\nCould not find the file!\r\n");: b8 ]7 ]- q Q' r
break; 4 M" `- a3 p4 w } ) `4 s+ A/ m" }4 C* N# |0 P: F case FR_NO_PATH://Could not find the path! y% ~& }) @0 x4 D0 ]7 V3 O
{ / |: V, `( K" m, U printf("\r\nCould not find the path!\r\n"); 5 `" M6 x6 N9 X' Y break;6 } q, L0 J' ]; o
}% A( T$ y8 E( @- Z
case FR_INVALID_NAME://The path name is invalid: C( f* k& [1 u" }
{ 1 K( ~, O {& ]/ Q! u! `1 u printf("\r\nThe path name is invalid!\r\n"); + D4 n& N x7 v9 x( u" Z break;$ }6 O/ O- _! U
}! f& @& ]' ?' w5 A3 x' T. B4 |
case FR_INVALID_DRIVE://The drive number is invalid. c; o" e: r6 x7 b& y' S/ n/ w
{ 6 I. D d1 T g# a printf("\r\nThe drive number is invalid!\r\n");0 ^- y% [6 P# l: B% ^3 b2 B
break;& m7 l$ C0 r$ \1 G7 B" P
}4 J2 Y5 w) m" q3 i$ }4 U6 y( H! @- Q
case FR_DENIED://The directory cannot be created due to directory table or disk is full. 3 x. S+ l* W- n" y# K- i0 p
{( ^6 D0 R; g" z! c6 o
printf("\r\nThe directory cannot be created due to directory table or disk is full!\r\n"); + ~, L! }* m D3 l0 F0 ?" T break; ) ?5 X% J& T8 y. `, ~ }% G8 P p4 }( i# c s* Q
case FR_EXIST://A file or directory that has same name is already existing$ S, O! {& @) ~# b) n( x
{6 L- p1 I9 c+ G( |6 C6 h
printf("\r\nA file or directory that has same name is already existing!\r\n");5 [8 V/ r& Q: B! z, \! z3 p
break;* A. ^; j' h5 l3 ^9 H: F u
}# ]1 [9 t6 d4 n: u- [/ ^
// case FR_RW_ERROR://The function failed due to a disk error or an internal error0 C6 k- f* H( c1 Z, i
/*9 i/ h( q4 ]& r5 {0 _6 x9 @( ?
case FR_RW_ERROR://The function failed due to a disk error or an internal error- o5 Y. S3 L& M' X1 ~* c; c/ H
{ ; R6 r# g$ a7 v" t printp("\r\nThe function failed due to a disk error or an internal error!\r\n"); + h- s" {8 D1 Z7 @ i break; % c9 `7 ^" m6 F: T5 A } 0 }, I* V6 S9 z6 O. d*/4 Y. e+ x+ S8 ]$ S* M
case FR_WRITE_PROTECTED://The medium is write protected / N8 c5 |6 ^/ b2 l1 }0 p3 ^- p { & G: O8 s) t; W9 k t printf("\r\nThe medium is write protected!\r\n"); K& _1 \/ U8 e8 B& ] break; 2 v. E# s1 b: y0 N) B( q" p } 8 S; B% h, D9 j0 Y* C case FR_NOT_ENABLED://The logical drive has no work area, W/ V/ r6 p( x; w/ ^) ~
{% t+ h- R0 P( {$ p
printf("\r\nThe logical drive has no work area!\r\n"); : Z& f; H" E5 Y) a$ Y break;$ ?1 I' O# G5 i% E* r' r( e
}1 l0 p. ?3 b; c f
case FR_NO_FILESYSTEM://There is no valid FAT partition on the disk " Q$ T; D+ [% t, a6 ? {7 R( }. a( j' W3 `/ ^% A* j
printf("\r\nThere is no valid FAT partition on the disk!\r\n");& r% J6 w$ ]9 g, [6 Z0 K
break;2 a. G6 l: E* O Q
}2 T( x) H! g+ Y/ f7 Z
case FR_INVALID_OBJECT://The file object is invalid" v1 y' @, q; q
{! D8 w& }" y$ \, j
printf("\r\nThe file object is invalid!\r\n"); & E, D) |2 U+ q$ N break; . q& j' ~$ u7 e8 l% q }+ H' F0 s$ H) A. P+ Y
' D) _8 c: v' a$ q
//The function aborted before start in format due to a reason as follows. 8 P0 x5 ^) R1 ^0 J$ B% T N
//The disk size is too small. , c% q1 A {' L% D! i. U0 z //Invalid parameter was given to any parameter. % a$ u3 b b$ U% ?+ q$ q //Not allowable cluster size for this drive. This can occure when number of clusters becomes around 0xFF7 and 0xFFF7. , p- ~7 O- |- ^: s6 M) E6 M G& H case FR_MKFS_ABORTED:// - j* U1 T/ s* {$ F( f7 E E2 v8 l {. ^6 K+ e* [( @2 p
printf("\r\nThe function aborted before start in format!\r\n");, ^/ [9 z7 V9 X( s* s. H3 ]
break;& t4 w/ v1 H# {1 `; ?, H
}5 [1 g( B9 A% P
1 s8 }' N5 a3 y
default:! A q; y& |( u& V: I1 C5 v5 ^
{ # m0 l. P8 M# L6 T* ? printf("\r\nerror!\r\n"); , ^# o0 c& z* C! P( |4 t break;. V9 l) a& \ Q* U
} ; o0 c+ d4 \+ k" a! n) c } & ~0 {5 ^$ o( `" q6 R return;( S2 H2 S {3 H5 B* z, S2 f6 }( g, ]$ J1 m
}! ]% k$ a, ?- R2 v' y
void Test_f_getfree(void)//获取卡的总容量及剩余容量7 }! m A B" [/ [6 }5 p0 g
{ ! }5 \- q& i4 h: v FATFS fs; 2 f6 F# t6 k/ M FATFS *pfs; Y& q$ ^' K0 H& f: | DWORD clust; 4 ]4 x! v3 k' O7 ~5 h FRESULT res; // FatFs function common result code $ {1 x. K d g& p* r# ~! f8 B' \0 q0 ~# p& v3 s. J( B: }6 v _) g
//检测磁盘是否插好: P9 j* a: r& N/ x0 g, M
if( disk_detect_OK()==FALSE ) return;6 ^: w7 Z' H6 ~5 `" D4 z% X
1 Z, a/ h! z0 r# A B pfs=&fs;//指向0 \* Y9 H. P1 Z( N5 |
// Register a work area for logical drive 0 ( w& H% {- }4 M6 N2 Z f_mount(0, &fs);//安装FATFS,就是给FATFS分配空间 5 Z N( D( b- V7 l4 e' J, Z' I- B6 ?. ~" \9 ] J* i1 ~& P7 |5 y
// Get free clusters5 t9 S5 n& \' s& `- c! H
res = f_getfree("/", &clust, &pfs);//必须是根目录,默认磁盘0;"/"或者"0:/", Z5 J0 P# o5 z0 N" w" |- }3 c
if ( res==FR_OK ) 1 `( \) i9 P& Q) C
{ % x/ \' ~6 _, D. C- x l6 @: i) I // Get free space 3 `: P; p4 z" d. u' U printf("\r\n%d MB total disk space.\r\n%d MB available on the disk.\r\n", - J9 n5 S0 G, ~4 `# l ]. e (DWORD)(pfs->n_fatent - 2) * pfs->csize /2/1024,//总的磁盘空间M =(总簇数-2)*每簇的扇区数/2/1024=可用簇数*每簇的扇区数/2/1024+ f* G& F1 ` {7 c; K, t
clust * pfs->csize /2/1024);//空闲的磁盘空间M=剩余簇数*每簇的扇区数/2/1024( l' w0 H( G1 \
} 2 t1 h5 U) o/ u8 C( ] else die(res);//测试函数执行结果分析- m+ S4 c% u/ P3 u" Q8 O4 Q+ G& b n4 n
1 B# `: q5 {) |. K W+ _, ?7 |
// Unregister a work area before discard it # g- X' G3 ~8 g3 m( y* z f_mount(0, NULL);//卸载FATFS,就是释放FATFS结构体所占空间 0 y0 x; ]0 b5 }. G4 ]% _+ h} & K% b7 @9 A& Z) o | : I4 T& [1 u+ W3 mvoid Test_f_read(void)//读文件的数据,如果没有此文件则返回错误& n5 `& Q4 q4 {/ B! V8 u' `* F7 |
{& f* r/ C% M T8 ^
FATFS fs; // Work area (file system object) for logical drive 2 B# B; m& W/ z/ r FIL fsrc; // file objects" C7 ?; e9 y7 f) G, C7 E+ J6 G0 r% ~
BYTE buffer[512]; // file copy buffer$ g2 H+ y2 Y, e' }
FRESULT res; // FatFs function common result code- R# u" \) ]: d. Z
UINT br; // File R count 2 h: B# y' U# y; X! H5 z# H; g u16 i; : {4 b7 a4 V/ o$ L- X' k( q 1 n& u0 Y7 b0 p: z' W3 ]0 d
: r8 i4 I- n7 A& u2 H) p8 [
char path[20];7 W6 m+ E$ K6 Y# P) k3 T
" D; M) r4 S' u. L0 h //检测磁盘是否插好6 ?0 D3 s7 {; j6 s+ \( D: r: {
if( disk_detect_OK()==FALSE ) return;7 [0 [) J" e! _5 c; D7 e
+ j/ R5 M4 G- U5 ] // Register a work area for logical drive 0 , \- M c. Y* l" K& Y' W/ D f_mount(0, &fs); / K) W9 L/ P, p0 D( q. r " u, w( w \' {9 a- J2 V2 Z$ M5 ? printf("\r\nread file:>"); * T/ W4 h3 z8 k; x4 r USART_Scanf_Name(path);//通过串口输入文件路径名/dir/file.txt或者0:dir/file.txt或者0:/dir/file.txt 8 E3 W+ g3 F: x$ H; F $ U3 x/ U/ r. C- L //Open source file8 O0 r+ D0 H! x" f
res = f_open(&fsrc, path, FA_OPEN_EXISTING | FA_READ);//打开存在的文件,如果没有则返回错误 1 m. T" ^/ Z2 E) f4 G9 {) p% F die(res);+ R% q; I6 U; C' R
" A9 P( o$ }& K5 k% Z4 u3 N //buffer空间设大一点,会提高读的速度。3 Y: t6 x+ ^5 D* p1 _* X( l9 ]
//如果文件实际大小512byte,0 C8 F4 C. e7 S* r" t
//设为buffer[512]时,只需要循坏一次,如果设为buffer[1],需要循坏512次。 ) d( ?- e) k( m: u9 h //下面两行主要是去除1s误差。6 ]4 ]! |8 `3 l, P! o( l3 Z
4 B. [! [ K0 q$ h% w8 Q) B for (;;) 3 m# B9 d! n: j, Q5 R" x {3 S( j$ o9 \& {- `
for(i=0;i<sizeof(buffer);i++) buffer[i]='\0';//清除缓存 + L3 ?$ @- f( | ' Z; j& q; i" H, Y2 C res = f_read(&fsrc, buffer, sizeof(buffer), &br);8 j) L8 r! L3 e5 Q" Y$ Y" Z9 r
if (res ||(br == 0)) break; // error or eof : o+ i' x D& G) w3 q5 n
2 L3 Z$ l' R' w' q# G3 U9 z y
printf("%s",buffer); 3 S# r1 v/ K' }9 s
}9 W7 _( I- ?$ h1 ?" u( |
9 D: p( P. ~0 a( e ) M' R0 k& f* X; S
// Close all files 7 G! _, D. }, q8 |3 r1 k f_close(&fsrc);& R1 Y0 I. F* B) G% O6 q- I6 r; o! O
// Unregister a work area before discard it& L, |' {% ?- j+ c7 U# K
f_mount(0, NULL); 7 E5 Y4 I4 R. b# I2 _} 5 E& i. w, E& g4 X2 m% g4 ?+ V+ A1 @% t1 j1 g
void Test_f_write(void)//写数据到文件,如果没有此文件则创建文件- R0 v% E V5 z
{ , }0 r/ \$ @$ ^: r0 ^/ Q2 w0 x FATFS fs; // Work area (file system object) for logical drive* w: \$ ] K9 s- Q+ D0 W
FRESULT res; // FatFs function common result code 6 m& H5 L' ^. \/ H+ e FIL Make_file; 9 f' ^8 t9 R) ]5 v char file_name[20];9 n# e9 n- J& i) z G7 l/ T+ B; n
char Storage_buffer[] ="0"; p7 t5 h3 O6 }! b/ i, j9 g
: R+ E% j6 M/ S6 r; n
UINT bw; 3 y9 M8 u5 g' Y* r0 u8 M //检测磁盘是否插好 / ?6 O' {5 t8 r! s% [ if( disk_detect_OK()==FALSE ) return; ]4 \$ I: c9 e' J2 c+ s9 r printf("\r\n inaert_ok:>"); ( L+ ~% H3 J$ \1 I W, D* Z" U // Register a work area for logical drive 04 W3 \* Z- z4 g* D% V
f_mount(0, &fs); " Z' O2 R7 K9 j9 b9 S/ k' b$ [* L! |: M" H: ^8 M) } {
printf("\r\n Make file Name:>"); ) ~/ n0 D9 u$ X9 S0 \6 ^3 n* N USART_Scanf_Name(file_name);//通过串口输入源文件路径名/dir/file.txt或者0:dir/file.txt或者0:/dir/file.txt : s( W4 ]$ `5 G* ^" n9 Z* c$ D/ j- u4 z9 s* b
res = f_open(&Make_file, file_name, FA_OPEN_ALWAYS | FA_WRITE); //可写方式打开 没有文件则创建 ( k. e" j) K. X2 ~9 |& L0 _ printf("\r\n open_ok:>"); + T: x2 V3 l- x g; k: r9 Z die(res);" e7 i% \# F7 E) ?0 ]- h
res = f_lseek(&Make_file, Make_file.fsize); //指针移到文件最后 8 ^! }; ]; g7 X ^( S# ? printf("\r\n seek_ok:>"); 6 y8 c( `# v# U" l' g6 A$ p* X8 }3 l die(res);6 P/ t& v: e) c! u
res = f_write(&Make_file, Storage_buffer, (sizeof (Storage_buffer))-1 , &bw); //每次需要写入的数据字节数,去掉最后的\0所以-1 1 }3 |9 O5 @1 p8 f9 }
printf("\r\n write_ok:>");2 C; q! L, H" i$ y F" u
die(res);+ [: c0 J! P/ a8 l/ _
res = f_lseek(&Make_file, Make_file.fsize); //指针移到文件最后 7 x& G, g6 `- {% T" n
f_close(&Make_file);//关闭文件. ^" G3 r6 F2 c( q, e7 @/ Y9 O
printf("\r\n close_ok:>");, ^' @) z9 A& \3 J9 ?+ ]
2 T8 C9 X) K# E4 ^4 o: t% |# ?- R printf("\r\n写文件测试OK!\r\n");0 k* v6 w' ^: E; Y
1 j- T7 t8 j' l: F1 F8 c
// Unregister a work area before discard it1 d9 `8 M8 Z r" e7 L
f_mount(0, NULL); 9 E+ `) i1 K% s' K! J# Y1 F! [}0 M9 q2 {: v/ e) s
9 z/ j! q% M- c' x0 V; [/ ?! o
//The f_read function reads data from a file. 6 v( k9 S+ O* l! v, d# k- [//在RAM里面调试这个程序的时候,总出现莫名其妙的错误,最后怀疑是堆寨溢出了,证明果然是这样6 W. I) U6 |% O1 C* a, P0 b
//把Stack_Size EQU 0x00000400 改为 Stack_Size EQU 0x00000800就正常了* \+ I. a% W- b C& m
//所以以后要特别注意这个问题。" v* L5 L" R" j) l M- r( @% \