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

【经验分享】基于STM32使用HAL库实现USB组合设备CDC+MSC

[复制链接]
STMCU小助手 发布时间:2022-4-9 23:20
工程试验环境2 O2 V( x2 g# j+ e
STM32F103RC
% Q( |( b# N' S1 _0 I+ F# B0 T( uSTM32CUBEIDE1.5.15 @: D. T& _4 L: P
1、本教程默认你已经会使用STM32CUBEMX生成CDC代码和MSC代码,这两个工程的生成很简单,网络上的教程一搜遍地是。
1 A& r8 n2 R" F3 ?; t/ E
+ }7 F8 B: N: G9 S3 s1 ^8 q$ m2、USB组合设备的移植修改需要具备一定的USB知识储备,如果没有强烈建议看一下我的另一篇博客:STM32 USB相关知识扫盲
+ z+ C) j) R& r8 T8 V
" d/ J2 b3 o: Z5 h首先说一下STM32的USB库的初始化操作,MX_USB_DEVICE_Init函数中使用USBD_RegisterClass函数注册绑定了实际的端口初始化控制等操作,如果是CDC那么注册的就是USBD_CDC这个结构,如果是MSC那么就是注册的USB_MSC这个结构,所以我们的组合设备思路就是用哪个的时候,就将这个结构切换成对应的操作结构。
0 |" O" c5 c: W) m! f4 H; E9 X2 b% _% k
第一步:基础工程生成5 Y' `6 V1 l2 [' D2 s9 E. a4 I
首先先用STM32CUBEMX生成CDC的工程和MSC的工程,并测试通过没有问题后,我这里使用CDC工程为基础工程进行修改成USB组合设备。
! I. k# b  S: k" a$ r4 {$ J) M" I/ }2 v! ^5 L0 K
基本步骤如下:
, o6 s4 i& j% n% o. N" l, v$ Q$ }2 v( i
USB设备描述符修改成组合设备类型, l1 C  N( b# b1 t6 P: d2 L
修改PMA端点分布
9 F& n4 C& {3 T8 ~7 h" i修改USB配置描述符并添加MSC的配置描述: u9 U6 H0 I# H, O! ?8 R( ]
修改初始化函数接口,改写成我们自己的组合设备初始化操作函数
6 H" W5 \# Q  O" R: \  x# S1 S修改MX_USB_DEVICE_Init函数,注册成我们自己的组合设备. w  T9 B% i% \' B9 n6 T( e

# }  l+ v) h1 `
0 G) X. ^! }& Z' T& p3 Y下面进行分布修改。% A5 G. U: r) z3 P* a2 t+ Y
6 v* V) b& a3 E- g% |- D( j
第二步:USB设备描述符的修改8 o# c9 B1 }. C$ Y8 L' l
这一步很简单的,就是修改usbd_desc.c中的设备描述符数组USBD_FS_DeviceDesc,将设备类型改为组合设备类型:
3 @+ H8 x3 j- k- P0 b2 T2 f' J4 x4 o" g" g
J)4A6FO7U[S`S6NWUY9PT63.png ' Z, k$ b; E" o4 k- N3 D: d5 I! h

8 Y% y) G0 v+ y7 J: O第三步:修改PMA端点分布

1 d! d! n! }2 ^; Z& \首先修改一下CDC所用到的端点地址,CDC的输入输出端点不动,将命令端点成0X83:3 Q4 J* K6 V* h& C) ]1 I* x$ Y
( j6 ?. p& H4 R  N2 p

, U+ s. |2 ~. K 2HX(T@W6WV[XTC]MD)OVTS2.png
/ t! O9 y( P3 T; R# g$ e8 d9 m
/ A: S8 u, m/ A& j然后进入usbd_conf.c文件中,找到USBD_LL_Init函数,修改PMA端点初始化:
4 b$ O7 U5 J2 \6 I; ]" g5 t7 c+ _* ~% ^
XEC{)J[~_964X[7EHLIV7.png & Q: O% J" Z7 U; S/ H  W; A

( v+ Q1 T' X& F4 I: m这里的修改非常关键,为什么addr要从0X38开始呢?
9 `# Y+ ]2 X+ ]1 o! E
' F/ {9 V7 @# {# R) |" D因为我们目前用到了:/ }+ d4 r! X7 o9 ]7 r% V

5 P- k3 r3 e$ n$ R默认的两个端点(0X80、0X00)
$ _8 O* h7 _3 E2 @! }0 M# wCDC的三个端点(0X81、0X01、0X83). n) H, I5 ]* `, v( y; o
MSC的两个端点(0X82、0X02)' P+ _, p# P& f8 ~: b7 o
! E1 Q: W6 U; f% X
  o! p( J8 Q3 L
共7个端点,每个端点占用8字节,总共56字节,十六进制就是0X38!% f0 d; i2 q- w5 W" {+ M

* C, E3 ^) l6 M7 ~6 p好多人修改自己的USB应用时,就是卡在了这里!如果起始地址修改不对,那么USB端点缓冲就会覆盖PMA头部的端点描述!
$ O* J, \0 N; e# O7 t' l5 K* r% c
  Y5 h9 B& m$ }4 u* V1 h9 J! J有关PMA的详细描述及使用,请看文档头部的《STM32 USB相关知识扫盲》链接文章!- M* A% f7 n, I6 s
