你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

如何制作一个读取U盘文件系统的工程

[复制链接]
aimejia 发布时间:2018-5-29 10:25
本帖最后由 aimejia 于 2018-5-29 10:27 编辑
# T. \4 j& B+ }% O' t  I9 v5 R% R
9 P" p  m' y* ~3 ?7 J. Q6 a1 前言
0 c- p, c6 n1 s, U; ]# v. D% W本文介绍基于CubeMx如何创建一个读取U盘的工程,并通过FAT32文件系统创建和读取文件。
' R" a/ M- _3 k/ B  _; E2 G1 @5 I6 b) v7 a1 i
2 创建工程
: h6 ^. j, J5 ]- F0 x' m( I读取U盘的程序在实际项目中经常会用到,这里我们基于STM3240G-EVAL评估板来示例如何创建一个读取U盘的程序。
& E. @$ r; U' q3 ]9 s; @( ]
% |4 o7 n; G% e. b, o4 s6 e0 p在这个示例中,我们将通过一个按键来触发文件的读写。
' ~5 S9 W! e; A* H. z+ Y) [0 P( C* f) m
2.1 硬件介绍' @( u% Y3 c1 M5 L# S- G
在正式创建工程之前,我们首先非常必要了解STM3240G-EVAL评估板相关的电路设计。 , b& H, J& p8 q6 n/ u6 T4 a, z
STM3240G-EVAL使用25M外部HSE,USB相关电路如下:
! Q  `" ?4 B- m8 Y# r- aUSB电路3 x; M8 \. ~) \( r0 c1 r

: t% i* g- m" F8 m% h- i3 D+ A7 P. z
1.png

6 ?) Z5 d8 ?: ]8 ~( n, Z, u
图1 USB电路
如上图所示,MCU通过PH5管脚来控制外部U盘的VBUS,低电平为使能。 4 H2 h, J) C' D+ Z
按键相关电路如下:
; Z' `4 Z8 e  i2 l按键相关电路
% ]- R4 I% z5 h9 O  Q) T$ U2 {
9 D% `+ Q, _  d/ H' Z3 J: i
2.png
. U" b" H& h8 N
图2 按键相关电路
2.2 创建CubeMx工程8 }, ~4 z2 a# W9 v( T4 _+ q! S7 c
STM3240G-EVAL评估板使用的是STM32F407IGH6,因此创建对应的CubeMx工程,在pingout页面中使能USB_OTG_FS外设,并设置为Host_Only:
/ n8 t9 n' ~; q. W0 V! [USB_OTG_FS设置为主机模式
3 O& P% R( O1 _& M3 r- m/ e# }
- Y7 C) l' Q+ [! w2 F( A
3.png

, u& K) \, r5 |( g
图3 USB_OTG_FS设置为主机模式
并见PH5设置为GPIO_Output模式,用作使能VBUS。同时将PH15设置为外部中断,检测下降沿。
* H3 b2 }( x) G0 e3 t; X9 J2 z( ? pinout分布
. r6 O* u4 r+ p; O- k) J; L- b  A) M+ P
4.png

- j7 q  ~) K* l1 E3 C
图4 pinout分布
时钟树方面外部25M HSE,主频设置为168M,USB时钟48M,如下所示: 6 K2 P- x$ K; k
时钟树设置
& V- A+ R/ E& h% w1 r9 R' L& S$ V8 [1 I. j, n
5.png

0 `! G. R! [+ |& }7 e; L
图5 时钟树设置
在配置方面,HAL层GPIO基本没有什么特殊,记得外部中断使用检测下降沿,这个是使用在按键中:
) \+ `' z# Y. t" O0 d按键检测外部中断
6 Y9 z6 Z* _  E- D, w- }* v0 z+ F- O- y! O
6.png
3 Z# z/ r" E1 X2 F/ \9 |- S3 [. ]& P
图6 按键检测外部中断
在NVIC中,一定要将USB的中断优先级高于按键中断,否则U盘不能正常读取。这里USB中断优先级设置为1,而外部中断15设置为5,如下图所示:
* t' T( n2 M' x中断优先级配置1 w3 k8 ], Q8 @
/ H" g3 t; U# c6 O5 y6 q
7.png
; n. _9 b( j+ R/ }, ^; k, F) U7 u  r) a
图7 中断优先级配置
同时为USB选上MSC类,且勾上使用USB disk FAT文件系统: 4 h3 g6 R. }: S/ F( V1 t( c# z
USB MSC类和FAT文件系统
2 I' X- I( Q  x" K/ I
& l- X5 }& N: y
8.png
+ D! k0 m5 e& R1 [! ?
图8 USB MSC类和FAT文件系统
中间件配置方面,其实可以使用默认,不过我们还是修改部分参数。 3 P7 v& ~+ G: l7 y
在文件系统配置方面:
, J9 w" u1 b+ R: k7 y文件系统参数配置" r' W; k% {" X( J6 h1 n! l& ^! D
( e) Q' [0 [! I/ t: E- j2 b* ~% N
9.png
) W$ w4 O# q$ e
图9 文件系统参数配置
我们只是简单地将其配置成支持中文,并支持长文件名。 8 g9 S, Q7 s) B/ i" G0 f
最后,将栈和堆的空间大小都设置为2K:   C' o# o7 V/ j% d2 F2 J
堆栈大小设置" y: Y  O6 X( H% c
, Q) d) v  `3 v, P9 i% A# b8 i
10.png

