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

【经验分享】STM32 USB虚拟串口

[复制链接]
STMCU小助手 发布时间:2022-1-13 21:00
串口调试在项目中被使用越来越多,串口资源的紧缺也变的尤为突出。很多本本人群,更是深有体会,不准备一个USB转串口工具就没办法进行开发。本章节来简单概述STM32低端芯片上的USB虚拟串口的移植。在官方DEMO中已经提供了现成的程序,这里对修改方法做简单说明。

- L" w( |9 p: N# q& \2 e, }& C( m: w' ?0 W; r
首先打开官方demo我们开始进行移植,第一步复制我们可用的文件,操作如下:
Projects\Virtual_COM_Port文件夹下,复制红线部分
图1
+ w9 l9 P# L' ?  T- O9 _
300035032772082.jpg
* v' L) U+ {! y0 H( I! }
图2

: ^3 C. p" w. S9 ?% w
300035202932682.jpg

- F4 M) M  o8 y8 d) J
我为了方便演示统放在usb/src文件夹下:
图3
/ g- ~" s8 l( z5 R* M3 t3 j" p0 y
300035313246246.jpg
, D( ^( i: j1 B! z3 t
现在复制USB的库文件,这些文件不需要我们修改:
图4
: J# u1 e. k1 l/ W: H4 x$ g
300035404189967.jpg

1 Y, t  ^/ S7 k
上图中的文件统一放在usb/lib文件夹下:
图5
/ O; K) q( X9 N$ d. Z
300036032935279.jpg

- Y& c5 ]: m8 [" B0 N# n, e' L- ]6 Y9 \4 ^; a
         好了现在所需要的文件我们以复制完了。这里先讲一下DEMO程序的主要工作流程:
9 [, ^! v& p9 A! ~: p2 Y) e7 o
300036178402768.png
7 K) u' l1 `6 h3 m$ w9 T. L2 y- l1 C
图6
         由上图可知,PC通过虚拟串口发送数据到STM32 usb口,STM32再通过usart1发送数据到PC串口。我们做项目时,只用USB虚拟串口即可。所以我们现在需要把串口发送部分删除。把USB做为一个COM口来使用。我们要如何使用这个USB口呢?demo中是把USB发送数据做了一个缓存,先把要发送的数据存入缓存中,然后由USB自动发送出去。而接收部分是直接通过串口透传。我们在应用时就需要用到两个FIFO,1是发送,这个和demo方式是样;2是接收,接收也做一个缓存,我们通过查询来判断是否收到新数据。这下大家应该明白为什么使用两个FIFO了。 我这里有写好的FIFO库函数可直接使用Queue.c文件。
         现在开始修改:
1,stm32_it.c 更名为usb_it.c删除无用代码,只保留usb中断函数,和唤醒函数。代码如下:
代码1
  1. 1 /* Includes ------------------------------------------------------------------*/* L4 y& ~& \& U3 v* o. d
  2. 2 #include "hw_config.h"5 e  I5 c" ~% y! d4 R+ g
  3. 3 #include "usb_lib.h"1 V8 h* ~: x) J5 t
  4. 4 #include "usb_istr.h"
    2 w) f! o6 }* [3 a
  5. 5
    / H4 A( @7 v, {; g
  6. 6
    " p# M/ C( f' Z+ _3 L. \* ~. I- S. ]4 Y" |
  7. 7 /*******************************************************************************
      _% Z0 l* [( v9 x8 o  k% i, r
  8. 8 * Function Name  : USB_IRQHandler2 Y1 ?6 V$ g- e7 q
  9. 9 * Description    : This function handles USB Low Priority interrupts2 L: @5 e$ }4 L0 ?
  10. 10 *                  requests.: \4 G. H1 @! i) k& r( y3 G4 r
  11. 11 * Input          : None
    . L  r7 {. [1 y4 L& A5 k6 C
  12. 12 * Output         : None' s: D9 @' {' Q( u- K
  13. 13 * Return         : None
    - M3 W- L( ]1 P% b7 T, l
  14. 14 *******************************************************************************/
    , H* e/ G. P( ]2 }% [' U0 x% l
  15. 15 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)|| defined (STM32F37X)
    1 n; D: S/ k/ J+ [4 Z: J; B
  16. 16 void USB_LP_IRQHandler(void)# X: h1 a7 V8 q
  17. 17 #else" B# _5 r8 y. h. c+ B& N
  18. 18 void USB_LP_CAN1_RX0_IRQHandler(void)
    2 v2 k. Q+ M. f  p
  19. 19 #endif3 y4 r0 ?" O8 C
  20. 20 {" H& ~' _7 O  o* F! b- Q
  21. 21   USB_Istr();
    * w# p0 y/ a/ I9 g
  22. 22 }( c; ]  D& _* ]- T: @
  23. 23 % _0 ]$ ~; ?' o+ v, G5 X9 @  h% X
  24. 24 /*******************************************************************************6 ?2 {7 y( E) Q3 f+ b
  25. 25 * Function Name  : USB_FS_WKUP_IRQHandler
    - Z3 c' K1 ^. o' Z- J/ i( ~
  26. 26 * Description    : This function handles USB WakeUp interrupt request.# B- A7 C* c  g: n" s  Q
  27. 27 * Input          : None: P6 y/ y' J& l$ X
  28. 28 * Output         : None
    & N2 ]. Z* \+ t
  29. 29 * Return         : None
    8 W9 w& v3 `! t: p7 u8 X: x' O( \* W
  30. 30 *******************************************************************************/
    ' J) ?7 i& R: ]  r! k
  31. 31
    6 g; C6 r0 X6 w6 C
  32. 32 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)- x  q* `: w* m9 e7 }
  33. 33 void USB_FS_WKUP_IRQHandler(void)
    $ J4 {! s0 z% o- n0 {# D6 e
  34. 34 #else
    8 O8 E5 M5 v  X1 E) \6 J; L
  35. 35 void USBWakeUp_IRQHandler(void)% c2 Z# z4 B  b
  36. 36 #endif3 T  q7 e2 _7 p. e9 K' Y+ K# i  ~
  37. 37 {3 |. }7 |" M! t* I  p
  38. 38   EXTI_ClearITPendingBit(EXTI_Line18);/ I, N3 D2 U5 n3 F
  39. 39 }
复制代码

7 `, Z" n0 V- _1 F
2,修改代码hw_config.c删除无用代码,新建立2组,读FIFO和写FIFO的函数。后面会用到。
代码如下:
代码2
  1.   1 /* Includes ------------------------------------------------------------------*/3 @" ~' u' c4 Q( h# h: C
  2.   2
    # z3 ~4 C2 L5 `5 N# E0 y
  3.   3 #include "usb_lib.h"
    " V) \) \% u% S8 F3 _( r
  4.   4 #include "usb_prop.h"1 l# y2 ]2 U$ R+ _0 }) Y# C3 G( i
  5.   5 #include "usb_desc.h"
    ; {) r  L" ~6 @- e5 M0 r% b- z8 ]9 x
  6.   6 #include "hw_config.h"
    3 V6 L: q, u0 d3 U! _; d& p
  7.   7 #include "usb_pwr.h"
    , N! f  n( W- k" Y
  8.   8 #include "Queue.h"& _$ a# w* b* t. p8 Y. ?1 I
  9.   9 ) r  i' P# l' f" A+ r$ o! Y' c
  10. 10
    $ @: |; l& w( z* q5 r5 f
  11. 11 /* Private typedef -----------------------------------------------------------*/% g! [0 W" z  _( Y& Z3 ^0 d
  12. 12 /* Private define ------------------------------------------------------------*/
    ( W0 |* x6 k  [7 \
  13. 13 /* Private macro -------------------------------------------------------------*/
    5 C& f2 G" q' g! ^* u0 A7 h
  14. 14 /* Private variables ---------------------------------------------------------*/- X' D) k( r, }& P
  15. 15 ErrorStatus HSEStartUpStatus;# S6 h8 E- Q; i7 K6 ?5 p9 j' Y! |
  16. 16 USART_InitTypeDef USART_InitStructure;. M  @- g/ z& u1 g$ b
  17. 17 EXTI_InitTypeDef EXTI_InitStructure;
    4 ]4 x) Z4 x7 N; v2 p; v
  18. 18 1 E$ Z  ?8 L" x" S1 E& j3 E/ {
  19. 19
    9 y0 G. d* F& l
  20. 20 #define USB_COM_RX_BUF_SIZE         (1024 + 256)
    " e' C3 h3 l2 U7 F% Y% j2 U+ D" J
  21. 21 #define USB_COM_TX_BUF_SIZE         (1024 + 256). s5 N3 ~  w( T7 W5 o/ @- v
  22. 22 + F6 s! r$ a. ]) N
  23. 23 static QUEUE8_t m_QueueUsbComRx         = {0};9 Y' U0 e  y+ E4 P" a+ N' r5 D
  24. 24 static QUEUE8_t m_QueueUsbComTx         = {0};
    9 x% O4 x. o( h/ z2 @+ M
  25. 25 static uint8_t  m_UsbComRxBuf[USB_COM_RX_BUF_SIZE]      = {0};     ' g% j% J( [; x6 ?3 e
  26. 26 static uint8_t  m_UsbComTxBuf[USB_COM_TX_BUF_SIZE]      = {0};   . _4 L' D  Q% ]4 ?' b
  27. 27
    & U1 y1 g1 R( |: Q! K, J
  28. 28 static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len);  l0 b: S6 ~1 T2 X0 E# j/ R
  29. 29 /* Extern variables ----------------------------------------------------------*/
    * ^. p+ w( u& q) R. g  V8 S, B3 Y
  30. 30 . ~& l, H4 Z* P. ]' Z  S  _- L
  31. 31 extern LINE_CODING linecoding;
    $ W& E: ?0 N$ R. |/ _: y, T$ O
  32. 32
    / n) o4 \! k- W8 b1 L1 l% e
  33. 33 /* Private function prototypes -----------------------------------------------*/
    9 D, ^$ {' y8 q( J
  34. 34 /* Private functions ---------------------------------------------------------*/
    4 Q8 f2 X! N" T8 m( O6 ~
  35. 35 /*******************************************************************************
    & Q& N; j; i5 f' }, x
  36. 36 * Function Name  : Set_System
    4 P6 `/ t% n6 v" N- M8 d: X6 z
  37. 37 * Description    : Configures Main system clocks & power" A: F/ F# a: a$ b4 Q
  38. 38 * Input          : None.6 k6 C3 t- ~5 R" X# s& i8 Y
  39. 39 * Return         : None.6 ^3 g: {+ ~: G5 Y
  40. 40 *******************************************************************************/
    9 p9 B* d) J: ~
  41. 41 void Set_System(void)) L# @1 e5 V- K0 r
  42. 42 {
    7 [/ H& N! D. |) ]. O4 ]
  43. 43   GPIO_InitTypeDef GPIO_InitStructure;$ U. ?4 P% i+ |* N
  44. 44 1 ]1 q9 b9 \( ?/ v' t- |
  45. 45   QUEUE_PacketCreate(&m_QueueUsbComRx, m_UsbComRxBuf, sizeof(m_UsbComRxBuf));5 M, K7 Y) b( g* ^
  46. 46   QUEUE_PacketCreate(&m_QueueUsbComTx, m_UsbComTxBuf, sizeof(m_UsbComTxBuf));
    # ]" Y# I) K2 G3 K8 W
  47. 47   
    2 r5 l. j0 w3 z& [9 n9 w
  48. 48   /* Enable USB_DISCONNECT GPIO clock */+ ]3 ?# P, `+ J" t) o! E
  49. 49   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);8 D% g" R  h! B! ?. N9 p% K, `
  50. 50 9 s, p* b5 @, l$ B  L, W; Z/ t2 y
  51. 51   /* Configure USB pull-up pin */5 J0 V: F% H* b0 O
  52. 52   GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
    3 ~7 z( K0 s; ^4 p' `
  53. 53   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;0 A+ m# |. w% N: D
  54. 54   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    8 R$ q! f  {; |6 g9 F& l* z6 s/ T
  55. 55   GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);
    ) K7 T% s/ R3 [. b# H. s
  56. 56   0 u+ t, A& W8 S7 M
  57. 57   /* Configure the EXTI line 18 connected internally to the USB IP */
    ) k& A( y3 I' p9 G8 F$ B: X3 `
  58. 58   EXTI_ClearITPendingBit(EXTI_Line18);7 s9 @* q7 k8 m/ e! l0 t
  59. 59   EXTI_InitStructure.EXTI_Line = EXTI_Line18;
    ; }. s' o- b( Q! q! z+ F
  60. 60   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    2 p) G/ |6 L) U3 ~& c" q9 F
  61. 61   EXTI_InitStructure.EXTI_LineCmd = ENABLE;. X$ l% `; A, D. O7 z9 P+ f+ t. \
  62. 62   EXTI_Init(&EXTI_InitStructure);
    + o: Y( o. W6 p% Q$ _% C
  63. 63 * ^( V/ f: G9 f0 o3 V5 @
  64. 64   8 N/ \4 H- ]5 y! M4 B) z0 O( n
  65. 65 }
    4 D1 {  o- q3 w$ i! S$ \
  66. 66
    . D% K& r# m9 p. D9 {
  67. 67 /*******************************************************************************
    3 |& u& h( |! A
  68. 68 * Function Name  : Set_USBClock
    : m6 e# x! ?/ b$ {/ ?: X5 O
  69. 69 * Description    : Configures USB Clock input (48MHz)! o! m! a- G: g8 {8 w2 X- ?+ O
  70. 70 * Input          : None.' {( n# ~: H# w: ^* r. ~( A) T
  71. 71 * Return         : None.
    8 I6 I- `, h  G6 q
  72. 72 *******************************************************************************/
    ; H. m4 R  _( l3 k$ s/ z9 B
  73. 73 void Set_USBClock(void)
    % q9 I+ v1 k6 ^+ b7 y2 l# p3 L
  74. 74 {& h: s0 a' ]* c* t9 A% d; T( H, }
  75. 75   /* Select USBCLK source */. b7 b- J: k- O8 X2 K
  76. 76   RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);  v0 f7 V. f( a9 ]2 E
  77. 77   
    5 A: ]% _+ s4 q  D$ M
  78. 78   /* Enable the USB clock */
    # h3 Q# d6 n; e/ H7 {1 w2 r% z
  79. 79   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
    5 m% e" n. r3 G" c" k+ a7 W% W
  80. 80 }& F% W$ Z2 S/ F6 [. r
  81. 81 4 `" {. k% C7 c9 W5 }1 k& s3 d& y+ F
  82. 82 /*******************************************************************************' \* w& w2 l; y- D
  83. 83 * Function Name  : Enter_LowPowerMode! C6 L2 c: t/ Q9 t; j; I2 |$ {: R( f
  84. 84 * Description    : Power-off system clocks and power while entering suspend mode) V% Z7 c% N8 O; Y( U& c/ s3 q
  85. 85 * Input          : None.
    + L- R1 D5 Y" z  j, T
  86. 86 * Return         : None.
    ! v! Y% [( m0 j" i
  87. 87 *******************************************************************************/
    : X3 v0 h  p7 [% c1 l# Q
  88. 88 void Enter_LowPowerMode(void)9 @- g- S" O( l7 |, a+ V
  89. 89 {4 K9 k, e. y3 U0 g+ J
  90. 90   /* Set the device state to suspend */0 p. r4 U9 J- N0 V
  91. 91   bDeviceState = SUSPENDED;
    # D* h. v, w. H) t: k6 |
  92. 92 }5 \4 C; g6 J7 w3 n8 z1 Y# Y3 J8 a
  93. 93 ) y' H1 L3 V& l, O$ h6 n2 E$ Q5 @
  94. 94 /*******************************************************************************
    9 J' k( b8 G2 s7 Z5 s
  95. 95 * Function Name  : Leave_LowPowerMode
      E+ p9 H, D: z' w" _% ~) F
  96. 96 * Description    : Restores system clocks and power while exiting suspend mode
    ' {7 c  J3 k& I" X( m$ D6 {
  97. 97 * Input          : None.9 h, z  z7 @: b9 A
  98. 98 * Return         : None.
    2 A2 G& f: c4 S9 d6 E  J
  99. 99 *******************************************************************************/" {0 t) ~% x* F$ [. N9 O1 y
  100. 100 void Leave_LowPowerMode(void)
    - d* P8 u4 r( [3 \# ~" W
  101. 101 {3 y% N9 j3 B8 i. K
  102. 102   DEVICE_INFO *pInfo = &Device_Info;' G; \5 A$ o$ J/ U
  103. 103 9 U6 W) |9 r2 }  L
  104. 104   /* Set the device state to the correct state */
    / v' L3 h9 @0 T4 Z) j
  105. 105   if (pInfo->Current_Configuration != 0)
    - s( K8 i5 j( \. _
  106. 106   {0 ^3 V6 d& N8 A+ M; b
  107. 107     /* Device configured */
    7 S5 V+ e* G6 s1 |
  108. 108     bDeviceState = CONFIGURED;
    ; T1 ?' `- U/ d- X0 ]6 l" v. L+ B
  109. 109   }
    $ `8 \) T/ w& a/ \, G  y' U% W( Y
  110. 110   else
    & D* U% A1 g2 I0 U; g! f
  111. 111   {' C& f( Z. l6 @( E
  112. 112     bDeviceState = ATTACHED;  q' Y& {7 U* X! G" s
  113. 113   }$ C; `- C- F3 [
  114. 114   /*Enable SystemCoreClock*/7 M3 K: Q- e7 z& H4 l
  115. 115 //  SystemInit();
    - e$ Q; L) _9 L. M. w
  116. 116 }
    + `9 U% D6 o3 }* ]! J
  117. 117
    " _# F% `& n* _& a5 J: ?" e
  118. 118 /*******************************************************************************
    - E. q( K/ ?9 _
  119. 119 * Function Name  : USB_Interrupts_Config
    + I6 Y; s2 \1 O1 D& N: J
  120. 120 * Description    : Configures the USB interrupts( \" [/ F! G' O
  121. 121 * Input          : None.
    1 j7 i+ t$ ]$ S# \3 S" C$ B. y
  122. 122 * Return         : None.
    ' R( a8 f& t! h* j9 M
  123. 123 *******************************************************************************/
    & B1 n5 X" e/ q/ Z# `
  124. 124 void USB_Interrupts_Config(void)  K. _: S6 i# _+ X7 W4 I- e: y
  125. 125 {' ~1 B- ^+ t2 |$ S; K- z% T
  126. 126   NVIC_InitTypeDef NVIC_InitStructure; 0 A* c- T. O; f* Y2 g
  127. 127
    8 n! {9 [0 C5 f/ i$ |
  128. 128   NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    8 s+ \2 _  @& B( L. C
  129. 129   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;* T4 O; a9 j' P( w' \
  130. 130   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    . M$ r* ^" P: _+ Z; c* `
  131. 131   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    4 O7 z. j. k, J0 |& l* W6 x
  132. 132   NVIC_Init(&NVIC_InitStructure);
    7 r% t, }# Y" u; T7 a& x& q( M
  133. 133   
    . R' Y0 Z9 D0 a+ F) u
  134. 134     /* Enable the USB Wake-up interrupt *// W' O; s' U. d+ A, A9 a4 r9 q
  135. 135   NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;. U2 X8 N: h! t- O+ u3 ?
  136. 136   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;6 P# T; _2 j7 ^, i
  137. 137   NVIC_Init(&NVIC_InitStructure);
    4 F% U" g: |% B4 L- ~
  138. 138 }5 L$ g% ^% H# c! Z" R1 Y
  139. 139
    ; B4 F3 _8 Z9 }7 a4 u/ h
  140. 140 /*******************************************************************************; ~3 \( `/ \2 v3 ^$ @' B
  141. 141 * Function Name  : USB_Cable_Config
    % X2 f6 w0 D+ w* G5 i: v0 }  S$ A
  142. 142 * Description    : Software Connection/Disconnection of USB Cable- K5 C2 S7 ~. i4 E+ b
  143. 143 * Input          : None.5 r5 q2 J) ~! B; N9 r6 R; w
  144. 144 * Return         : Status5 O- G$ h1 t! E) w& ?9 O
  145. 145 *******************************************************************************/
    9 r0 R8 w/ w6 |
  146. 146 void USB_Cable_Config (FunctionalState NewState)
    : O7 j; ~  @4 q7 w* S
  147. 147 {
    ' T" F4 G2 U8 a. P2 p# x" t
  148. 148   if (NewState == DISABLE): Y; Y4 n0 `+ I0 Q" ]
  149. 149   {2 U$ \/ S  T6 w5 D" v$ G' B
  150. 150     GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);8 M& r$ y' M3 H/ [3 q2 }* ?+ }1 H+ S
  151. 151   }
    8 A. Y/ S  R4 X! N; e
  152. 152   else
    3 F- J; c8 j/ M4 w. \( _
  153. 153   {# J- F) h3 L8 s- `2 y
  154. 154     GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);5 x1 p* b) Q  q* ?: P4 a. y+ k
  155. 155   }
    - @( _1 ?3 W' h) m/ |, W! D' I
  156. 156 }
    ' @$ D+ c; S+ d5 R/ U" q
  157. 157 : M, j" i' W, H; I
  158. 158 /*******************************************************************************
    + u! M' |* m- L3 O5 s1 ]) U/ T; l, f
  159. 159 * Function Name : void USB_Config(void)# Q/ T4 g! A! d& m6 e
  160. 160 * Description   : USB系统初始化
    ) d" r0 w$ Y& G3 ~, W! h" ~
  161. 161 * Input         : ; N0 N. B: R: n# A, G8 i
  162. 162 * Output        :
    4 R1 E* p/ L1 v) r# [: q/ n
  163. 163 * Other         :
    , A, z, O- ]$ F
  164. 164 * Date          : 2014.11.28: _+ @' x! ^3 Z; ]6 s  K- P* i& L
  165. 165 *******************************************************************************/  G7 z% S3 L: I/ G* T0 F5 n, V$ X
  166. 166 void USB_Config(void)
    . b% w0 |2 W- ~7 j3 z" q! g% j
  167. 167 {
    . P/ B/ Q: s, t3 N
  168. 168     Set_System();
    ( \' V% J6 q; G9 Y; E  q- J
  169. 169 - Z7 f/ \$ W/ W
  170. 170     Set_USBClock();5 i% {; \& J( e* ^& \7 a
  171. 171 2 E5 u! |. e4 E7 y% D7 P7 Z
  172. 172     USB_Interrupts_Config();' k3 H9 U- G# s
  173. 173
    * a5 ]" l* w' L
  174. 174     USB_Init();) V7 k3 s; E$ H9 S! N* I
  175. 175 }
      Y+ b- a  m* U# \# }' Y
  176. 176 & j: S7 z+ k7 u
  177. 177 /*******************************************************************************
    9 F: h- s6 ?8 k6 f6 I: V) {
  178. 178 * Function Name : uint32_t USB_RxRead(uint8_t *buffter, uint32_t buffterSize)
    - C' b' P8 o4 O9 a$ M
  179. 179 * Description   : 从USB接收缓存中读数据
    8 m6 J* }+ K% }  f/ ]5 j8 ]
  180. 180 * Input         :
    8 I7 |# v0 D8 }* K1 E. E" x4 N
  181. 181 * Output        :
    ; t' V8 x5 E! m, W; A+ V  M
  182. 182 * Other         :
    0 M8 j2 j- b8 X% L. `+ O5 U2 {
  183. 183 * Date          : 2014.11.28" O  W4 J: q; h1 P# M9 }6 |6 I$ b
  184. 184 *******************************************************************************/
    2 T3 A- S; h7 t' v3 Y% E
  185. 185 uint32_t USB_RxRead(uint8_t *buffter, uint32_t buffterSize)
    3 W, \$ L1 J3 u# [
  186. 186 {
    . Q8 h1 N2 U/ t+ X
  187. 187     return QUEUE_PacketOut(&m_QueueUsbComRx, buffter, buffterSize);% s8 `5 J: y1 ~" e
  188. 188 }* |9 V6 {: m- d9 f* c
  189. 189 /*******************************************************************************2 z8 T1 a8 B# X* w! B$ P
  190. 190 * Function Name : uint32_t USB_RxWrite(uint8_t *buffter, uint32_t writeLen)
    + M- z! `0 H/ m1 j
  191. 191 * Description   : 写数据到USB接收缓存中5 H, A- F9 O1 E( X1 d: C
  192. 192 * Input         :
    0 A3 q0 X8 [# c) m/ I1 X+ o
  193. 193 * Output        : ' E3 L1 z; [( I  c+ w
  194. 194 * Other         :
    - v. E0 B; z+ K9 l$ C' p
  195. 195 * Date          : 2014.11.28
    2 ~! m; `' M8 S( {+ K
  196. 196 *******************************************************************************/" G5 Q. k$ K6 u( {4 |( D
  197. 197 uint32_t USB_RxWrite(uint8_t *buffter, uint32_t writeLen)
    7 E' z5 [6 q  j0 s
  198. 198 {3 l7 z; T+ Z7 C
  199. 199     return QUEUE_PacketIn(&m_QueueUsbComRx, buffter, writeLen);# u9 q# W9 R! {1 @2 N7 g
  200. 200 }7 G& v+ d* D& _" h) m, M, e8 y
  201. 201 /*******************************************************************************
    - p9 O  u+ n9 Y1 Y# \9 B1 X
  202. 202 * Function Name : uint32_t USB_TxRead(uint8_t *buffter, uint32_t buffterSize)) {$ U8 _  F8 D4 F( x  A
  203. 203 * Description   : 从USB发送缓存中读数据
    8 ^3 b9 [- p  `9 z: q! P, T* q
  204. 204 * Input         :
    3 W& T6 l6 y8 b- G9 n5 h
  205. 205 * Output        : 5 i) y" D8 N5 n# F0 r
  206. 206 * Other         :
    : [4 g" C. V& d: ~( j
  207. 207 * Date          : 2014.11.286 {* i' A( G9 A
  208. 208 *******************************************************************************/
    ; k# C5 N1 P9 G& h; G
  209. 209 uint32_t USB_TxRead(uint8_t *buffter, uint32_t buffterSize)
    " E0 e; E0 N( ]) ]/ U5 O: ^& T+ K
  210. 210 {
    % ]: K& a- ?2 Q* \' v# t' F6 }
  211. 211     return QUEUE_PacketOut(&m_QueueUsbComTx, buffter, buffterSize);;
    % T+ M) w. ~% p9 R& x8 L
  212. 212 }) S: ~2 l3 G" @9 d6 W! ]7 A2 h
  213. 213 /*******************************************************************************
    / A1 j% n) z$ S/ l9 B3 d
  214. 214 * Function Name : uint32_t USB_TxWrite(uint8_t *buffter, uint32_t writeLen): }  p! {  O  \- t% l; k$ b5 w" ~# m
  215. 215 * Description   : 写数据到USB发送缓存中* O) F0 g0 i7 s5 g, d- \: j
  216. 216 * Input         : ) `+ n$ P+ u% d. D; q; Z: u$ ^
  217. 217 * Output        :
    ) d. }9 J8 Y& q& C9 i5 ]% b
  218. 218 * Other         : " w' p$ d" @* J/ s" ~
  219. 219 * Date          : 2014.11.286 ]) _& H: q% t7 m& s. p
  220. 220 *******************************************************************************/# F4 J$ \9 M4 l) e/ ]3 @' }
  221. 221 uint32_t USB_TxWrite(uint8_t *buffter, uint32_t writeLen)
    - e5 l$ f3 d4 p
  222. 222 {# E' [- Y2 w% l
  223. 223     return QUEUE_PacketIn(&m_QueueUsbComTx, buffter, writeLen);6 F9 u- a+ S6 a% W
  224. 224 }0 d8 _: S6 O# R& H8 ], S
  225. 225
    6 ^4 h# C! Y. i! j$ t: R
  226. 226
    $ w. W' P! D4 \5 r* p, f
  227. 227 1 \; S0 u: S& h$ L" p( x" ~# J6 [; V
  228. 228 /*******************************************************************************
    + l, J/ @9 T9 x% y
  229. 229 * Function Name  : Get_SerialNum., L# w% |. W+ t$ V/ w9 N
  230. 230 * Description    : Create the serial number string descriptor.
    1 [; ^. M# B- q9 ?
  231. 231 * Input          : None.  w+ n4 z! I6 Z! m- f
  232. 232 * Output         : None.
    9 R; }( K- g4 h2 U0 A5 p
  233. 233 * Return         : None.
    , Z! v! _- }( R% J. N& ]
  234. 234 *******************************************************************************/! y, M- }9 |4 y3 J  [8 u3 D
  235. 235 void Get_SerialNum(void)
    1 E0 o1 e4 f. k2 c9 Z0 K# o
  236. 236 {/ ^" _; G5 E( n! D- P
  237. 237   uint32_t Device_Serial0, Device_Serial1, Device_Serial2;- @# B# _& h3 J% v
  238. 238
    # g; V% i1 U  b1 ?1 w
  239. 239   Device_Serial0 = *(uint32_t*)ID1;) q: b0 G+ G. p- y" Q* a7 e
  240. 240   Device_Serial1 = *(uint32_t*)ID2;
    # H( A4 X$ }- K* K6 y
  241. 241   Device_Serial2 = *(uint32_t*)ID3;    z& t5 I, L0 y3 h
  242. 242
      E% {; T; \( W; `3 G6 F
  243. 243   Device_Serial0 += Device_Serial2;& d; M" ]+ I" Q8 q3 ^- K
  244. 244
    5 R4 i2 o" m, {( E- T7 o0 u6 l
  245. 245   if (Device_Serial0 != 0)  ^. B' T- {& S3 u
  246. 246   {) T% l3 R: x0 F# ~
  247. 247     IntToUnicode (Device_Serial0, &Virtual_Com_Port_StringSerial[2] , 8);
    3 X: O+ H; P; b1 B+ v% w( D
  248. 248     IntToUnicode (Device_Serial1, &Virtual_Com_Port_StringSerial[18], 4);
    0 q" T' }7 r3 r) ]
  249. 249   }% H( H" P7 s  @; H
  250. 250 }: [! X/ g) L6 c, g$ T1 G! c
  251. 251 ' }5 c2 J7 ~" A2 j- n' T
  252. 252 /*******************************************************************************
    . s( m3 _3 f6 c/ O* N
  253. 253 * Function Name  : HexToChar.
    . C! Y( X9 s5 J
  254. 254 * Description    : Convert Hex 32Bits value into char.6 n& [) a6 G+ z" S
  255. 255 * Input          : None.
    8 I) M3 P, [# f" N5 ?1 c
  256. 256 * Output         : None.- u& ?5 q( |( F5 g6 E
  257. 257 * Return         : None.
    6 |/ t+ b) Z$ Z6 ~! D# E
  258. 258 *******************************************************************************/* }/ M1 n6 S. V: b
  259. 259 static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len)+ T* j: F; g0 w' L  Z( ^
  260. 260 {1 v& \- z5 ?  q/ N4 ^1 W
  261. 261   uint8_t idx = 0;5 ?* q; i8 _' F1 v
  262. 262   
    0 A( n6 j; j4 W0 h8 ]5 h
  263. 263   for( idx = 0 ; idx < len ; idx ++)$ z; {4 ~! f5 B$ `4 s0 y
  264. 264   {
    - d& R6 H+ K/ w( E( T8 U' M+ O
  265. 265     if( ((value >> 28)) < 0xA )' W4 O8 I. t: G6 g8 A
  266. 266     {
    ; v) U7 s0 F. S$ H- p7 S+ h8 S
  267. 267       pbuf[ 2* idx] = (value >> 28) + '0';
    - }2 n% H$ c  E: X
  268. 268     }
    ; b5 @' a9 J& k2 }# J' c. Q- w- B
  269. 269     else4 R) b5 e8 |. {+ S: |  e" H
  270. 270     {
    ' ^, Z- e; e5 ^) W; b, M$ s
  271. 271       pbuf[2* idx] = (value >> 28) + 'A' - 10; 8 v1 F$ a% V6 }0 G3 n- F; Z
  272. 272     }: q9 Z, K% Y- v- Y6 _8 V
  273. 273     ) X% f: w$ u4 m' D% a: n5 H
  274. 274     value = value << 4;9 |( p" w  Q# P
  275. 275     , K+ t6 {2 [2 W) t- E
  276. 276     pbuf[ 2* idx + 1] = 0;
    * |7 X6 f; y$ }! V
  277. 277   }
    - G2 C( a! v! N7 [; j7 ~
  278. 278 }* n& x" ?9 B. d
  279. 279
    / M( Q8 ]$ R' |* i  j+ N+ d) ]
  280. 280 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码
$ h, p& z' L* ?' D6 n
  M7 C: i8 j0 t2 p/ F) P
这里要讲一下为什么要屏蔽SystemInit(),因为demo只运行虚拟串口功能,在USB未插入的情况下,是进入低功耗状态,插入时从低功耗状态退出后会调用此函数。当然我们在项目中一般不会这样,系统是否运行和插USB接口没有联系。所以我在下文中把进入低功耗代码屏蔽了,自然也就不用唤醒代码了。
图7
  |( I- @; [, W
300038465597900.jpg
( t% k6 x9 f4 s1 ]
关于USB口使能控制引脚,需要根据开发板的引脚定义来修改宏定义platform_config.h文件中,笔者使用的是神舟3号开发板,控制信号刚好和demo相反,所以修改hw_config.c代码如下:
代码3
  1. 1 /*******************************************************************************  _( W- V7 i5 L0 T
  2. 2 * Function Name  : USB_Cable_Config0 x3 b% E& ]. g. G% M
  3. 3 * Description    : Software Connection/Disconnection of USB Cable
    ( P" H6 q: R- n3 j: a  }( e$ t
  4. 4 * Input          : None.  S. m! x* ?0 P( R3 r
  5. 5 * Return         : Status
    * z0 A; B# h1 ?8 X. p) l
  6. 6 *******************************************************************************/
    + V2 F" e* y9 x9 A+ T8 M6 Q" x
  7. 7 void USB_Cable_Config (FunctionalState NewState)
    : z6 {$ x) [& \0 f3 x( K( k
  8. 8 {- _& i; w" d" [8 a* z4 ^
  9. 9   if (NewState == DISABLE), ?: q( d' X. I# }+ q2 @: H
  10. 10   {
    / N1 n, D. i( s# ?1 g& c, e( A
  11. 11     GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
    : L0 s9 x- p0 l( h* o
  12. 12   }
    * H+ e3 L/ W# v
  13. 13   else& ]) |3 e2 H5 r, ]6 V# s. p
  14. 14   {: ]# q' N0 A# A& r4 d7 p% E
  15. 15     GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
      _- w+ L+ o' e+ W' O" y8 p
  16. 16   }
    ) [$ u6 W; U/ H; V, F
  17. 17 }
复制代码

3 X( @( @! p1 O( e" ]
3,现在修改USB 回调函数中的代码usb_endp.c文件。使用下文代码替换:
代码4
  1.   1 /* Includes ------------------------------------------------------------------*/
    8 Q% D: X  P7 _/ [# W0 B
  2.   2 #include "usb_lib.h"
    / {- H4 c; U2 i
  3.   3 #include "usb_desc.h"
    ! N' ?: O  Z) {" |
  4.   4 #include "usb_mem.h"
    0 A$ c: |  U& |0 Q6 O7 u% k
  5.   5 #include "hw_config.h"
    % K4 e, |; E' z3 j
  6.   6 #include "usb_istr.h"+ S6 ~( s) d/ D) Z& k+ d3 B; T
  7.   7 #include "usb_pwr.h"( s" Z% }; J$ u* U
  8.   8
    ( r! u9 Z3 k; U! R: f3 h
  9.   9 /* Private typedef -----------------------------------------------------------*/6 k1 X+ P/ H5 C* i! F
  10. 10 /* Private define ------------------------------------------------------------*/
    8 ]2 T. t: m% `. C3 N
  11. 11
    - e9 k4 R" \  g
  12. 12 /* Interval between sending IN packets in frame number (1 frame = 1ms) */
    " B9 y$ M. B! B7 Z* t
  13. 13 #define VCOMPORT_IN_FRAME_INTERVAL             5
    ! n2 t0 b) P; k4 r0 B& |3 }! {4 q+ z
  14. 14
    4 z3 J" w% W+ x% K' o0 ?5 s7 O
  15. 15 /* Private macro -------------------------------------------------------------*/
    , f* ^2 S5 @& z' ]
  16. 16 /* Private variables ---------------------------------------------------------*/2 t- ~0 f/ m7 J( Z* ~" w
  17. 17 static uint8_t txBuffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};+ G. q1 r/ K! S
  18. 18 static volatile uint8_t txFlg = 0;  h& w# F/ w6 ~2 f# v! y
  19. 19 static volatile uint32_t FrameCount = 0;5 D- G; T3 ?7 G. R5 g+ o1 L
  20. 20 7 A/ V3 y2 w! u0 H- ~0 V5 h1 `) o
  21. 21 - w6 U1 _2 S7 i* j. Q; d7 l( \
  22. 22 /* Private function prototypes -----------------------------------------------*/  b9 o: i: g9 g
  23. 23 /* Private functions ---------------------------------------------------------*/4 f+ }, r. h' Y6 Z# @
  24. 24
    / Q" S6 F- M& G; B3 C$ v
  25. 25 /*******************************************************************************
    ( S& ?# e; a/ f- k4 H
  26. 26 * Function Name  : EP1_IN_Callback
    / ~2 F# M9 `8 u; K+ y( \
  27. 27 * Description    :
    : a. {$ r$ b/ ~1 q& U" F7 d
  28. 28 * Input          : None.6 C" q% p+ r9 e* F; l2 O6 }2 v" Q
  29. 29 * Output         : None.0 F( t. t9 j9 P
  30. 30 * Return         : None.
    ; P1 y" s4 T4 t, [
  31. 31 *******************************************************************************/; F& T5 E1 e8 s: I! h; N8 F
  32. 32 void EP1_IN_Callback (void)
    2 O  b  Z" V+ k6 k- G( S
  33. 33 {
    ; L# J# E% Z7 b) {8 r
  34. 34     uint16_t len = 0;
    8 J( K1 D  |3 f; o6 l
  35. 35     
    1 Q7 N  g( W. N8 Z! E. \
  36. 36     if (1 == txFlg)
    % `! A& B0 J# Y$ `' J
  37. 37     {
    . S3 ^  F+ u3 q7 Q$ N' C7 ?/ D6 _& ~
  38. 38         len = USB_TxRead(txBuffter, sizeof(txBuffter));
      J4 C5 O: D* L+ m8 C" g- `( J
  39. 39
    + F2 O( X  Q) |( F6 w. ~' z
  40. 40         if (len > 0)
    # M# p) U1 B: E2 l2 d
  41. 41         {  M" C. L  r8 B( ]+ g! g8 a( R% T
  42. 42             UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);
    9 E. O6 q# Z+ t: N0 b1 f
  43. 43             SetEPTxCount(ENDP1, len);  c) I8 @% L9 c3 Z# q4 [( Z7 X
  44. 44             SetEPTxValid(ENDP1);
    3 \3 X* g+ G6 B3 v7 A0 q' a+ {& `
  45. 45             FrameCount = 0;
    8 s) ~1 E; V2 \! |6 A+ }2 W9 B
  46. 46         }! I$ E5 N! w  u% e2 v
  47. 47         else. Z$ V5 L- v) e5 O0 B5 v
  48. 48         {
    9 N8 s6 R1 K" {
  49. 49             txFlg = 0;
    ' p6 i; ?' I* P2 a6 U/ N6 }# ]
  50. 50         }/ k' H4 f1 N# {' w  q4 u( D
  51. 51     }' ~9 B$ p0 [: r; i
  52. 52 }: x" G% p) J9 u
  53. 53 , g* ~+ r: T0 r5 J. S
  54. 54 /*******************************************************************************% C( P1 |! i9 Y; A; l8 `
  55. 55 * Function Name  : EP3_OUT_Callback
    : V3 v! f/ a" ~' M, c
  56. 56 * Description    :6 n* J- L- E! d6 G$ t4 y
  57. 57 * Input          : None.8 R2 c- Q7 m9 I1 U
  58. 58 * Output         : None.- K9 p% A3 W; S
  59. 59 * Return         : None.- R4 B5 M, ^4 V$ G/ j
  60. 60 *******************************************************************************/
    9 Y2 [+ ?+ D" J4 u0 c
  61. 61 void EP3_OUT_Callback(void)
    5 L5 n' M) v  d; C
  62. 62 {) G& W0 Q; m. K; E3 C  S+ B# _0 d
  63. 63   static uint8_t buffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};
    $ e! c6 T4 n/ D) T9 J8 v, j! F
  64. 64
    ' l# t0 q) M& P: ]# w
  65. 65   uint16_t USB_Rx_Cnt;
    7 o3 ?; `9 t, e; [
  66. 66   + X8 y( k2 e2 I& L9 X% t
  67. 67   /* Get the received data buffer and update the counter */
    7 k, W6 M  V) j9 ~
  68. 68   USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, buffter);6 D, L7 I/ W( }( }* `/ c0 z( B
  69. 69   
    8 ^- U# Q5 L& z8 w7 Q
  70. 70   /* USB data will be immediately processed, this allow next USB traffic being
    4 k; T+ q% _! r# N1 w2 o  Z
  71. 71   NAKed till the end of the USART Xfer */% p* B$ R/ _" g' Z
  72. 72   USB_RxWrite(buffter, USB_Rx_Cnt);
    ) d) u) O! ?! F  Q& a4 O* M
  73. 73 - {% t0 l. j$ q' N
  74. 74   /* Enable the receive of data on EP3 */9 v) q& n( a' L/ o
  75. 75   SetEPRxValid(ENDP3);
    + X( x. Z8 k; ]) L- {1 R9 e) o8 |2 B
  76. 76 9 }, i% B6 G; G) ^0 N0 t
  77. 77 }
    . z! R* ]& L. C) m
  78. 78 5 X  w) y2 d2 P( k8 F, t* A
  79. 79   B4 }/ t' J4 Z9 O+ l0 L8 n' S
  80. 80 /*******************************************************************************+ }* I0 j% V5 @1 O
  81. 81 * Function Name  : SOF_Callback / INTR_SOFINTR_Callback
    " _& p! Y8 r2 `! O
  82. 82 * Description    :/ t% [; k1 A: K! a. Q4 e
  83. 83 * Input          : None.
    6 u7 p8 [$ k1 N+ I/ ?8 w4 w* E
  84. 84 * Output         : None.( I9 ^2 n4 [. x( I
  85. 85 * Return         : None.+ U8 s9 S' X' g) n- `) _3 Q8 n
  86. 86 *******************************************************************************/1 t% S8 {& O, Y* a
  87. 87 void SOF_Callback(void)1 z* E: ?: t4 i+ _9 b1 H8 d- Y
  88. 88 {
    ' [' |6 Y; s( h
  89. 89     uint16_t len = 0;
    " x8 G6 n4 @/ T, \8 O
  90. 90 1 |9 |1 M% h( V
  91. 91     if(bDeviceState == CONFIGURED)9 ^4 z1 ~6 g" R
  92. 92     {1 F* ]  {! q, D4 Q- b
  93. 93         if (0 == txFlg)
    : B6 k0 J: r- L% O& w8 P
  94. 94         {) L: w2 O; ], \; \$ J
  95. 95             if (FrameCount++ == VCOMPORT_IN_FRAME_INTERVAL)
    # S$ _$ {5 y+ n8 l1 F
  96. 96             {+ B) `( V  l- o# p
  97. 97                 /* Reset the frame counter */
    - Z" O9 l# D+ S, G& x. ~0 p
  98. 98                 FrameCount = 0;
    + p- d0 z( W& E+ S9 L/ Q5 _" H
  99. 99 : Z% D9 [% V1 a
  100. 100                 /* Check the data to be sent through IN pipe */- h5 [' f8 U# V
  101. 101                 len = USB_TxRead(txBuffter, sizeof(txBuffter));- \# M/ g# x  b: P' d
  102. 102
    3 \/ z& h8 x5 d
  103. 103                 if (len > 0)
    . A# m1 _) Z# G2 I# j5 T
  104. 104                 {
    , e' E: {9 P4 O  j
  105. 105                     UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);  o4 y, Z5 v! V- w
  106. 106                     SetEPTxCount(ENDP1, len);
    . J% \8 n4 V& D2 I2 z1 s
  107. 107                     SetEPTxValid(ENDP1);
    2 V& o: x: W( o3 N, r- v
  108. 108 ( `" ]/ `6 C, y9 L) k
  109. 109                     txFlg = 1;5 i3 g' u4 y* m/ I, x, F: ]  ]
  110. 110                 }. ~( X8 S. B: S- z# n( ^( h# C  K
  111. 111             }
    * _: J& J% P, n4 A  W
  112. 112         }" c0 {1 {  m* G3 S/ I$ x
  113. 113     }  
    5 D* _) Q: g( ~+ S- S) _
  114. 114 }
    ; F% W; c% a8 r3 X0 ?
  115. 115 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码

