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

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

[复制链接]
STMCU小助手 发布时间:2022-4-9 23:20
工程试验环境
. H. {' _, S! S( Q) M2 MSTM32F103RC" R' d0 ]; j2 C4 w6 X# A( G  e$ O
STM32CUBEIDE1.5.1% B3 u" `# Q) o+ ~% o/ q
1、本教程默认你已经会使用STM32CUBEMX生成CDC代码和MSC代码,这两个工程的生成很简单,网络上的教程一搜遍地是。
+ H4 T7 R8 [& \7 j$ ^; ]
- a3 T2 o8 H- B, S" Z- P2、USB组合设备的移植修改需要具备一定的USB知识储备,如果没有强烈建议看一下我的另一篇博客:STM32 USB相关知识扫盲2 S- ^( Q$ g7 `3 I: Q
! N; a/ I9 g# F7 t1 h  s
首先说一下STM32的USB库的初始化操作,MX_USB_DEVICE_Init函数中使用USBD_RegisterClass函数注册绑定了实际的端口初始化控制等操作,如果是CDC那么注册的就是USBD_CDC这个结构,如果是MSC那么就是注册的USB_MSC这个结构,所以我们的组合设备思路就是用哪个的时候,就将这个结构切换成对应的操作结构。) z2 y* r2 u* u- K( d% W* J
, }' n/ B! x6 _8 s) W+ c
第一步:基础工程生成. V/ O. G. p% r. k$ m& d8 n3 @( f
首先先用STM32CUBEMX生成CDC的工程和MSC的工程,并测试通过没有问题后,我这里使用CDC工程为基础工程进行修改成USB组合设备。- @8 a% M4 e# G
/ v# r5 c3 S' p  N- @' m1 P
基本步骤如下:, ~  K4 L; D, ?' d+ T  m, ^' Z" r

  b% G4 ~% t  YUSB设备描述符修改成组合设备类型3 ?6 j9 R0 S: g$ D6 O8 F8 U
修改PMA端点分布
# q& r9 g' X2 a* k修改USB配置描述符并添加MSC的配置描述9 ^! V' K4 I; p8 t( q9 H, c
修改初始化函数接口,改写成我们自己的组合设备初始化操作函数
3 ?. M" H" \- L6 ^- ~- Z/ [修改MX_USB_DEVICE_Init函数,注册成我们自己的组合设备9 }4 I0 E& R3 Z0 d- h+ X

8 E4 n7 G! S) ~8 d/ V: j
& o/ o/ ~( T& U% V5 s5 j9 c下面进行分布修改。
) i2 t' ~% ^% ~4 _  Z6 E' \
0 Y7 [  |5 M9 |8 m5 c$ j第二步:USB设备描述符的修改
+ D3 t$ z7 E! Y这一步很简单的,就是修改usbd_desc.c中的设备描述符数组USBD_FS_DeviceDesc,将设备类型改为组合设备类型:
6 @( r) K* Q& O3 r) A! K% |
/ y: |, j6 z" |5 q3 w J)4A6FO7U[S`S6NWUY9PT63.png . P8 q4 t* z& C" [1 A7 Q

& t; @# q2 V3 s2 c6 c3 G$ ?* v) E第三步:修改PMA端点分布

8 c# b' d2 j9 x( K, ?0 V! g' r首先修改一下CDC所用到的端点地址,CDC的输入输出端点不动,将命令端点成0X83:
# I; ?2 c+ Z; ]) ?4 O. ^- x! R: ?. Z6 |  x- W) F4 @
" a5 Y+ r  w3 H$ k% }3 C  N
2HX(T@W6WV[XTC]MD)OVTS2.png ! G' s% @% Y4 s% x8 ^( v

4 g9 P5 I! w! B! I) F- t, G然后进入usbd_conf.c文件中,找到USBD_LL_Init函数,修改PMA端点初始化:
) ~+ s7 u% }* O  b/ k% `+ F5 l$ P( _3 v# _# m; l) U, G" b% W
XEC{)J[~_964X[7EHLIV7.png
) I2 B: E$ y2 E3 ~3 U% |4 ?$ {/ O
& L! z& E2 d3 ?; j5 a* ?5 \这里的修改非常关键,为什么addr要从0X38开始呢?
( T+ I' e9 C) X& e5 N& f% j
6 u7 z5 b' U7 B' m( l( J& n因为我们目前用到了:1 a8 P3 O5 ]% Y  g0 L; i' ~
' a* g6 C) X! W8 V6 x
默认的两个端点(0X80、0X00)
- G, O- r3 m: Y! Z* ~CDC的三个端点(0X81、0X01、0X83)" i3 l5 j4 e# h% A; T7 @
MSC的两个端点(0X82、0X02)# n# U' r: A1 o2 ~$ ^
- i: B2 K9 S5 \+ \
2 k& |# d1 g- z$ ~: L
共7个端点,每个端点占用8字节,总共56字节,十六进制就是0X38!
% `/ ]  }: p* _; A5 Q8 t
- o' p& Y$ k4 k- R好多人修改自己的USB应用时,就是卡在了这里!如果起始地址修改不对,那么USB端点缓冲就会覆盖PMA头部的端点描述!
3 n# v$ f/ j- y/ {# C
3 W1 P4 @7 C: |有关PMA的详细描述及使用,请看文档头部的《STM32 USB相关知识扫盲》链接文章!
+ B$ |" m# v& U5 M5 W" u
9 M/ I0 j: I- g: y* w第四步:编写我们自己的组合设备配置1 L( t9 H, Y+ N0 g0 |5 c# }, I& r
这里我为了方便修改,新建了一个usbd_composite.c文件,用于编写组合设备驱动,文件内容如下:
; T  @, F% ^3 a1 [8 Z- J! I* o
5 _- Q9 H. @( U% x
  1. #include "usbd_def.h"* y5 o8 r8 c1 j
  2. #include "usbd_msc.h"
    ( {' O) B" q- k; l0 ?
  3. #include "usbd_cdc.h"6 |- x& I: c5 D' z) ?( }8 s* [
  4. #include "usbd_storage_if.h"
    3 Q, P3 I- [( @* Z$ A" m
  5. #include "usbd_cdc_if.h") d+ y4 p9 P3 R& B, D( t, k0 G

  6. 1 j/ i( U" l( P/ _' a6 E2 ?% ?/ g$ z$ @

  7. ; Q7 T, b- O" }+ ]
  8. #define USB_MC_CONFIG_DESC_SIZ 106
    $ V$ V5 p% E& N0 S" t

  9. & U8 K; H& t0 y2 `) A3 U) ?

  10. 7 L' H. J. B' s9 D
  11. extern USBD_HandleTypeDef hUsbDeviceFS;
    . i2 X* c' g1 r

  12. * h; ?0 T% r5 _5 k$ @4 ]3 Q
  13. 4 q8 G: i4 r; u" s6 M- w
  14. extern uint8_t USBD_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
    ' R" p0 K& R1 F5 `* X' r2 v7 Z
  15. extern uint8_t USBD_MSC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
    1 W/ d1 U4 Q9 E( C- o) N2 E" F
  16. extern uint8_t  USBD_MSC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);& c9 K. q0 {' I
  17. extern uint8_t USBD_MSC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
    * E7 Z: [; b3 r, |( ?. h
  18. extern uint8_t USBD_MSC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
    # R6 l% k0 M1 A
  19. ! F. v9 G: N3 K: ^$ x# ^/ o7 {
  20. 4 @, ~1 h* i3 u: C7 |: H0 Q6 g
  21. extern uint8_t  USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
    ' Q+ f6 S7 k; o& F
  22. extern uint8_t  USBD_CDC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
    2 O# n7 W0 n+ j8 W; ~2 b: R
  23. extern uint8_t  USBD_CDC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);$ V* B; X1 Z) v" m7 L  x2 ]
  24. extern uint8_t  USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
    ; }4 p' M+ m0 D* m% l9 f
  25. extern uint8_t  USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);* X4 U% m" d, @9 }1 ]
  26. extern uint8_t  USBD_CDC_EP0_RxReady(USBD_HandleTypeDef *pdev);# X0 o8 }4 P& W/ u! s
  27. 5 J8 A; V; b( @

  28. # S2 _. [. ~6 P1 @! F3 v
  29. static uint8_t  USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);+ M" E3 f, [* U
  30. static uint8_t  USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
    . h- E* z; Y8 j. ?& K! d
  31. static uint8_t  USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);0 w' ^6 x% Q3 F( A9 x4 Z& o% ?
  32. static uint8_t  USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
    , q) D8 G: F8 t. a% R+ h' l
  33. static uint8_t  USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
    ( ]% _& |) F" D* `$ c) u
  34. static uint8_t  *USBD_Composite_GetHSCfgDesc (uint16_t *length);
    8 K1 w0 R  f' R0 [* d( X
  35. static uint8_t  *USBD_Composite_GetFSCfgDesc (uint16_t *length);
    % F5 K" A3 V: i2 X! E
  36. static uint8_t  *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length);
    8 z' x4 ~! l: D! M0 B% G
  37. static uint8_t  *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);
    $ A4 d: T  e  a) C; l
  38. static uint8_t USBD_Composite_RxReady (USBD_HandleTypeDef *pdev);
    + V3 C$ P7 R& M' L2 z2 q8 i
  39. static void USBD_Composite_Switch_MSC(USBD_HandleTypeDef *pdev);( L1 D$ t" z. _0 z3 T1 z/ Z/ F
  40. static void USBD_Composite_Switch_CDC(USBD_HandleTypeDef *pdev);
    - P/ H% r# \. l! x
  41. 2 ?# I7 ]. l4 `9 L. |

  42. 3 {- b+ d& |: [* p6 S3 N8 W
  43. USBD_ClassTypeDef  USBD_Composite_CDC_MSC =
    1 z" b: M6 d, I
  44. {7 V5 `: L/ C( a0 C. e  u
  45.   USBD_Composite_Init,
    & U- D, @4 \( ^* u  p! ~
  46.   USBD_Composite_DeInit,9 h  v1 h. m+ \
  47.   USBD_Composite_Setup,
    % h( f3 @, P. M$ H% ], q
  48.   NULL, /*EP0_TxSent*/  s& w8 [! m+ C5 c- s
  49.   USBD_Composite_RxReady, /*EP0_RxReady*/4 g& \) |# E, {7 J* g$ n
  50.   USBD_Composite_DataIn,
    * _5 S/ `. d5 ?5 Y$ H1 f
  51.   USBD_Composite_DataOut,) M  T  \  o* J6 X
  52.   NULL, /*SOF */
    * |' i+ L8 Z7 j3 Q+ d9 W7 d# _: I# J
  53.   NULL,( O- @- `4 Y1 u2 s0 v6 K) d3 K
  54.   NULL,2 T, P) r. Q2 _* o" D- J
  55.   USBD_Composite_GetHSCfgDesc,6 _- V9 x, L7 J
  56.   USBD_Composite_GetFSCfgDesc,
    9 z) v; m! {" J# P0 C: V
  57.   USBD_Composite_GetOtherSpeedCfgDesc,& b7 T  h* s: W
  58.   USBD_Composite_GetDeviceQualifierDescriptor,
      T! C# D& t6 t" a
  59. };* G, e( l/ l  ]

  60. * R' b! N( r/ K& q* d' ~) V( n
  61. * \3 P! H5 C4 E
  62. /*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
    8 c2 h% q$ W* A& L" ~
  63. __ALIGN_BEGIN uint8_t USBD_Composite_CfgDesc[USB_MC_CONFIG_DESC_SIZ] __ALIGN_END =
    1 C& b" j5 J# \
  64. {
    # k# \4 P! y+ E) w6 j1 s! o
  65.   /*Configuration Descriptor*/
      u; D8 M# O" q5 C/ n8 h
  66.   0x09,   /* bLength: Configuration Descriptor size */
    & I, z  I! K! C% g
  67.   USB_DESC_TYPE_CONFIGURATION,      /* bDescriptorType: Configuration */
    & g  y4 T6 ^2 H5 r# U8 |
  68.   USB_MC_CONFIG_DESC_SIZ,           /* wTotalLength:no of returned bytes */
    9 J  l2 L) c' U5 a+ O
  69.   0x00,  M- ^3 _  b5 {& D) _, |
  70.   0x03,   /* bNumInterfaces: 3 interface */ /* +++lakun:CDC用了两个接口,MSC用了一个接口,所以是3 */5 E+ R+ x8 I2 j
  71.   0x01,   /* bConfigurationValue: Configuration value */
    1 G. t. _2 ]0 e5 Q+ P2 ], K
  72.   0x00,   /* iConfiguration: Index of string descriptor describing the configuration */+ [1 R! m4 w5 B2 ^. U3 S; m. L
  73.   0xC0,   /* bmAttributes: self powered */
      J  V5 b# N4 ?; a
  74.   0x32,   /* MaxPower 0 mA */' K6 y: I1 K6 X( T

  75. ; K0 }$ K2 p7 M/ b! Y2 _5 E: U
  76.   /*---------------------------------------------------------------------------*/3 s- S) [4 |+ M& O" H  ?
  77. % C# X3 [6 n1 [2 K  G# G3 H% D  G8 `
  78.   //1 n% g: r% z% Y* W4 y3 Z
  79.   // +++lakun: IAD(Interface Association Descriptor),用于指示CDC
    2 g5 G9 Y/ n, p% p4 F
  80.   //2 @  u8 O" m- w2 |; e# s% y
  81.   0X08,  // bLength: Interface Descriptor size,固定值$ T; t4 D, B  P( R" w
  82.   0X0B,  // bDescriptorType: IAD,固定值0 P2 {1 Q0 d2 T7 P. j3 y. d
  83.   0X00,  // bFirstInterface,第一个接口的起始序号,从0开始5 N. M" x+ a" {; Y- n
  84.   0X02,  // bInterfaceCount,本IAD下的接口数量
    1 Z: m" v7 q  r/ w: l
  85.   0X02,  // bFunctionClass: CDC,表明该IAD是一个CDC类型的设备+ p$ S3 |9 a% f' C( u& g1 Q
  86.   0X02,  // bFunctionSubClass:子类型,默认即可2 r8 S' x3 }4 q
  87.   0X01,  // bFunctionProtocol:控制协议,默认即可& ?% a9 x# |& U7 b. |% L/ x
  88.   0X00,  // iFunction
    2 J- _" }2 d$ n+ T7 ?/ c

  89. ; S7 h4 `* R" e' n
  90.   /*Interface Descriptor */
    7 A3 p- a4 M0 N8 i& e% D: l
  91.   0x09,   /* bLength: Interface Descriptor size */1 y9 K) V- {7 Q" e8 ?, f
  92.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */
    " Z. ^' t2 E& l. \) e. ^# d+ {- {
  93.   /* Interface descriptor type */
    " Q+ P! \. w0 }3 U* M6 K$ M) \7 L
  94.   0x00,   /* bInterfaceNumber: Number of Interface */                   /* +++lakun:接口编号  */
    - r1 d+ x/ \9 Q
  95.   0x00,   /* bAlternateSetting: Alternate setting */0 }! g3 p4 ^% Z. e0 {0 r
  96.   0x01,   /* bNumEndpoints: One endpoints used */
    ) `, g( h# K9 J
  97.   0x02,   /* bInterfaceClass: Communication Interface Class */          /* +++lakun:表明这是一个通信接口 */
    % A5 \2 \% A5 {! ~) D- Z
  98.   0x02,   /* bInterfaceSubClass: Abstract Control Model */
    / X. b) i! Q: w) ~0 K  G, c
  99.   0x01,   /* bInterfaceProtocol: Common AT commands */
    # R8 g1 X4 x0 d, M" R. F0 y
  100.   0x00,   /* iInterface: */
    , g# w3 b- c  s2 P
  101. 0 ^3 b4 z) u0 m3 D4 w1 M5 ?
  102.   /*Header Functional Descriptor*/* x  A; N* q4 @
  103.   0x05,   /* bLength: Endpoint Descriptor size */) C# `  D! _( S4 r
  104.   0x24,   /* bDescriptorType: CS_INTERFACE */
    ' P& Z( b1 M# d7 q) n
  105.   0x00,   /* bDescriptorSubtype: Header Func Desc */1 \/ C6 j3 Z. R5 k4 k& d3 _
  106.   0x10,   /* bcdCDC: spec release number */6 t/ T/ o' X7 A1 y$ c
  107.   0x01,' d* X" Q" u; w! F* r; A/ [

  108. 3 ^1 Z) m  g  U, y: ]
  109.   /*Call Management Functional Descriptor*/
    + W/ I5 ^, r# l$ p  e
  110.   0x05,   /* bFunctionLength */! h/ h0 u9 e0 g7 _- ~0 o+ S
  111.   0x24,   /* bDescriptorType: CS_INTERFACE */
    * b% W+ _4 e3 l- F3 y6 ~
  112.   0x01,   /* bDescriptorSubtype: Call Management Func Desc */
    , l3 C& B5 u' F' m; v2 R1 l
  113.   0x00,   /* bmCapabilities: D0+D1 */
    : B$ h5 a% ?) ^9 R0 r
  114.   0x01,   /* bDataInterface: 1 */4 l+ w9 x/ Z. b/ F/ I2 [1 Z
  115. 0 z$ i8 ~: B: P5 O  P' n3 p7 h
  116.   /*ACM Functional Descriptor*/
    ) \- Z3 S- j$ u; @& `5 R( B  `$ C
  117.   0x04,   /* bFunctionLength */
    1 q  N8 w* b( o7 Q( A, u- a; t+ F
  118.   0x24,   /* bDescriptorType: CS_INTERFACE */
    4 m: Q  {2 G) B3 C8 i- s+ @
  119.   0x02,   /* bDescriptorSubtype: Abstract Control Management desc */  {' F) m$ r, [
  120.   0x02,   /* bmCapabilities */& [! k% F' ?3 h' O9 \; g
  121. ) S) ?/ g; l' i3 z
  122.   /*Union Functional Descriptor*/) r: i  T5 k/ M  t
  123.   0x05,   /* bFunctionLength */
    $ @* C; i4 c( ~% o; D
  124.   0x24,   /* bDescriptorType: CS_INTERFACE */
    6 `1 T2 a% a+ |1 U3 c; {$ j
  125.   0x06,   /* bDescriptorSubtype: Union func desc */
    4 e* p6 f( s8 Y  e8 j: Y7 @& a
  126.   0x00,   /* bMasterInterface: Communication class interface */           /* +++lakun:这里是用来指示CDC通信接口的编号的 */
    * G0 u: X! m0 w3 K* c$ }
  127.   0x01,   /* bSlaveInterface0: Data Class Interface */                    /* +++lakun:这里是用来指示CDC数据接口的编号的 */
    2 s& e% ?( Q+ P: X
  128. * H/ D  h" r- m+ f- D0 p+ S
  129.   /*Endpoint 2 Descriptor*/
    ' w- x( J% X3 z0 @1 _( D  j. `6 a
  130.   0x07,                           /* bLength: Endpoint Descriptor size */" u' D) I& z8 o
  131.   USB_DESC_TYPE_ENDPOINT,   /* bDescriptorType: Endpoint */
    1 g0 D2 ?+ c# Y8 H( X' y5 A
  132.   CDC_CMD_EP,                     /* bEndpointAddress */5 k( E% i' N; ]+ _' w+ u! ^
  133.   0x03,                           /* bmAttributes: Interrupt */
    1 L* P3 k  r+ t3 n
  134.   LOBYTE(CDC_CMD_PACKET_SIZE),     /* wMaxPacketSize: */! l2 i" x! w8 R" g' x; ?
  135.   HIBYTE(CDC_CMD_PACKET_SIZE),
    # U* L* n  `* H* l" U
  136.   CDC_FS_BINTERVAL,                           /* bInterval: */
    * H  s' [4 \9 e6 ^) G
  137.   /*---------------------------------------------------------------------------*/0 ^$ g0 j# f7 g* c
  138. 2 i# }7 W1 J  _/ Y- x( m% i
  139.   /*Data class interface descriptor*/8 ^: {  |. |- A6 [
  140.   0x09,   /* bLength: Endpoint Descriptor size */2 n9 k5 d6 g6 M$ L2 [, o) }& b
  141.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */
    # P" L' U% k& N9 ]6 H% P. q% h$ R+ f
  142.   0x01,   /* bInterfaceNumber: Number of Interface */                     /* +++lakun:CDC数据接口的编号为1 */
    + d  R2 I( _2 n' n( a" F2 F# D
  143.   0x00,   /* bAlternateSetting: Alternate setting */% r: W: w/ L- O0 m7 ]4 B
  144.   0x02,   /* bNumEndpoints: Two endpoints used */9 {3 s% G- d/ q" ?
  145.   0x0A,   /* bInterfaceClass: CDC */) W) x+ C* f/ @
  146.   0x00,   /* bInterfaceSubClass: */  Y1 w* O+ s/ j  F
  147.   0x00,   /* bInterfaceProtocol: */
    ) ~; A; k/ K" j4 l4 Y3 k
  148.   0x00,   /* iInterface: */
    & |  h/ F) c+ P8 ~- E

  149. 4 s9 _: C6 ?3 s9 ]3 U
  150.   /*Endpoint OUT Descriptor*/( l# I4 Y: K" Q! Y) V2 w3 k2 S- D7 }
  151.   0x07,   /* bLength: Endpoint Descriptor size */
    ; Y% ~2 r0 y. E2 H; F% T1 D% N
  152.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
    : B  c; S) t8 O
  153.   CDC_OUT_EP,                        /* bEndpointAddress */8 F, Q& C9 O( J( D5 x
  154.   0x02,                              /* bmAttributes: Bulk */
    ; F: j* c" u4 u
  155.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */8 v2 T1 ^9 r$ n1 o
  156.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
    % h$ p+ x6 h* c: g
  157.   0x00,                              /* bInterval: ignore for Bulk transfer */
    5 A$ ]. Y* z4 K
  158. # P) r) x# R( ^0 k& i, K6 n
  159.   /*Endpoint IN Descriptor*/; N6 H0 Y# E* `/ ?! j
  160.   0x07,   /* bLength: Endpoint Descriptor size */
    1 P; c: O/ k( H1 ^1 n5 x# P; T
  161.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */+ @6 O, N8 N1 B4 Q4 h
  162.   CDC_IN_EP,                         /* bEndpointAddress */( P8 B/ Y3 @6 A8 a6 Q% O! }5 R
  163.   0x02,                              /* bmAttributes: Bulk */
    ; U* p  B2 k. b" @2 W% {% K
  164.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */% }/ ^) E, A- w3 ]) g* i8 h* Z
  165.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),% T+ q6 |5 ^' @; {- P, n
  166.   0x00,                               /* bInterval: ignore for Bulk transfer */
    . u# ^+ `2 w9 M! b: o2 n. d

  167. # j# N. U5 L& g5 ^/ V5 P  F$ Z
  168.   //
    ! C# }# q5 J( o6 F6 h" p1 F
  169.   // +++lakun: IAD(Interface Association Descriptor)
    + P: c/ p" t' o6 ]# G, P. \
  170.   //4 k. y' B1 n: K" J. `! `+ X
  171.   0X08,  // bLength: Interface Descriptor size,固定值) ]4 |8 A6 _% t; }
  172.   0X0B,  // bDescriptorType: IAD,固定值' c9 {( D( \  ^3 i9 ]
  173.   0X02,  // bFirstInterface,接口的起始序号(第0、1编号的接口用于CDC1,所以从2开始)
    ! k/ A9 M5 X' U0 }0 {% T+ W
  174.   0X01,  // bInterfaceCount,本IAD下的接口数量$ l& C3 C3 J+ v: c- }; y8 `8 @
  175.   0X08,  // bFunctionClass: MSC,表明该IAD是一个MSC类型的设备
    5 u5 O3 h4 B; ?, p0 Z
  176.   0X06,  // bFunctionSubClass:子类型,默认即可9 n, k2 ?& Q) C4 Z+ R) R/ n9 ~
  177.   0X50,  // bFunctionProtocol:控制协议,默认即可5 v6 E) G2 Y* C& n% V0 k
  178.   0X05,  // iFunction9 N$ T3 M: k% `( F
  179.   O2 j  d& O8 U4 G" E; w. D! B1 M3 a: g
  180.   /********************  Mass Storage interface ********************/
    . y- D2 C! F& n2 h- X$ A9 z
  181.   0x09,   /* bLength: Interface Descriptor size */
    7 X" R2 r: ~$ J* C3 y8 o6 R
  182.   0x04,   /* bDescriptorType: */
    9 e) f0 M: M: `/ [6 S& b
  183.   0x02,   /* bInterfaceNumber: Number of Interface */  /* +++lakun:第0和1编号的用给了CDC,所以MSC接口的编号从2开始 */' e  x5 M; w1 H7 H% D
  184.   0x00,   /* bAlternateSetting: Alternate setting */
    & w; l) S6 G' Q* O& |4 h
  185.   0x02,   /* bNumEndpoints*/7 H* `. [) g2 d" P
  186.   0x08,   /* bInterfaceClass: MSC Class */: A3 |" w' |( ~2 r
  187.   0x06,   /* bInterfaceSubClass : SCSI transparent*/
    ; d. N! h& f, M9 L  H1 d
  188.   0x50,   /* nInterfaceProtocol *// ~3 i+ N: r  v# p) Z, d
  189.   0x05,          /* iInterface: */3 ^7 G% S7 B  F9 A& @
  190.   /********************  Mass Storage Endpoints ********************/
    ' u6 v! q' [& S% O# ?7 T/ F9 X! Y
  191.   0x07,   /*Endpoint descriptor length = 7*/* c# l) s+ K3 \5 J: Y
  192.   0x05,   /*Endpoint descriptor type */  ^0 L" J6 E' f% E) N
  193.   MSC_EPIN_ADDR,   /*Endpoint address (IN, address 1) */6 A4 |  F  Z$ o0 i" P7 `# r+ B0 t
  194.   0x02,   /*Bulk endpoint type */+ p. ^/ q- n6 e" X
  195.   LOBYTE(MSC_MAX_FS_PACKET),
    ( B6 }- O4 `7 k" q; }
  196.   HIBYTE(MSC_MAX_FS_PACKET),2 j" W9 d* ~) j
  197.   0x00,   /*Polling interval in milliseconds */6 N: L% F' K( x* d1 y3 q! J8 ~

  198. 1 X+ B1 {6 `) v8 t4 W% A
  199.   0x07,   /*Endpoint descriptor length = 7 */$ J. c% o8 I& |& _
  200.   0x05,   /*Endpoint descriptor type */+ ?$ A* E% t% Y5 [
  201.   MSC_EPOUT_ADDR,   /*Endpoint address (OUT, address 1) */
    * q  V$ q9 w8 E( J
  202.   0x02,   /*Bulk endpoint type */; c: q2 p* C( V: ?8 c
  203.   LOBYTE(MSC_MAX_FS_PACKET),) n* G9 p; @% Y# u: i- q
  204.   HIBYTE(MSC_MAX_FS_PACKET),/ f9 v) Q, |" R" k* R: \) F4 ^
  205.   0x00     /*Polling interval in milliseconds*/& d* g6 c" V6 }8 E# ~6 i
  206. } ;
    * r- n; l7 q4 M7 k% t/ S5 f* x
  207. / \/ V5 n" ~( T, n! d7 T6 c# N( A( }
  208. 6 q0 g( O( B% I! \
  209. /* USB Standard Device Descriptor */) H' W/ k9 Q2 {$ y
  210. uint8_t USBD_Composite_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] =
    / V. @7 \! Q& D( r& T& m- W8 x
  211. {, T5 d& @6 t8 N- r: R
  212.   USB_LEN_DEV_QUALIFIER_DESC,; F: {( y, H, ~+ N
  213.   USB_DESC_TYPE_DEVICE_QUALIFIER,. J% x, Q: z1 u  c  f+ f8 N4 U
  214.   0x00,
    6 o: G- M1 `: m( a
  215.   0x02,
    , a- Z2 z4 @! x. j$ s
  216.   0x00,9 Y; X" E+ v, {' L% D
  217.   0x00," a% r, o" L: r; D# D9 W
  218.   0x00,; M: T. {+ S; z# R3 f
  219.   0X40,
    ( O  p) H2 e8 L# |
  220.   0x01,
    # e. b- W, D+ @
  221.   0x00,5 t9 x' p) d6 z5 W
  222. };
    & a! _) }5 ^* O. p

  223. , f0 d6 I5 @; \! C+ Q7 x4 {7 _
  224. ! F( P3 }, U0 Z" ]+ }, L
  225. // 这个函数是修改的USBD_MSC_Init
    2 Z3 q9 T1 K8 n0 n
  226. static void USBD_Composite_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
    3 B1 \, F3 b! R0 X
  227. {9 e* H- g! ]6 V+ @& o* b, [1 I
  228.         USBD_Composite_Switch_MSC(pdev);
    5 f& X1 o& o* a* `" b1 T; V. `
  229. . {/ P" h# x& B
  230.         /* Open EP OUT */' O' _0 P, Q0 C, S. q! Q
  231.         USBD_LL_OpenEP(pdev, MSC_EPOUT_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET);
    + H/ K; s; c7 v! M+ f/ X2 k. r
  232.         pdev->ep_out[MSC_EPOUT_ADDR & 0xFU].is_used = 1U;% I7 v0 ?# O2 {/ a2 }# j
  233. , P3 D0 C" L0 T# X/ \
  234.         /* Open EP IN */1 H. h) \, A- R* d
  235.         USBD_LL_OpenEP(pdev, MSC_EPIN_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET);# _# H# N/ Z! l/ n. R# h2 x
  236.         pdev->ep_in[MSC_EPIN_ADDR & 0xFU].is_used = 1U;. ]' u: n5 f3 S  s: B
  237.   W8 u: T$ E9 W- L; P' ]
  238.         /* Init the BOT  layer */' J3 j# @) K% V8 ]* ^' f
  239.         MSC_BOT_Init(pdev);2 e$ E: L1 A% k7 c
  240. }) K+ J) g- j; ^3 I1 A/ s  T/ `

  241. . o& N9 U. U! U' ]2 Y: \7 r' |) l
  242. // 这个函数是修改的USBD_CDC_Init4 Y) Y7 W7 k+ I" [) y* [& ~
  243. static void USBD_Composite_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
    * Z3 G" m% G9 o, O% j4 ^# a$ ~: A2 @* g
  244. {8 t6 W2 ^9 u# L$ P: i0 Y
  245.         USBD_CDC_HandleTypeDef   *hcdc = NULL;! q1 J5 k$ J$ T( D3 }; B; \' q  s

  246. - W: f) p- \. {# I' U. G- |
  247.         USBD_Composite_Switch_CDC(pdev);
    * `" N; t; J2 l9 P0 [! z7 w9 _6 k

  248. 2 z9 L! o* e  z: s! e1 q
  249.         /* Open EP IN */' O- C9 E) H. ~7 v/ n8 H1 D
  250.         USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK, CDC_DATA_FS_IN_PACKET_SIZE);
    , z9 ~9 L' R6 W  M
  251.         pdev->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;
    & o& c; y  \1 _3 d1 C2 ?5 d
  252. 0 B7 Y7 o- r( V4 b# w
  253.         /* Open EP OUT */9 F" Y9 e# l9 W  H3 {
  254.         USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK,CDC_DATA_FS_OUT_PACKET_SIZE);+ g) T# ^6 S5 b5 k; I2 W
  255.         pdev->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;
    0 @. d( g5 e# f! r4 b9 e4 x9 r

  256. . E4 g3 P7 u8 ^2 m3 s- O3 D
  257.         /* Open Command IN EP */
    # Q# r' B& f+ Q8 c1 P9 i: ]
  258.         USBD_LL_OpenEP(pdev, CDC_CMD_EP, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
    : i& O/ v9 b9 x+ P& l
  259.         pdev->ep_in[CDC_CMD_EP & 0xFU].is_used = 1U;
    ( x4 J( |. S9 u8 H

  260.   h2 ^9 d9 l, P; a2 |
  261.         hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;: O/ t) u3 H) _8 Z2 o7 I  @0 H0 t9 o

  262. ( H% q1 z0 D7 H# U+ B
  263.         /* Init  physical Interface components */! e+ u3 @$ s9 \4 U! q: Z8 Q" V& Z
  264.         ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();6 q5 T# ?2 C6 V3 P+ _+ U  N2 @' z! r( J
  265. 7 T$ L% |" e2 n- o( V
  266.         /* Init Xfer states */! @3 @* j* H+ R
  267.         hcdc->TxState = 0U;
    # u& C" L: q$ i3 W" Z+ _+ ]
  268.         hcdc->RxState = 0U;
    5 P- `- v: C) D6 I! G) }
  269. . `8 M9 }5 u! u9 ^
  270.         /* Prepare Out endpoint to receive next packet */3 ~3 q/ t! ?7 Y9 L: i6 f
  271.         USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, hcdc->RxBuffer, CDC_DATA_FS_OUT_PACKET_SIZE);  ?# u+ d- Y+ L' ^0 [; i
  272. }8 ]  j6 M  T9 u

  273.   v& o& |2 m1 x/ C6 m2 s# {3 |
  274. uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx). X) i( t+ h9 B
  275. {4 {9 D" g: N, Q' \: a8 z; e
  276.         USBD_Composite_MSC_Init(pdev, cfgidx);  // 初始化MSC
    2 z0 B; q7 v. Z6 k1 f* _% x. K
  277.         USBD_Composite_CDC_Init(pdev, cfgidx);  // 初始化CDC7 D: L' f  f3 w, o; j1 D
  278.         return USBD_OK;
    - H2 f  h6 R8 a: [) V
  279. }) m- h8 R1 A  J$ r; q7 c9 x

  280. " r/ M8 |5 U: A, V2 n& m$ ?+ q/ y
  281. uint8_t  USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
    4 ^+ F. C5 N# _% J8 w8 o
  282. {' r2 T% y) f4 ~1 `
  283.         return USBD_OK;8 K" Z* P9 U( E" z
  284. }* B" i2 [1 z/ |% j
  285. ! q; q8 z6 V2 g4 w! M$ p7 A# f
  286. uint8_t  USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
    " F: g% z' M- B3 N
  287. {
    2 w) b) V2 O6 ?5 m% J- m9 O
  288.         switch(req->wIndex)  // wIndex是接口编号,在配置描述符里面我们第一个IAD是CDC使用的是编号0和1两个接口,第二个IAD是MSC使用的是编号2的接口' M9 E" e% q8 j3 X5 o
  289.         {4 k- X, O) I4 @' l; U6 m& A

  290. $ R% e  H7 m* Q3 R: N
  291.         //
    # I0 d% C5 t( c" p- {
  292.         // 第一个IAD& q" k1 }& n# R; c1 ]" R- Z
  293.         /// d# R2 [1 Y% F* |% c, ^
  294.         case 0:  // CDC的命令接口编号为0
    * n2 _2 G6 [  ?1 x* I
  295.         case 1:  // CDC的数据接口编号为1$ V! P, C! v& J  s7 Z9 A4 ?( L' C( E
  296.                 USBD_Composite_Switch_CDC(pdev);
    * Y" D) E/ R* ?
  297.                 USBD_CDC_Setup(pdev, req);
    8 r! P: q, m, k1 i& x
  298.                 break;
    1 p5 D& L5 Q( `! ^- L

  299. . n) V  Y5 X; p- Y4 k
  300.         //2 T9 q" g1 R  F6 P, T6 B
  301.         // 第二个IAD
    1 u; k& V( |6 w3 n& u
  302.         //5 t' Q$ e0 B" ]" o8 y
  303.         case 2:  // MSC只有一个接口,编号为2
    ; P5 E: ]4 }% J7 o
  304.                 USBD_Composite_Switch_MSC(pdev);
      Z! f6 f/ K" ?4 k
  305.                 USBD_MSC_Setup(pdev, req);9 [5 a" y5 ^7 C  V( S1 U7 [
  306.                 break;) _; d4 ]' e* R1 ]" O. l0 Y. q8 K

  307. " l* n* v4 @4 S2 f8 U
  308.         //
    & o$ i* _3 _8 ~& l' B2 i2 y
  309.         // 第三个IAD(如果有,在这里初始化)
    ! B; t1 e& J% l1 l" x* o* }" Y
  310.         //
    7 V- f& k0 {' y
  311.         case 3:
      y3 g$ k" y( K% W3 l
  312.                 break;
    6 n) ]; @- P9 |* X
  313.         default:break;
    . t7 X/ u! u4 ]+ j( d9 M
  314.         }" k4 M9 K& E$ ?! |
  315.         return USBD_OK;
    % c4 l1 E! p& d7 g* ]- U. n/ g
  316. }
    6 M! Y0 A' S& u, N/ u
  317. / u3 g2 ]$ _5 E: g5 V
  318. uint8_t  USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
    ; a! K6 S  m6 R% Q- ~
  319. {" p2 ~7 Y: o+ {2 n
  320.         switch(epnum | 0X80)
    + p: l1 Y3 _! Q' q% X5 C! n5 \- g
  321.         {
    . p2 q) A) i# v: |  S7 X/ x
  322.         case MSC_EPIN_ADDR:5 ]% K6 g, ~) e  z
  323.             USBD_Composite_Switch_MSC(pdev);9 g: u4 m( s) ]9 h. y) c
  324.             USBD_MSC_DataIn(pdev, epnum);
    7 J6 d$ d& N$ h  f
  325.                 break;
    / K6 l, l5 ^3 @- `6 Y3 [
  326.         case CDC_IN_EP:( a9 p8 U7 C$ Q& Z+ p
  327.             USBD_Composite_Switch_CDC(pdev);7 ^7 V. l. T, M$ N
  328.             USBD_CDC_DataIn(pdev, epnum);
    + X# N9 F  p9 S# {  ?3 B, B/ {
  329.                 break;4 f. ]1 C! A; U" p) W  p
  330.         default:break;
    4 I; o/ j( ^% S# t9 V  h% H
  331.         }
    + Q5 L2 I. S# P; R, Q5 k+ J
  332. - H" T9 Y! o: [* Z; w3 e
  333.         return USBD_OK;6 ?$ W! o3 T( R
  334. }% n5 k6 J1 Z# s
  335. " F4 F! v* O6 d3 l" F/ B) H% a
  336. uint8_t  USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
    ! |) v6 |/ k1 H2 L
  337. {& a. |& Q6 h: ], Y
  338.         switch(epnum)6 T" p* l/ I! D: U3 ]- u
  339.         {3 e3 H& b. q- b" Z2 s) r
  340.         case MSC_EPOUT_ADDR:% e, \5 G7 ?% W: z! S* ~6 {4 ~- w' s
  341.                 USBD_Composite_Switch_MSC(pdev);
    5 e8 f' x5 Q4 j2 p' \3 c5 y
  342.                 USBD_MSC_DataOut(pdev, epnum);3 [& l. _9 G0 k3 w& u2 r) B
  343.                 break;; l+ u! S$ B9 W* {) c6 r
  344.         case CDC_OUT_EP:4 Z* k2 s8 C; @  n, s
  345.                 USBD_Composite_Switch_CDC(pdev);" b5 d  l0 ?  v2 T9 _! z; S( F7 B
  346.                 USBD_CDC_DataOut(pdev, epnum);/ l" t7 N" }+ _# b
  347.                 break;
    5 N" D1 S; s' e0 X+ t/ v
  348.         default:break;" r! U7 d5 Z% j) `! y/ |+ ~: e* W
  349.         }6 l: `+ k/ l6 y9 Y  Y% R! s
  350.         return USBD_OK;
    6 x  b+ Q! z% P" j4 L
  351. }/ t* b% F/ t% j" G: m
  352. ) I$ V# }% J5 f+ C! Y
  353. uint8_t  *USBD_Composite_GetHSCfgDesc (uint16_t *length)
    ( R# L2 h. T* x: n
  354. {2 j6 Q) f6 w6 [) {0 x
  355.   *length = sizeof (USBD_Composite_CfgDesc);
    * }$ O8 k) G* O
  356.   return USBD_Composite_CfgDesc;
    ; @, n$ G: R4 l) y' O! y  e' Y
  357. }
    5 l& k: s) D; ^. O- z: f

  358. + ~3 d, M6 T1 q3 O- A
  359. uint8_t  *USBD_Composite_GetFSCfgDesc (uint16_t *length)
    ; O- T: T2 a1 ]. H6 S8 N% n% G
  360. {
    . I5 M. `) d! E# Z
  361.   *length = sizeof (USBD_Composite_CfgDesc);
    . R2 J# \! n5 A$ Z* a5 p
  362.   return USBD_Composite_CfgDesc;
    ; \" n% P8 I, X# W1 H- N; n$ A6 v
  363. }
    & F9 X" T. F8 l
  364. . P0 g( u! V' c7 x# c+ o. c
  365. uint8_t  *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length)
    6 o' g8 ~, ?3 I0 T
  366. {
    3 O# X- M: Q. Y/ }& p" p2 P( z( Z
  367.   *length = sizeof (USBD_Composite_CfgDesc);
    % _  m0 V3 B3 {
  368.   return USBD_Composite_CfgDesc;
    + F" C  w- R. n$ ^! O5 b5 D+ R
  369. }
    / t' f' m) Y/ Q! X7 E( a

  370. $ V# d8 a# ]0 B
  371. uint8_t  *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length)
    ' v) m0 Q9 I) x6 B# K+ L
  372. {+ U& [5 A0 P4 ]5 X
  373.   *length = sizeof (USBD_Composite_DeviceQualifierDesc);" i/ e8 I9 O/ }& `8 P: G  r
  374.   return USBD_Composite_DeviceQualifierDesc;
    ; v0 M2 s# Z3 U# R
  375. }! B& C% u- @' r3 z

  376. 3 U! U8 K+ Z- E3 I. L
  377. static uint8_t  USBD_Composite_RxReady (USBD_HandleTypeDef *pdev)
    3 Q4 G0 l- m* u( J
  378. {
    . a5 m! U# H5 O! e7 s
  379.         uint8_t ret = 0;
    4 B( o* }# k1 J; W1 q8 y9 a
  380.         switch(pdev->request.wIndex)  // wIndex是接口编号,这里我们通过接口编号确定CDC还是其他设备的EP0接收
    3 e4 L0 h9 V$ e; ]9 |2 {
  381.         {
    + _% C! m' d1 z2 G: y9 Y) @  t7 @
  382.                 case 0:  // CDC的命令接口编号是0
    , G" P1 P9 X, g1 _6 L
  383.                 case 1:  // CDC的数据接口编号是1
    & P5 J* J: y3 d# j% y' V
  384.                         USBD_Composite_Switch_CDC(pdev);5 M' u5 \' q3 i4 J4 T
  385.                         ret = USBD_CDC_EP0_RxReady(pdev);6 ?+ P* y) U0 W6 G8 m
  386.                         break;+ a+ o4 H2 H3 ~  e" N
  387.                 // 如果有其他设备还用到了EP0接收,在这里加入
    9 Z/ e4 g- h4 ?4 M+ @' D
  388.                 case 2:$ A; x8 H3 N1 m
  389.                         break;
    / B# a3 y6 f+ \8 }+ e  J. w
  390.                 default:break;
    2 ?( c4 Z/ C# M9 a$ X/ }
  391.         }
    ( E( {# ^  t: `
  392.     return ret;7 m/ t& \* ~- Y6 _4 ?/ \; \0 h# v. W
  393. }
    ; g1 m. u4 n/ u; L& L1 q) f" T

  394. # q( u. |& m% P/ P2 ?
  395. static void USBD_Composite_Switch_MSC(USBD_HandleTypeDef *pdev): S5 D$ O1 \7 R! f6 V9 x
  396. {
    " f3 U7 e. j/ [4 p
  397.         static USBD_MSC_BOT_HandleTypeDef USBD_MSC_Handle;
    2 N0 p) {/ _' Y; ^8 i) [9 J) g6 O
  398.         USBD_MSC_RegisterStorage(pdev, &USBD_Storage_Interface_fops_FS);
    ! m" K$ V. n* L
  399.         pdev->pClassData = (void *)&USBD_MSC_Handle;% Z  Q$ z6 m. p. O5 r
  400. }
    9 {  Z) P1 |/ q

  401. 1 Y- A0 J6 V0 s3 |3 p! S+ H! I
  402. static void USBD_Composite_Switch_CDC(USBD_HandleTypeDef *pdev)
    ' P9 C) p' |0 J$ ?5 l/ a( N
  403. {) B/ E2 t8 m; c
  404.         static USBD_CDC_HandleTypeDef USBD_CDC_Handle;
    - ?  X4 z) f/ R5 a7 t6 ]0 F5 q
  405.         USBD_CDC_RegisterInterface(pdev, &USBD_Interface_fops_FS);
    - R! t% D" o; E/ q: a5 X; L  l. d
  406.         pdev->pClassData = (void *)&USBD_CDC_Handle;5 `6 B2 i, \+ r% C
  407. }
    7 i2 s. _" Q; _" f* s
复制代码
5 V, m* Q" f' Q5 \
其中有关设备描述符的修改,我都用+++lakun进行了标注,并写上注释,方便查看。1 u% Y% O! F: C5 ^# W3 w( g

( x1 v) P6 c! h: J第五步:MX_DEVICE_USB_Init修改
7 W3 W( n2 Q! i( a7 v5 _. H# [上面我们已经完成了统一接口的编写,现在就可以修改MX_DEVICE_USB_Init函数了,屏蔽掉接口注册函数USBD_CDC_RegisterInterface,然后将类注册换成我们自己的组合设备,如下图:
% T1 c. a$ T3 A- ~: C- t
5 f" H" {4 a& e$ e1 |( k. g, W& m ~V(N24[X4FFR~H~TYROQ{5N.png
5 U' o+ s- L, r  O3 P" g/ B) S) @; p1 G; Q/ ]* m
到这里就已经改完了,运行程序之后设备管理器会出现:一个组合设备、一个虚拟的串口、一个USB大容量存储设备,如下图:7 B* F: A7 n8 C

+ V5 J9 ?% e3 R. m  s 20210425090801727.png 0 y2 x& J* b% Y) |. c* t
% r. x9 ?: r  {
这样就是成功了!
7 e6 p: M- M: M9 P! k( O
9 `4 k+ T  J! K1 r5 N!!如果修改过后发现设备管理器的MSC或者CDC显示感叹号,那么在回头检查PMA的配置以及组合设备描述符!!
% w7 h% o/ p) L
) Y6 {$ F# Z7 D遇到的问题5 O- T* `2 d8 [  k: w
我修改完毕之后,将板子接入电脑,虚拟出来的串口没问题,但是就是死活认不出U盘,后来找到问题的原因是因为我先使用的CDC串口这个单独的工程,我的win10已经默认枚举成了CDC,所以认不出U盘。% m- p6 X7 q* t  z* _

9 `, Y0 W1 P$ N1 G3 J- I解决办法:2 f" p1 m- k+ U, x& v6 T# i3 ?7 p
1.卸载识别出来的串口,重新拔插) i8 y' U% F7 |* h3 `% b; B+ _* x' ^
2.在程序里修改一下PID
7 [! m, U0 M/ w( u0 H# Z% y/ L
+ ^# a) N0 {/ U- e. u, G. D! [; ]5 |* ^% T& |! \  W, H
S30Z~TQ%1__%MHK`IJ2XN6N.png
- ], a) Z# M6 \! V8 O
/ d5 D5 S6 N' J. j  \4 c我是用的第二种办法解决的!6 q6 \* P( a& C5 A2 X2 b
0 H5 p/ I- U; B  g5 K3 x- ~. M4 j2 |

: n: x: x7 A8 p9 E, C
. X: \& b! g( T) W4 A" ]" F8 A
收藏 评论2 发布时间:2022-4-9 23:20

举报

2个回答
小白小灰 回答时间:2024-12-14 13:36:11

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

小白小灰 回答时间:2024-12-18 09:33:46

小白小灰 发表于 2024-12-14 13:36
不需要composite.h吗?编译出错,有几个没定义的。能给个源代码吗?不胜感谢
...

是拼写错误导致的,程序可以运行。谢谢

所属标签

相似分享

官网相关资源

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