2 A" W9 g. V2 b7 C$ q1 u1 m
图10 堆栈大小设置
OK,接下来就可以生成工程了。4 ]1 h; Y- Y* D' t) n
; N: q; g0 z# _0 V" v( \
2.3 代码修改- X1 y* S8 N1 w  z
在生成的代码中,首先我们对main函数进行修改,在main函数中我们需要做的工作主要有以下几件:1 C1 P' B# k' j+ M  n- [

/ n0 P( b1 @' y# x0 {完成系统初始化2 y; L% ?4 G- Z  ]4 O
使能VBUS
& \* j" j* f' w: t; @3 B+ L1 X当检测到插入U盘时挂载文件系统( _5 c+ i% S: R" Y, ^! N
当检测到U盘拔出时,卸载文件系统
2 B- g$ e/ i% h/ E2 P$ _6 y于是main函数如下所示:( w7 p* ?- }- ~- Q0 G
  1. int main(void)$ L6 k# Y4 O% h/ w
  2. {6 }2 R5 N# Z: }! s% I+ l* [. d
  3.   /* USER CODE BEGIN 1 */
    : b5 x2 D- M4 \$ @$ M* |
  4. static ApplicationTypeDef pre_state = APPLICATION_IDLE;* f% ?( f- K1 q: j) D/ Y
  5.    FATFS fs;
    ' {& j0 ?* P0 r1 T
  6.   /* USER CODE END 1 */
    $ l2 B- [& K# O% G' v0 x6 H! i1 n
  7.   /* MCU Configuration----------------------------------------------------------*/
    ' @  N8 t, M: B# F
  8.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    2 n8 U  w5 p' G+ S3 H
  9.   HAL_Init();& x" j9 J$ Q4 y- U0 \5 e
  10.   /* Configure the system clock */
    3 d7 z" `) G2 D" j9 K
  11.   SystemClock_Config();
    - J$ P9 N% R; Z6 i: ?+ Z4 T
  12.   /* Initialize all configured peripherals */
    / ?! T; n' k; i. t: q7 M" x
  13.   MX_GPIO_Init();' `# g) k7 a) ~+ c& x7 r5 [
  14.   MX_FATFS_Init();
    ' k; U6 x1 t. ?+ Y: d, V1 i2 O
  15.   MX_USB_HOST_Init();
    5 G, ^8 N( {2 x" c
  16.   /* USER CODE BEGIN 2 */
    7 ?% H" i) f- F
  17. HAL_GPIO_WritePin(GPIOH, GPIO_PIN_5, GPIO_PIN_RESET);//enable usb VBUS
    ' N* W- |. u- \9 e; c9 w0 G
  18.   /* USER CODE END 2 */! w# W0 s0 w! P" S/ N* q
  19.   /* Infinite loop */; Q& ^/ Y. \+ f* @; T
  20. /* USER CODE BEGIN WHILE */6 ?2 U# w; _8 p* e! a; C
  21.   while (1)
    , ]/ ?$ M7 b( n; `$ O6 C
  22.   {+ F9 k$ l% y* |
  23.   /* USER CODE END WHILE */& |4 z- K8 p5 X+ b7 E! }% C1 ]" \
  24.     MX_USB_HOST_Process();
    - r' j3 c( W1 T+ c" H: j
  25.   /* USER CODE BEGIN 3 */
    ' [3 ^& u6 c$ B8 O
  26.     if (pre_state != Appli_state)
    ) Z$ S0 i4 x3 C
  27.     {
    9 H* F5 M; z6 z, @+ G1 v
  28.         switch(Appli_state)2 v* H! y+ K/ ~3 ~) O& U7 A
  29.         {$ e" U" m1 j( ~) _& d* Z1 S# I
  30.             case APPLICATION_DISCONNECT: //USB flash disk remove
      L+ W7 {, d4 F( a
  31.                 /* Register the file system object to the FatFs module */" f" M' u1 ?! m2 q
  32.                 if(f_mount(NULL, "", 0) != FR_OK)) _% t( G8 b) H" X$ w# ]
  33.                 {
    - H: i: N: N4 c4 u+ w* O3 |
  34.                     USBH_UsrLog("ERROR : Cannot exit FatFs! \n");
    . ?! s/ ]4 k: b& n) q+ l% p6 i! z- ^
  35.                 }
      m' \  {) d6 x+ v
  36.                 break;) Q- L- q$ h/ ]+ O# Q8 z
  37.             case APPLICATION_READY:   //USB flash disk plugin
    + \0 v8 @+ `2 O; Q: X% \
  38.                 /* Open or create a log file and ready to append */, o, A/ K1 r" G4 W1 J- W4 y' Y3 R
  39.                 if(f_mount(&fs, "", 0) != FR_OK)
    ) O2 w% b8 A; g# G
  40.                 {
      S1 ]" z& T. N# z' u7 V" C
  41.                     break;/ q8 M: j2 e% ^- {4 o" ]6 M
  42.                 }) w) ]  n/ [# R& r
  43.                 break;0 m/ I2 c4 x8 ~$ J. J1 V
  44.             default:
    7 o+ H+ Y2 h7 ?+ h
  45.                 break;) w  ]' y  x( z0 h" d
  46.             }  f) A$ P+ C% @4 I
  47.         }9 I' Q: F) `+ R( X4 @
  48.         pre_state = Appli_state;
    & \5 J7 {6 ^' Z5 I2 O4 U" M+ e7 i
  49.   }
    * N" [" G) d* y( t
  50.   /* USER CODE END 3 */" b3 n5 ~. B- M. ?! K/ c1 d
  51. }