$ R& ~6 i, A3 q
( ^' v3 ?, Q5 D4 X# h* z, O4 s
这里讲下大概意思,函数EP3_OUT_Callback是在USB口收到数据后,将数据存入FIFO中。
函数SOF_Callback定时查询用户是否有要发送的数据,如果有则进行发送,在发送完成后会触发发送中断EP1_IN_Callback函数,如果发送完毕就不调用SetEPTxValid(ENDP1)函数,发送完成后就不会再触发EP1_IN_Callback函数。
4,修改usb_pwr.c在前文中说到:不让系统进入休眠状态,这里屏蔽185行 __WFI();
5,修改usb_prop.c屏蔽COM初始化代码。137行USART_Config_Default(); 237行USART_Config();
6,修改usb_desc.c 这里修改需要参考一些USB专业的书籍,推荐全圈圈的书,讲的通俗易懂。关于本程序的驱动,笔者在win7下测试可以自动安装,如果无法自动安装可使用文章开始的链接中的驱动程序。本文件如果修改需谨慎,其中pid,vid是制造商ID和产品编号,如果修改了那驱动也要对应修改,官方驱动就无法自动进行安装了。
到这里移植就差不多完成了,下面进行测试。由于USB虚拟串口不受波特率限制,所以笔者进行过50k/s的压力测试,运行半小时未丢1个字节。
移植好的工程STM32_UsbVirtualCom.rar也一起存放在上文章开始的链接中。

4 X( R9 u* V! ?; |) m: `1 U3 k7 M
收藏 评论0 发布时间:2022-1-13 21:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版