, ]0 |1 J, p& c
第四步:编写我们自己的组合设备配置
* F, V% o, n; O0 c+ B$ T  ?& o这里我为了方便修改,新建了一个usbd_composite.c文件,用于编写组合设备驱动,文件内容如下:
1 S2 g* v- f/ [) C
8 K' r& c! |3 V$ r# C# G
  1. #include "usbd_def.h"  h8 n8 M! Y5 x* R+ o) g9 @& I* u
  2. #include "usbd_msc.h"
    * V" m% ~$ R- B
  3. #include "usbd_cdc.h"
    ( ~5 C7 ^, C* o' v$ h5 d
  4. #include "usbd_storage_if.h"
    ; `+ t( `. g1 b
  5. #include "usbd_cdc_if.h": a3 r) ~5 s* W/ {+ c) U

  6. % y! a% D- b/ B9 g. U) @
  7. 0 e$ M1 g8 I, c* P
  8. #define USB_MC_CONFIG_DESC_SIZ 106: f( H" W, n8 T3 M

  9. * D) L7 n$ z/ S1 E* g+ Y
  10. ; z3 O6 w9 l' ^7 Q# h; X
  11. extern USBD_HandleTypeDef hUsbDeviceFS;4 y6 e7 s- c# E

  12. * \) I) q4 `/ y9 x- n. W. |" E
  13. * n$ K0 v6 t5 B2 r9 x$ _* \8 t
  14. extern uint8_t USBD_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
    & t, i! s: q. a# L2 N' a8 c
  15. extern uint8_t USBD_MSC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
    $ ?& N1 l! S- w2 v
  16. extern uint8_t  USBD_MSC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);0 M  J: Z- A$ A6 i9 F$ D3 [
  17. extern uint8_t USBD_MSC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
    1 D5 A, T+ \/ Y2 i8 m2 Q; }
  18. extern uint8_t USBD_MSC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
    , j" B6 b/ D9 u/ g! U

  19.   E  B! c! y4 M) U3 B0 T
  20. $ ^' v" S3 X2 h8 e& [
  21. extern uint8_t  USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);2 Y. ~5 R9 d8 Y; Z4 j
  22. extern uint8_t  USBD_CDC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
    ( N, c" I( u  j3 u7 ?* z: i( q2 d2 C
  23. extern uint8_t  USBD_CDC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
    , Q- L4 X2 t* G$ A: }+ Y: m3 V
  24. extern uint8_t  USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);3 ~9 H& N: @: o3 J$ [
  25. extern uint8_t  USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
    8 I5 d1 e/ E6 z5 b* T
  26. extern uint8_t  USBD_CDC_EP0_RxReady(USBD_HandleTypeDef *pdev);+ X* B1 f$ v/ v( X, @8 ]) ]" l
  27. & o- t  X9 q  l

  28. : ?) R" y$ N2 i- D3 X$ x  y5 q
  29. static uint8_t  USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);4 ]9 O/ l0 w7 n5 B2 m2 d
  30. static uint8_t  USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
    , G2 p( c* B. N" [
  31. static uint8_t  USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);- @4 \& x5 s7 @) a9 a& m
  32. static uint8_t  USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);" g8 e+ q' O2 H' x0 F2 I
  33. static uint8_t  USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
    ( D! [0 Q. F! {) ~" M$ N
  34. static uint8_t  *USBD_Composite_GetHSCfgDesc (uint16_t *length);6 L. k, y  V! d# k
  35. static uint8_t  *USBD_Composite_GetFSCfgDesc (uint16_t *length);
    / X! {% o  V3 y5 r2 t% c7 G
  36. static uint8_t  *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length);  d6 A* q: k7 ^" p  K+ Z& n
  37. static uint8_t  *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);
    3 L/ P& C0 o; ~
  38. static uint8_t USBD_Composite_RxReady (USBD_HandleTypeDef *pdev);" @3 w7 C$ y, x3 ]/ K
  39. static void USBD_Composite_Switch_MSC(USBD_HandleTypeDef *pdev);# \; Y) A. Q) U, L2 Y3 v! q7 ?
  40. static void USBD_Composite_Switch_CDC(USBD_HandleTypeDef *pdev);! N& Q- `+ Z2 r

  41. % e  x; ^) t8 Y& I% s0 S, ^
  42. ; }8 I* u% `/ f/ E
  43. USBD_ClassTypeDef  USBD_Composite_CDC_MSC =5 C, u- i: [$ J4 }' {/ W0 j7 W
  44. {7 v* L9 [) {1 z. V6 g$ w
  45.   USBD_Composite_Init,
    & a0 W+ n* y* P/ U& J
  46.   USBD_Composite_DeInit,
    + {% m3 i! I- O. C
  47.   USBD_Composite_Setup,
    ; `+ ~* u0 V- p; G8 _+ l; D
  48.   NULL, /*EP0_TxSent*/  c; P0 `7 X" B% Y; k8 m
  49.   USBD_Composite_RxReady, /*EP0_RxReady*/
    ! D2 k. T" o! Q( Y
  50.   USBD_Composite_DataIn,
    $ Z) y# Y. u% g1 ^
  51.   USBD_Composite_DataOut," N/ D& A& b. D$ d
  52.   NULL, /*SOF */" m* h: B: H' @$ @4 D
  53.   NULL,
      F6 M& j1 b; N* I
  54.   NULL,3 g* b0 C" R- p2 r/ t
  55.   USBD_Composite_GetHSCfgDesc,
    ' ]0 P: h2 ^. S, h
  56.   USBD_Composite_GetFSCfgDesc,
    : ?" f# I  d" U/ \- g2 e9 ?  `
  57.   USBD_Composite_GetOtherSpeedCfgDesc,% V% @2 ~5 H7 |9 f. ]/ r% @
  58.   USBD_Composite_GetDeviceQualifierDescriptor,! Q, ~. R  l! k* I9 h
  59. };
    / V& G4 L0 x5 u! w( x
  60. 6 ~. V0 I8 R# B1 E$ w* l

  61. / g7 s% B. `8 J4 R
  62. /*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */) t& L0 A) F& g. ~$ \! l
  63. __ALIGN_BEGIN uint8_t USBD_Composite_CfgDesc[USB_MC_CONFIG_DESC_SIZ] __ALIGN_END =
    , X& W' |: N0 w% F
  64. {
    + b+ Z; i# v+ H: K4 [, D2 v4 [
  65.   /*Configuration Descriptor*/
      L9 x2 E) w% V& h
  66.   0x09,   /* bLength: Configuration Descriptor size */; J# q& k* `" C- H
  67.   USB_DESC_TYPE_CONFIGURATION,      /* bDescriptorType: Configuration *// P3 H: E: }/ v: q. n- y) e
  68.   USB_MC_CONFIG_DESC_SIZ,           /* wTotalLength:no of returned bytes */- R% Q% L( b& P; M
  69.   0x00,
    ' A& U" A: o! l( d
  70.   0x03,   /* bNumInterfaces: 3 interface */ /* +++lakun:CDC用了两个接口,MSC用了一个接口,所以是3 */
      b( r3 A% v4 }4 T4 l
  71.   0x01,   /* bConfigurationValue: Configuration value */( N7 f$ `  b+ s
  72.   0x00,   /* iConfiguration: Index of string descriptor describing the configuration */
    ; U: m4 T; X* J0 e# Z1 Y6 J
  73.   0xC0,   /* bmAttributes: self powered */# h5 Y* @& H' I5 h1 c+ C/ E( U- w
  74.   0x32,   /* MaxPower 0 mA */, A- g- M4 f5 b
  75. 2 n6 c. a. l" Q0 s; G1 |
  76.   /*---------------------------------------------------------------------------*/9 p6 ~+ i% R' K2 W' ^9 c; ^$ S

  77.   @+ }, {) I: R& z& F  N8 e
  78.   //2 P0 E- Y. b' b$ c6 u. e
  79.   // +++lakun: IAD(Interface Association Descriptor),用于指示CDC
    ' O! ]6 l4 R- ]  o1 t' t
  80.   //
    ! d) o: S1 [; ?
  81.   0X08,  // bLength: Interface Descriptor size,固定值7 Y7 A& b7 G0 w) F& b5 q* r
  82.   0X0B,  // bDescriptorType: IAD,固定值
    ( _- `# f3 a$ x( i1 I
  83.   0X00,  // bFirstInterface,第一个接口的起始序号,从0开始5 \/ k0 x% V- f; ]' K' _; L
  84.   0X02,  // bInterfaceCount,本IAD下的接口数量
    $ y6 K8 z$ j9 ]+ r
  85.   0X02,  // bFunctionClass: CDC,表明该IAD是一个CDC类型的设备
    0 m# M& ^3 g% `
  86.   0X02,  // bFunctionSubClass:子类型,默认即可+ @) l7 z# Q# }9 |) H
  87.   0X01,  // bFunctionProtocol:控制协议,默认即可: e9 {" s- @2 S: Q& E8 j
  88.   0X00,  // iFunction
      A2 E$ f9 J9 B: G- v

  89. ; V; e" l; x, z" k
  90.   /*Interface Descriptor */- p2 o4 N; l, W$ H  x4 z5 M) `4 u/ }
  91.   0x09,   /* bLength: Interface Descriptor size */) [1 m9 b/ n5 w# v
  92.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */
    * |( Q1 J, c. v7 f2 ?/ K
  93.   /* Interface descriptor type */
    - e( K0 W# v9 y' Z" K
  94.   0x00,   /* bInterfaceNumber: Number of Interface */                   /* +++lakun:接口编号  */
    ' ^) ^7 ^( W7 ~7 e1 D
  95.   0x00,   /* bAlternateSetting: Alternate setting */5 Z  E( \+ O& \) O% N2 Y# [6 i1 z* x
  96.   0x01,   /* bNumEndpoints: One endpoints used */' U  y3 S3 ?6 Q% R; v0 R
  97.   0x02,   /* bInterfaceClass: Communication Interface Class */          /* +++lakun:表明这是一个通信接口 */! T5 S6 e9 I+ g! {( U) Q* [
  98.   0x02,   /* bInterfaceSubClass: Abstract Control Model */" x2 R( F* ^" k' d
  99.   0x01,   /* bInterfaceProtocol: Common AT commands */1 M* h/ b2 |; X1 X$ C. t
  100.   0x00,   /* iInterface: */
    3 A" b( s7 C# ]& P+ ^4 O

  101. % _! C' ]' l% O$ R$ K% O: ^
  102.   /*Header Functional Descriptor*/
    & F0 W) S/ E1 y3 I1 \) g  ?
  103.   0x05,   /* bLength: Endpoint Descriptor size */4 p; n" d2 j- ^$ B' @5 t; {
  104.   0x24,   /* bDescriptorType: CS_INTERFACE */
    2 _# c% k5 H7 r* g
  105.   0x00,   /* bDescriptorSubtype: Header Func Desc */1 C7 o' Q4 g$ D; i+ V
  106.   0x10,   /* bcdCDC: spec release number */; Q7 W8 ~+ X7 W. Q( S' w: B
  107.   0x01,
    * @0 q* R- L) T' k' |9 E

  108. 7 E0 ^5 Y6 D- L1 s% X! @) x! {3 r2 ?
  109.   /*Call Management Functional Descriptor*/
    8 J* V! \- o) N4 n  G* j% S
  110.   0x05,   /* bFunctionLength */( G$ c9 d' i3 {" M
  111.   0x24,   /* bDescriptorType: CS_INTERFACE */' r& I. ]5 j5 p) e  p, `
  112.   0x01,   /* bDescriptorSubtype: Call Management Func Desc *// }5 G# ]4 W- D6 y# f
  113.   0x00,   /* bmCapabilities: D0+D1 */
    / g1 N; x0 V* P  j# c' z3 x  N
  114.   0x01,   /* bDataInterface: 1 */( l3 m6 V: r5 Y0 G
  115. 5 o) O; S0 c' ^5 A" u3 D3 ?
  116.   /*ACM Functional Descriptor*/" ]" Y( }/ \8 d6 t7 p* J/ g
  117.   0x04,   /* bFunctionLength */
    - Z$ p4 X. f. \4 `) @" y$ H5 z
  118.   0x24,   /* bDescriptorType: CS_INTERFACE */- x( W6 `7 }8 x! b8 v
  119.   0x02,   /* bDescriptorSubtype: Abstract Control Management desc */5 C/ _0 M6 E8 R+ L
  120.   0x02,   /* bmCapabilities */
      L7 _) O- X. B- t* Q
  121. * W0 M/ u3 f1 f& n7 H* L
  122.   /*Union Functional Descriptor*/
    9 e" g( r# Y/ Z0 }7 ?- `/ r, W; A
  123.   0x05,   /* bFunctionLength */
    % R1 ?; V) _- ^% Y0 F/ x3 L- W
  124.   0x24,   /* bDescriptorType: CS_INTERFACE */
    3 C' t1 `, f" [9 T  r' G4 o2 v
  125.   0x06,   /* bDescriptorSubtype: Union func desc */  R. N) b. J9 Q  D
  126.   0x00,   /* bMasterInterface: Communication class interface */           /* +++lakun:这里是用来指示CDC通信接口的编号的 */
    , `0 I% \1 D0 M' f8 i( H! C
  127.   0x01,   /* bSlaveInterface0: Data Class Interface */                    /* +++lakun:这里是用来指示CDC数据接口的编号的 */
    , c/ Z$ x2 c9 O% h% S- O2 o

  128. ! S: s- q2 b5 i0 F# M
  129.   /*Endpoint 2 Descriptor*/# O% c3 |" L3 y; R/ l* e
  130.   0x07,                           /* bLength: Endpoint Descriptor size */
    5 u* N; N* Q! A8 r2 @
  131.   USB_DESC_TYPE_ENDPOINT,   /* bDescriptorType: Endpoint */
    ! f2 q. @4 a! m( j  q; I5 B
  132.   CDC_CMD_EP,                     /* bEndpointAddress */
    # u+ B9 u; k& t' h- I0 u0 Q* X8 Y. Y
  133.   0x03,                           /* bmAttributes: Interrupt */6 G6 j3 y2 n% Z  _
  134.   LOBYTE(CDC_CMD_PACKET_SIZE),     /* wMaxPacketSize: */
    / u7 U: v" k7 W2 r7 q% P% Q4 }
  135.   HIBYTE(CDC_CMD_PACKET_SIZE),# ~% o/ J3 T- ?; ]" w) ?0 u
  136.   CDC_FS_BINTERVAL,                           /* bInterval: */0 v6 ~: [! N& s7 y
  137.   /*---------------------------------------------------------------------------*/
    2 m3 h/ I3 z. p( j
  138. ! ], t1 \$ d# l0 r
  139.   /*Data class interface descriptor*/: W( o% ]% m* \9 J+ i5 L3 [; I/ R
  140.   0x09,   /* bLength: Endpoint Descriptor size */" _6 F5 _7 X$ X: \7 b, d. H$ [" h
  141.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */& K* ?! H! k5 U4 m/ J
  142.   0x01,   /* bInterfaceNumber: Number of Interface */                     /* +++lakun:CDC数据接口的编号为1 */
    ( k, j' r2 F/ V- W) @& T
  143.   0x00,   /* bAlternateSetting: Alternate setting *// N* b& E  c2 P5 \3 p
  144.   0x02,   /* bNumEndpoints: Two endpoints used */- J: c' T  x. W9 v
  145.   0x0A,   /* bInterfaceClass: CDC */, N5 ^- I% Y! W$ ^& Q  F! A
  146.   0x00,   /* bInterfaceSubClass: */, a2 m6 {( |* d; m, A/ I0 s9 V
  147.   0x00,   /* bInterfaceProtocol: */- h& \+ p. T+ L! @- k
  148.   0x00,   /* iInterface: */
    , }5 |% K8 q  P
  149. 8 d* Q6 Q) e4 n0 _1 B' B% r
  150.   /*Endpoint OUT Descriptor*/1 z8 w0 ?) w5 K  W# A
  151.   0x07,   /* bLength: Endpoint Descriptor size */  c7 h) e* C3 B) g
  152.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
    ' r1 J4 K+ P$ H" ~
  153.   CDC_OUT_EP,                        /* bEndpointAddress */
    & t5 R0 ~- a* A% D, X- l
  154.   0x02,                              /* bmAttributes: Bulk */4 Z9 X1 y% b' u; Q3 ~9 s
  155.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
    : ~6 ?* m, P9 Z. T. p* P, \
  156.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
    ; A, s' b6 v4 G5 z) U& m
  157.   0x00,                              /* bInterval: ignore for Bulk transfer */
      Z/ f6 n0 ~: A+ k: ^% e- X' @

  158. % g) H' Y- J! o: d6 j
  159.   /*Endpoint IN Descriptor*/& y/ @. Y5 r# P5 U- P
  160.   0x07,   /* bLength: Endpoint Descriptor size */2 o& L( T5 ~0 [
  161.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
    . p- n! B: F$ W( C5 Z, r) I) S
  162.   CDC_IN_EP,                         /* bEndpointAddress */
      k% C: g! A0 @# D' b
  163.   0x02,                              /* bmAttributes: Bulk */
    2 J% |& B# |- {- c6 l6 q( K: @
  164.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
    2 X& M. W) Z2 V- x5 R
  165.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),5 X7 T3 T+ B# K2 k3 \
  166.   0x00,                               /* bInterval: ignore for Bulk transfer */! t$ }2 Z0 V0 ?

  167. ( V, @) q' n3 G3 H
  168.   //
      s: C5 N% n& u6 c6 L
  169.   // +++lakun: IAD(Interface Association Descriptor)
    3 o7 Q+ @5 D: d2 J8 l7 I  ?' y9 P
  170.   //+ U: ~1 S! \) D; h
  171.   0X08,  // bLength: Interface Descriptor size,固定值/ t7 S7 s6 V- n* s' n
  172.   0X0B,  // bDescriptorType: IAD,固定值/ \  f; L2 v, o- G
  173.   0X02,  // bFirstInterface,接口的起始序号(第0、1编号的接口用于CDC1,所以从2开始)+ r" j: b. N: E1 ^
  174.   0X01,  // bInterfaceCount,本IAD下的接口数量
    1 X7 \! e/ j$ `2 y( w% ?6 d
  175.   0X08,  // bFunctionClass: MSC,表明该IAD是一个MSC类型的设备
    1 k6 X/ s. b, R; B2 S
  176.   0X06,  // bFunctionSubClass:子类型,默认即可
    ! F, O. C0 i) c" H# D
  177.   0X50,  // bFunctionProtocol:控制协议,默认即可6 j6 j! k* o2 O9 A3 j
  178.   0X05,  // iFunction' x& Z2 g. w- p" ]' T
  179. - ~/ T1 O% y2 H
  180.   /********************  Mass Storage interface ********************/! L; r8 a: S5 U3 j3 E$ B- p5 N- `
  181.   0x09,   /* bLength: Interface Descriptor size */6 g2 Y4 u3 [3 _4 ^, M0 Z2 p% A
  182.   0x04,   /* bDescriptorType: */# o2 x2 W- _* T# ~- V+ z1 @! u
  183.   0x02,   /* bInterfaceNumber: Number of Interface */  /* +++lakun:第0和1编号的用给了CDC,所以MSC接口的编号从2开始 */0 z+ J! a. V! ]5 ]  u! H, E
  184.   0x00,   /* bAlternateSetting: Alternate setting */- ~- ~2 t5 [0 [" V% u) h. x7 p. h
  185.   0x02,   /* bNumEndpoints*/6 W! j; w& [, Z" a. F7 D3 a
  186.   0x08,   /* bInterfaceClass: MSC Class */
    5 b$ x( S$ O1 E  W& }
  187.   0x06,   /* bInterfaceSubClass : SCSI transparent*// j- X9 D- I+ V8 P7 d0 C0 i) x
  188.   0x50,   /* nInterfaceProtocol */
    5 v3 t0 x0 V: Y7 V, Q3 x
  189.   0x05,          /* iInterface: */
    7 `2 Z+ F. C  v$ V' j; k, }8 ~
  190.   /********************  Mass Storage Endpoints ********************/# |, }. H4 b  D, ^
  191.   0x07,   /*Endpoint descriptor length = 7*/. g( u, l; F/ u0 e9 _2 I& f
  192.   0x05,   /*Endpoint descriptor type *// Y9 H. w% N( \3 l6 P  t7 P% G1 Y# j
  193.   MSC_EPIN_ADDR,   /*Endpoint address (IN, address 1) */
    / i0 l6 T0 Q1 f8 B: E
  194.   0x02,   /*Bulk endpoint type */
    5 H* @3 ~/ G) E8 G; Y
  195.   LOBYTE(MSC_MAX_FS_PACKET),) f  S  ?8 d0 z: n! k. v
  196.   HIBYTE(MSC_MAX_FS_PACKET),
    , d* [) x1 Z- K
  197.   0x00,   /*Polling interval in milliseconds */
    - R7 S$ d4 y+ P9 v, t
  198. & |# c8 e/ n0 A" K( t* c/ r
  199.   0x07,   /*Endpoint descriptor length = 7 */
    ) v  N1 z9 q$ E3 h' W
  200.   0x05,   /*Endpoint descriptor type */: [1 M( t2 O$ h- f0 {" n
  201.   MSC_EPOUT_ADDR,   /*Endpoint address (OUT, address 1) */9 f, I/ j/ v! X& C
  202.   0x02,   /*Bulk endpoint type */
    , P% p1 l# J9 }& [0 V
  203.   LOBYTE(MSC_MAX_FS_PACKET),
    4 C) u, `; ~; Y, W# S
  204.   HIBYTE(MSC_MAX_FS_PACKET),. }8 n/ d& _! P* k  k1 X
  205.   0x00     /*Polling interval in milliseconds*/
    - b! G- S; C( K/ W8 }
  206. } ;" ^# k" i. ~# y6 W2 N% v: V+ E
  207. $ {6 o9 k* q0 _

  208. : F5 s- n7 W  Q
  209. /* USB Standard Device Descriptor *// o+ P/ j# y0 @8 ?' |$ ~0 [2 Z& ?, J8 _
  210. uint8_t USBD_Composite_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] =- C1 W- a/ z+ L' |) x
  211. {( F8 y$ p2 p! I
  212.   USB_LEN_DEV_QUALIFIER_DESC,* v3 o5 x" h& |
  213.   USB_DESC_TYPE_DEVICE_QUALIFIER,9 {+ v% K& L* _0 O& a5 X/ k
  214.   0x00,
    # G' k/ z) i% N( ]
  215.   0x02,
    * r7 e4 r  x/ N
  216.   0x00,7 m2 K7 }" E/ v. I# g( e  B' C
  217.   0x00,% d4 F# S' I5 f: R( y
  218.   0x00,  c- d, N- n$ i8 e2 n
  219.   0X40,
    % R( C1 e9 w/ t( ^/ j, y4 E
  220.   0x01,% C& ?( q  j5 ]
  221.   0x00,
    4 I1 T- e% Q7 n- c4 y  C3 b' {
  222. };
    & [& w( Q4 `% Q0 a
  223. 9 F4 R( L% v, O! ]
  224. & h8 O( E: C. C( I
  225. // 这个函数是修改的USBD_MSC_Init& }# a+ a1 o& K% @7 s8 s/ Q; K/ E
  226. static void USBD_Composite_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
    5 t" @+ N4 y3 E7 B# t" m
  227. {$ v1 x+ \" X! c5 @9 [
  228.         USBD_Composite_Switch_MSC(pdev);
    ' ^7 c' s( I. L0 ^2 v
  229. " s& Y# N' p7 M/ s
  230.         /* Open EP OUT */
    . j' Q0 W) Y( z  O7 W, k
  231.         USBD_LL_OpenEP(pdev, MSC_EPOUT_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET);9 m1 t1 f' m, y
  232.         pdev->ep_out[MSC_EPOUT_ADDR & 0xFU].is_used = 1U;1 N! N* Q7 H2 P0 e+ W* U( p9 i0 H. i

  233. 0 A3 x1 U' H% f  s3 g6 y* U. ?
  234.         /* Open EP IN */. r. H5 Z) S! t. l+ S; Q; W" i& B
  235.         USBD_LL_OpenEP(pdev, MSC_EPIN_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET);; {) a$ n: V4 }1 i2 f% N- @/ }
  236.         pdev->ep_in[MSC_EPIN_ADDR & 0xFU].is_used = 1U;, t# R; x5 K8 m" ^. [6 e4 n' b4 T
  237. / ]$ l  \* t& L, f2 w; y
  238.         /* Init the BOT  layer */9 C. m) g4 A/ P8 Z2 v+ Y+ l6 H0 i
  239.         MSC_BOT_Init(pdev);
    ! j# _" P. g$ ?' i2 o' X7 K
  240. }- O( _# X0 E3 T* n/ ^
  241. * k( V1 H. O( Z7 A
  242. // 这个函数是修改的USBD_CDC_Init2 ~1 ]# ?  j0 ~# Y* X$ @0 ^
  243. static void USBD_Composite_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)$ P* X! W  \  \. C% w
  244. {
    9 W6 F8 V4 q7 P
  245.         USBD_CDC_HandleTypeDef   *hcdc = NULL;7 T4 ^1 }6 }6 V1 }5 Z6 \
  246. : s. w: q% B6 H: M5 R
  247.         USBD_Composite_Switch_CDC(pdev);. p3 @& R' [! c

  248. $ p0 ^* W" @" \
  249.         /* Open EP IN */
    0 X- S  ^/ K; s9 i- X/ k6 O
  250.         USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK, CDC_DATA_FS_IN_PACKET_SIZE);
    , Y' h7 P! N6 O* M8 }6 c$ K
  251.         pdev->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;
    ' v/ L9 }+ V8 _8 Q

  252. 1 [9 h0 P7 O9 W8 a' j1 A
  253.         /* Open EP OUT */
    ; s8 i4 y4 M- [% h
  254.         USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK,CDC_DATA_FS_OUT_PACKET_SIZE);, ^2 X$ W) n) ^0 M( |# }) g
  255.         pdev->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;
    8 x& X+ ~! x4 Z, C' H* G
  256. , V0 R. ?" p. v
  257.         /* Open Command IN EP */
    & }- c) `7 O& u2 Z5 k% W
  258.         USBD_LL_OpenEP(pdev, CDC_CMD_EP, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);) I4 `$ c% Z2 _8 ^
  259.         pdev->ep_in[CDC_CMD_EP & 0xFU].is_used = 1U;
    + N; F9 A3 K+ `* j8 p5 a& J: x# J

  260. % L, m7 W  ^' _' O" y
  261.         hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;
    # K  f! B! n. W& M- J1 U1 _
  262. 2 L$ M9 a2 G9 x- N. g- e
  263.         /* Init  physical Interface components */6 E: ?# b/ a, k* j  Z2 v
  264.         ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();' t1 k4 y0 K9 f9 {$ F# @
  265. $ C( W" I3 m; f' @  v: z5 ?
  266.         /* Init Xfer states */
    / d& D5 y" [( M" b) w+ }" t4 R
  267.         hcdc->TxState = 0U;
    7 G5 P1 `7 @. T# c
  268.         hcdc->RxState = 0U;% F/ A. a- F2 Z4 c. N' x9 Y

  269. ' H# Q" D9 C$ u# W2 Y( w- M
  270.         /* Prepare Out endpoint to receive next packet */
    8 \* B6 d1 j- g3 M2 v2 Z$ H* c7 D# a
  271.         USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, hcdc->RxBuffer, CDC_DATA_FS_OUT_PACKET_SIZE);5 K- V( C4 F- _/ I/ l$ H
  272. }) G2 @; t% }4 }. U7 x( C
  273. $ r( m1 G% u. B# ?( W3 a8 |
  274. uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
    9 O0 z% o: F( B
  275. {
    - s, i7 V8 ], S8 Q: K1 j
  276.         USBD_Composite_MSC_Init(pdev, cfgidx);  // 初始化MSC* R4 T0 \: S  {7 {0 Z
  277.         USBD_Composite_CDC_Init(pdev, cfgidx);  // 初始化CDC7 @7 T8 E+ x+ k/ L, g2 Z/ F4 ^* M/ n
  278.         return USBD_OK;  n, R6 b8 q; T1 s) t/ G
  279. }
    % I" ^. [1 |7 @' l
  280. 1 L) v& h+ T! s8 O% b" y+ P
  281. uint8_t  USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx)1 Z  i# P  P0 {7 e/ D4 G
  282. {
    - @/ k8 e0 V& r0 ^& ^0 d4 r+ C
  283.         return USBD_OK;5 x) L0 T$ F2 }7 R8 m7 W# Z& @
  284. }
    8 E7 d* w1 v$ T$ O! w! e

  285. 4 C) w* T9 x$ k- ]2 j
  286. uint8_t  USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
    5 K6 E3 k9 S0 ]4 G
  287. {
    ( X0 H; ]( O; z
  288.         switch(req->wIndex)  // wIndex是接口编号,在配置描述符里面我们第一个IAD是CDC使用的是编号0和1两个接口,第二个IAD是MSC使用的是编号2的接口4 H) T6 m7 C& C! R
  289.         {6 k, q, ?  O* n" a" j2 @7 O
  290. 0 F7 Z, X* h. T& d) b2 ~
  291.         //7 l3 i: M; ?, A
  292.         // 第一个IAD# F" d" C: f# ]1 X5 ?+ X4 ^% g, F
  293.         //
    , M0 y. w+ x) Z
  294.         case 0:  // CDC的命令接口编号为0
    2 s2 Z, n2 v9 [' G- _1 S
  295.         case 1:  // CDC的数据接口编号为1: n2 M* ?/ e; k7 s
  296.                 USBD_Composite_Switch_CDC(pdev);& _1 A1 w) E; A6 g, _+ E1 Q
  297.                 USBD_CDC_Setup(pdev, req);
    $ F; D! x- _, A' Z1 K+ q
  298.                 break;% Z  G6 d/ T) }6 d/ C/ X5 @' w

  299. ! E# E# [/ g, p4 V) H/ h
  300.         //  C6 a; Z) ?9 ~! _! v! J
  301.         // 第二个IAD/ ^; h9 y. v4 \5 ?
  302.         //
    % g. ]3 Z& K1 t* g5 _# c0 _
  303.         case 2:  // MSC只有一个接口,编号为2
    ; P! q8 l( n0 o. d4 T
  304.                 USBD_Composite_Switch_MSC(pdev);
    ; h$ Q+ J4 E/ F0 v4 `
  305.                 USBD_MSC_Setup(pdev, req);" X4 z* S- C" _- D2 s$ J" k4 }7 k% S
  306.                 break;
    6 d& j3 k, G& C) e, ?# w
  307. + n& B1 O* _* L2 K1 D: L% g
  308.         //
    ' A  Z' k0 Z' O. c  L/ C
  309.         // 第三个IAD(如果有,在这里初始化)+ e6 n8 z/ i- L3 c5 _; b4 Z
  310.         //
    - `% b' _1 @) C7 U7 _) l0 q# v
  311.         case 3:
    & f; ]9 R, O% [) {
  312.                 break;
    ( f6 v; \! E9 Z; i% w* V/ G
  313.         default:break;8 C7 R4 B9 M+ ^! X1 t6 n* _- p
  314.         }9 o+ |: f  R, y( |/ ~5 s0 O! k
  315.         return USBD_OK;, D, a: W; r/ o3 O) b; F. ~
  316. }! c( {2 O3 g5 U- a: g
  317. / k) ~$ ?2 L9 P2 Z+ L3 i
  318. uint8_t  USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
    ; t: V  c8 _3 p( v: _# \: N
  319. {
    . e; h+ g9 W. a) u5 h6 ?! K
  320.         switch(epnum | 0X80)- A( F# V% L9 a7 ]" _% T. L
  321.         {
    . k8 A' J7 l8 M
  322.         case MSC_EPIN_ADDR:
    - M/ Z% e! T$ i6 e3 V6 I' \$ b
  323.             USBD_Composite_Switch_MSC(pdev);
    # q& `0 x' y  K6 d+ e: d0 L  T
  324.             USBD_MSC_DataIn(pdev, epnum);
    5 C  _/ o/ h3 a0 S+ r4 K
  325.                 break;
    ) @! s5 B0 ~. [; J6 m8 U
  326.         case CDC_IN_EP:; v, P3 M5 s' Y# c. C) r
  327.             USBD_Composite_Switch_CDC(pdev);
    & h) H6 n2 k8 Q! t6 i2 |: x# @
  328.             USBD_CDC_DataIn(pdev, epnum);) m& E. m, Y: F/ y1 M: ?  A
  329.                 break;
    $ I6 I5 _% C5 e5 h0 i5 U
  330.         default:break;
    6 z  S+ Y& v! J+ ?% v$ T
  331.         }8 ?4 Y: j8 H* @8 `# D; A
  332. 1 h4 G8 n; D- i
  333.         return USBD_OK;+ w3 a+ @3 h( P; |( O; J7 k
  334. }
    : z0 C% h( E0 m* {

  335. , G9 e9 x" \" ?
  336. uint8_t  USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)( {& Z' V, Q$ Q( A. t
  337. {/ D- s* |6 }, v' L' }* l2 Y/ L6 a  L+ t
  338.         switch(epnum)
    # G0 u' [2 J$ U3 j8 ?
  339.         {
    " b" e+ l7 l9 Y; t2 q4 B' }$ w
  340.         case MSC_EPOUT_ADDR:
    % k$ R5 u1 k) ?5 r
  341.                 USBD_Composite_Switch_MSC(pdev);
    3 j8 s" p, V1 Q3 n/ o# g/ n% A
  342.                 USBD_MSC_DataOut(pdev, epnum);
    9 g6 y, ^, I5 H' k& O( x( G4 O
  343.                 break;
    + h$ z. e6 G2 F% M. T
  344.         case CDC_OUT_EP:
    " S3 l! z8 n( R0 _" U* u; ]
  345.                 USBD_Composite_Switch_CDC(pdev);# q2 }1 Y6 s# ^
  346.                 USBD_CDC_DataOut(pdev, epnum);
    ! _0 N) \& w4 y) z* I0 V& m
  347.                 break;8 v# b  D9 E8 K
  348.         default:break;- t: {1 y2 O# g7 R; O& Z
  349.         }
    1 C- r9 H4 Z6 t' t
  350.         return USBD_OK;/ _& D( s  z! h# A; F  U: R
  351. }& \$ d8 t4 L) _* B- ]( N7 Y0 t' G

  352. ) K4 p% S- u. ]- F8 {! {8 C' _1 b, p
  353. uint8_t  *USBD_Composite_GetHSCfgDesc (uint16_t *length)
    0 a# P; \9 \1 k' N* p8 N
  354. {8 m) z) v/ Q& U( @3 t9 S
  355.   *length = sizeof (USBD_Composite_CfgDesc);3 u6 D0 n: y8 n& O8 W) o
  356.   return USBD_Composite_CfgDesc;. Y( O" R, I& @4 C# P8 m
  357. }/ ~- A5 s: J/ L7 X: H% \6 s1 k

  358. 7 C! v% T$ Z! T) j. q+ @
  359. uint8_t  *USBD_Composite_GetFSCfgDesc (uint16_t *length)
    / b1 `& ?/ K, F% E! V! r
  360. {0 y$ H, }( U2 ^: B2 s; c0 l
  361.   *length = sizeof (USBD_Composite_CfgDesc);
    ! C& u+ a9 e' o4 a7 l) a
  362.   return USBD_Composite_CfgDesc;
    . |  Y% d7 ]' f' E$ E
  363. }4 g7 ]( G" o* Y; {

  364. ) x' g" ]+ `6 U7 m5 s+ ]
  365. uint8_t  *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length); L6 n3 I* V8 W( y
  366. {6 d  @! C2 _5 h' _* j; y# f: q
  367.   *length = sizeof (USBD_Composite_CfgDesc);: V- x7 p6 S% [% t* ~5 ^$ ]
  368.   return USBD_Composite_CfgDesc;
    - X" k( A4 A/ ?& I- s& H, ]
  369. }
    - l9 ]& R; {0 ?  B- O9 f1 {

  370. 8 p: w: k1 K1 G
  371. uint8_t  *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length)! e7 r1 G! _% w/ G, K8 S9 E, k# L
  372. {
    & @: y8 j# d* k! Q, h/ d" W* d
  373.   *length = sizeof (USBD_Composite_DeviceQualifierDesc);
    ( X  {' p4 E( s/ p. Q
  374.   return USBD_Composite_DeviceQualifierDesc;
    ! |0 o$ R4 A) m' s+ P
  375. }
    # Q) D4 P8 F; A3 G$ P! T

  376. 5 K$ |: A+ g8 ?
  377. static uint8_t  USBD_Composite_RxReady (USBD_HandleTypeDef *pdev)5 i: [2 u1 ?4 f$ b4 U6 r& @
  378. {
    ; u- v! j, _$ E
  379.         uint8_t ret = 0;
    # q4 W+ A5 V+ S% Q6 X0 n# ~( i
  380.         switch(pdev->request.wIndex)  // wIndex是接口编号,这里我们通过接口编号确定CDC还是其他设备的EP0接收' P" [0 \. H. A# X' r( P- P3 Q
  381.         {5 R8 A& E6 \8 N; {5 f! c2 {* `
  382.                 case 0:  // CDC的命令接口编号是0
    3 c2 g( g2 W% D: m0 ~  R
  383.                 case 1:  // CDC的数据接口编号是19 N8 n2 Z( a2 ^; {# l* J9 B+ B& M6 c
  384.                         USBD_Composite_Switch_CDC(pdev);
    - \3 n  `* F  h. C" \5 D4 b" N; w2 G+ l
  385.                         ret = USBD_CDC_EP0_RxReady(pdev);) [( t9 Q$ f) h
  386.                         break;
    . i  N1 g- ?1 e
  387.                 // 如果有其他设备还用到了EP0接收,在这里加入
    8 Y8 G0 k; Y4 j$ d" F
  388.                 case 2:
    $ M1 `# v! d6 o, h0 G# q- d
  389.                         break;% W/ t( ^: F/ \# _9 P  |1 c
  390.                 default:break;) p5 D* K' O( |- b0 a
  391.         }
    ' Y' s$ t! s1 D
  392.     return ret;
    * S5 E& _# M8 |8 n8 j
  393. }
    ) c( y& B  N* Y) }
  394. 3 y, H+ J# a5 A& @# W
  395. static void USBD_Composite_Switch_MSC(USBD_HandleTypeDef *pdev)
    1 |6 c; b4 T" A( O8 _
  396. {8 P( n6 ~3 |) I, A( u$ D
  397.         static USBD_MSC_BOT_HandleTypeDef USBD_MSC_Handle;
    . t* D/ @$ B9 D: N
  398.         USBD_MSC_RegisterStorage(pdev, &USBD_Storage_Interface_fops_FS);, A$ S3 w; u9 f7 ]: N
  399.         pdev->pClassData = (void *)&USBD_MSC_Handle;
    ! N& o3 a( \7 L) w. w. i1 c
  400. }7 b$ a) d. O+ D/ B% T7 {

  401. 3 b$ t* S5 N2 N: D8 x
  402. static void USBD_Composite_Switch_CDC(USBD_HandleTypeDef *pdev)3 z, @( H9 M- g9 o6 B
  403. {
      S5 O  M% h# ^
  404.         static USBD_CDC_HandleTypeDef USBD_CDC_Handle;, f* _8 ~1 N0 p/ i6 [: q3 E2 n1 N
  405.         USBD_CDC_RegisterInterface(pdev, &USBD_Interface_fops_FS);1 w7 [' t4 c/ M. d+ X1 f
  406.         pdev->pClassData = (void *)&USBD_CDC_Handle;
    1 C$ c! z2 w# V
  407. }
    / |# `! r8 A3 Z% R
复制代码
$ j2 K, d0 v2 V
其中有关设备描述符的修改,我都用+++lakun进行了标注,并写上注释,方便查看。+ ~0 q2 O/ v, g$ c

3 {! R& S- V: l; w第五步:MX_DEVICE_USB_Init修改( J4 J5 S4 }. L
上面我们已经完成了统一接口的编写,现在就可以修改MX_DEVICE_USB_Init函数了,屏蔽掉接口注册函数USBD_CDC_RegisterInterface,然后将类注册换成我们自己的组合设备,如下图:. g+ ]; d/ _: f8 S
# C7 d* _2 W7 J
~V(N24[X4FFR~H~TYROQ{5N.png ' m3 X1 `0 ?6 F% h, b

( x; h; J, f& U! X到这里就已经改完了,运行程序之后设备管理器会出现:一个组合设备、一个虚拟的串口、一个USB大容量存储设备,如下图:
9 R+ p; g  b3 {1 E, F+ A0 z$ L- c, J) B8 K! S, R3 p! C
20210425090801727.png
0 ^! ?. U; A( p" \) Z5 K
) Z  Q/ G! r  Y7 L4 ?1 W这样就是成功了!
- G! `; Q* a/ P2 R
7 y! u( j0 t$ C# t!!如果修改过后发现设备管理器的MSC或者CDC显示感叹号,那么在回头检查PMA的配置以及组合设备描述符!!
2 J3 y4 r- v: k; [! N1 P! [' ?) F" H, k0 u. w% M  q/ _- U5 o# x
遇到的问题6 u" K- a0 b: }) \
我修改完毕之后,将板子接入电脑,虚拟出来的串口没问题,但是就是死活认不出U盘,后来找到问题的原因是因为我先使用的CDC串口这个单独的工程,我的win10已经默认枚举成了CDC,所以认不出U盘。
) V0 W+ g! ~4 D2 c6 {7 B9 N7 \* m7 W! l+ r' w( H: d
解决办法:
$ V* |  p% r5 c5 r; N1.卸载识别出来的串口,重新拔插' E6 A: l0 k; A' Q  v5 Z
2.在程序里修改一下PID
: c$ C: L" _% p( k/ P; ]
; l: T: c: U) ~& Z# v1 R( w( B6 g+ P2 l
S30Z~TQ%1__%MHK`IJ2XN6N.png
& Z% A- |' m3 J' e& n
6 H5 S6 U( D6 D% j我是用的第二种办法解决的!
% @" D5 o. m0 L  s4 t/ d  n, X# W) L, z$ }
" W) e+ @* z+ B7 w
4 z3 K4 K4 J$ \$ d/ a- k) `6 H9 J0 b5 O
收藏 评论1 发布时间:2022-4-9 23:20

举报

1个回答
小白小灰 回答时间:昨天 13:36

不需要composite.h吗?编译出错,有几个没定义的。能给个源代码吗?不胜感谢

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版