复制代码
如上代码,程序通过拉低PH5管脚来使能VBUS。使用使用一个静态的局部变量pre_state来记录之前的U盘拔插状态,用以跟踪U盘的连接状态,当U盘插入时,立即挂载文件系统。当检测到U盘拔出时则卸载文件系统。( o5 S2 n/ A+ e+ I# E3 Q+ B

- D1 d! j5 ~. ^0 u' A6 i& d接下来看按键中断处理,这里,我们在按键中断中分别做3次测试,写文件测试,和文件扫描测试 :
) y9 d) f, c* O+ ?  I
  1. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    * C3 s/ [5 ]3 m- y3 L/ `
  2. {1 O9 _. C7 g. h) Q
  3.     static uint8_t step =0;. B% p6 i# h) Y2 X! t& l8 J% M
  4.     if(USBH_MSC_IsReady(&hUsbHostFS))
    ' b  Y7 A" c! O* ?
  5.     {: M6 _- l$ C: L% U
  6.         switch(step ++)4 h( _, g1 L; m3 @2 p4 U% |( O8 y
  7.         {
    ! L4 t% m, K7 W! C& y& w! j8 D8 [
  8.         case 0:7 L- N, D9 k+ D& d8 L* K. k& `
  9.             writefile_test(); //写文件测试& X- b% b- G+ A3 e& w
  10.             break;
    ; l6 [$ R) e/ d2 X
  11.         case 1:
    * w. d7 |. ^" W0 ]/ c
  12.             readfile_test();    //读文件测试4 R1 b& \+ j, j
  13.             break;
    " z! A7 u* S1 @( O
  14.         case 2:) k, `2 Y. r7 R8 |+ a6 d2 Q
  15.             Explore_Disk("0:/", 1); //文件扫描测试( g8 O1 Y- c- C  E: [
  16.             break;
    ! b4 |% S: k) m+ o7 B. C
  17.         default:7 n! D$ r5 X5 O/ K- ]
  18.             break;* x  j5 n! w7 Y. X# K
  19.         }8 [# [! g$ p; V) D/ U- h
  20.         if(step >2)2 H5 ~# G( ^3 r; _! Q, C9 B
  21.         {! n3 \, ]2 N4 h9 p
  22.             step =0;
    8 n5 t. t+ U, {7 R9 J7 F
  23.         }# n- A" D5 _5 }
  24.     }
    2 F  V3 ^3 \! g0 O/ c. o! P
  25.     else
    ) v0 V$ @2 M) E' Y, t, g! L( |9 F
  26.     {
    $ o4 c0 T. v6 {! i! u# F) v
  27.         USBH_UsrLog("USB Device is not ready.\n");
    ) W3 _7 N) C  @
  28.     }
    + |3 a8 J* W% k, L& Y
  29. }
复制代码
文件扫面测试,写问津测试,读文件测试:
  1. FRESULT Explore_Disk(char *path, uint8_t recu_level)- }7 E% @4 z) h$ b
  2. {6 `5 K+ Q/ t% p4 {! e$ h
  3.   FRESULT res = FR_OK;8 ~3 o! b! G5 o
  4.   FILINFO fno;0 ~& Z: T3 w9 d1 M' ]
  5.   DIR dir;
    ! Q, M; J7 I0 G
  6.   char *fn;
    , L! y, V/ Y' i; N9 S2 T* j
  7.   char tmp[14];
    7 l/ R* n. k3 Z. Z  A1 k4 X
  8.   uint8_t line_idx = 0;
      M& \3 ~  y4 j
  9. : j1 j9 [4 h# R
  10. #if _USE_LFN
    % [) Q4 R4 W6 u6 V8 e/ h% p
  11.   static char lfn[_MAX_LFN + 1];   /* Buffer to store the LFN */
    1 t  S+ \& j3 P8 h, G! m7 t
  12.   fno.lfname = lfn;
    / V; ?7 O* N2 t& u3 {$ {8 f' b5 }
  13.   fno.lfsize = sizeof lfn;2 S3 u$ @+ D" {4 Y' U+ c
  14. #endif  k1 ~9 e5 d9 w1 Z, a  r# B, W

  15. $ m0 @2 I+ t+ A* B
  16.   res = f_opendir(&dir, path);
    , N/ {  d% u1 U1 d! E
  17.   if(res == FR_OK)
    , P9 G3 t, Z; ^& H% m: ]9 \
  18.   {
    # i( h7 m' y9 Q6 T
  19.     while(USBH_MSC_IsReady(&hUsbHostFS))
    2 @% M* \% L5 R) H
  20.     {
    & m+ b+ f0 R# D5 h& V: P# F" _
  21.       res = f_readdir(&dir, &fno);, X& k0 ?8 [5 J1 y2 H, C+ n" ?+ @
  22.       if(res != FR_OK || fno.fname[0] == 0)
    7 p, d7 y8 Z! e7 D( _/ ]4 G
  23.       {5 P8 k+ @2 y  A, S# m6 t; X
  24.         break;) W9 b! J5 O+ W) A
  25.       }
    " P/ z# Y6 e# U/ f& v8 W
  26.       if(fno.fname[0] == '.')
    3 m. b. }6 z6 d+ Q6 c( R- a8 w7 B
  27.       {2 o, G. r5 i4 o1 t+ _; m
  28.         continue;6 j4 T! [1 M$ I( M) M+ Q- ~, o8 o8 _$ Y
  29.       }
    ! u7 l5 h1 x5 O% Z
  30. 4 x* T2 z2 ^) r- T" L  Y
  31. #if _USE_LFN
      `( Q/ j3 z- F# v$ {: r
  32.       fn = *fno.lfname ? fno.lfname : fno.fname;" _% ]* y8 R& i
  33. #else. Z3 H+ r% n; @, ~
  34.       fn = fno.fname;
    4 X# w$ X& r( ~
  35. #endif% i4 [1 Q( x/ D, T. s4 ~) M7 g
  36.       strcpy(tmp, fn);! R# b% @+ G, h5 O
  37. # V" k- s$ E% j% e& ~& j! b$ j9 m
  38.       line_idx++;
    / R; m; h% p5 P! q5 c! w1 f
  39.       if(line_idx > 9)$ |7 E$ t. A3 K6 r; q0 j3 a
  40.       {) [$ ~6 T7 [2 P" i& S
  41.         line_idx = 0;
    # k- d6 c; `; u
  42.       }3 {; J8 L" ^# J+ I1 q

  43. ) e- q" T- Q# P* F$ E
  44.       if(recu_level == 1)
    7 L! R: I5 o7 b9 F3 {, i
  45.       {- V% i# s) |( l1 l8 o* E- k6 e1 L
  46.         USBH_UsrLog("   |__");' K$ y8 J% o! ?$ G7 ?
  47.       }
    2 [3 Q) Z' n" H6 @
  48.       else if(recu_level == 2)) F4 X, L0 |/ F
  49.       {
    / `" y5 l5 f- s; c
  50.         USBH_UsrLog("   |   |__");/ U( p$ H5 `* k# q
  51.       }
    1 i1 A* h, C7 b
  52.       if((fno.fattrib & AM_MASK) == AM_DIR)0 [. p. C! ~& m4 l) {1 i
  53.       {
    . @& L; u3 ~3 Z
  54.         strcat(tmp, "\n");- P9 T. Y8 u9 _) j- t. L0 G
  55.         USBH_UsrLog((void *)tmp);' j; R4 W0 i9 N; p
  56.         Explore_Disk(fn, 2);" W$ X1 z6 w7 z6 |4 o/ }  K# y3 L
  57.       }- Z& Y: ?3 D( m- X6 y
  58.       else9 q4 x' S+ ]/ n4 b( f8 `. L
  59.       {
    8 r* [) P. }3 n4 s+ ^6 i4 a5 @
  60.         strcat(tmp, "\n");4 i" J) M; X- D9 [9 q, o
  61.         USBH_UsrLog((void *)tmp);$ S+ G6 E+ v) Z, U* `  Q2 r
  62.       }
    # v2 {: [4 S+ T/ P
  63. / ^. s% Z, i9 s1 r
  64.       if(((fno.fattrib & AM_MASK) == AM_DIR)&&(recu_level == 2))
    5 n" e6 W2 h( h' E
  65.       {9 e, L7 P/ q9 Z3 C, P- o1 C. l1 M
  66.         Explore_Disk(fn, 2);
    . Z$ u$ i) f/ t9 q$ V) w- n# B
  67.       }
    : v! M) B8 W8 d& D" _8 D" U
  68.     }! z. N& }) _7 x; S6 [6 p
  69.     f_closedir(&dir);; J. W5 Y  w7 E2 ?6 \2 K
  70.   }
    ) n4 o. U- n5 b1 q- p" S
  71.   return res;
    & E- K, l. @7 ]+ H+ o8 g" t4 o
  72. }
    * C4 w* L$ N2 {0 n& i& a& I
  73. void writefile_test(void)
    $ E5 C# n7 X  I& d0 X, \5 l" u
  74. {6 Z  D, D5 c# |( ^/ i( L
  75.     FIL fil;) Z$ f% z  V  V/ a% m- @7 }3 U
  76.     FRESULT fr;9 e4 X8 L3 i, T. ]1 D0 ]
  77. 9 I6 ]! Q4 Y0 Q0 H# ~' y9 B0 n
  78.     /* Opens an existing file. If not exist, creates a new file. */9 E# y  l/ I" B/ ^& ?+ f+ f4 N5 b
  79.     fr = f_open(&fil, "0:/mytest.txt", FA_READ | FA_WRITE | FA_CREATE_ALWAYS);
    - p, F5 p8 ?0 |" S4 l
  80.     if (fr != FR_OK)1 m7 F4 N6 g+ F: d" `5 b
  81.     {
    " @1 W: d2 q& R" i" I
  82.         return;3 @( H" U, F$ D/ b4 A
  83.     }
    ( f- w2 [* R. @5 z3 E- @( c( N
  84.     f_printf(&fil, "%s\n", "[USB]write txt OK!0123456789");6 K2 [6 L. s( M& X# c" }, r
  85. 8 F$ y& C7 I4 [/ B: l7 C, @
  86.     /* Close the file */
    : d3 Q5 U1 x, W+ m/ N1 ^( P: \& r
  87.     f_close(&fil);
    + r' D! d! R8 R
  88. }  k0 S" ?2 c  N8 p8 U
  89. void readfile_test(void)9 _* R2 ?2 Y$ [3 o7 P9 m4 E2 v$ I
  90. {
    8 N. r1 R$ l0 n3 d
  91.     FIL fil;  K+ g7 p/ s5 p# Y" ?  v" v
  92.     FRESULT fr;
    ! }; q& ]* s9 N( D" F
  93.     uint8_t buff[20];
    9 \  M' j6 H/ k2 e. M  r& P# P7 B
  94.     UINT off = 0;9 e; b: r, B5 u5 D9 @
  95. : K1 E8 N% m5 `( s
  96.     /* Opens an existing file. If not exist, creates a new file. */
    0 D, P! V4 m% g8 `& S1 X$ M
  97.     fr = f_open(&fil, "0:/mytest.txt", FA_READ);2 o- v5 F" f4 ?* B( l* N0 v! ]
  98.     if (fr != FR_OK)
    . ~. g3 N5 P7 l0 X
  99.     {- o+ f* W7 C9 Q  z/ E- ?7 {
  100.         return;, ?- B5 p0 |9 r0 y/ m7 O6 _
  101.     }
    ! a/ g, \- U% m8 i( J" |. T
  102. % {0 v  P: p* u# o
  103.     f_read(&fil, buff, 16, &off);" y+ Y: H% [, c) o& M
  104.     buff[16] = 0;2 m8 |$ z! h5 i
  105. 6 @! b9 t# D1 B0 j4 j
  106.     /* Close the file */) c7 j. l2 A1 R' x# g9 r# `
  107.     f_close(&fil);
    . T7 Y) h. [$ ?/ \3 M6 I. ?7 N
  108. }
复制代码
) ?5 x: A' ~" Z8 N% Q2 V
最后将U盘去下来插入到windows查看,可以正常考到测试文件mytest.txt文件,这证明结果是OK的。
  F/ E2 M+ L( N- A) G( J+ P
' u4 X; k9 Z5 w3 结论% q: `  h( P7 y8 b! _
按键的中断EXIT15的优先级一定不能过于USB的中断优先级,否则代码运行到操作文件的时候回卡死!
* g/ l$ B% W, U( I0 J
/ I; h1 m/ y9 [! c' S5 X/ N2 n通过CubeMx工具将一个比较复杂的读取文件系统工程大大简化的。
" _1 E$ B. Q5 h  y, g8 H9 v' C  X: r. G; n" Z  T# M# Q
: g- V1 ]7 l  {: a! v0 l

) Y5 K4 T+ l0 u  f4 @1 [转载自flydream0% m6 o( ]9 l5 Q; `' Q
2 b* f3 d' }0 {7 i; [8 D+ ^: y

: p7 @7 A! |) T4 |. \1 }& a
赞 收藏 2 评论0 发布时间:2018-5-29 10:25

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版