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

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

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

7 y8 c' F. j! j4 F- m0 Q
% {( C1 U( ?. N& _3 X
首先打开官方demo我们开始进行移植,第一步复制我们可用的文件,操作如下:
Projects\Virtual_COM_Port文件夹下,复制红线部分
图1

$ a' V! j4 N# Y1 n0 u- E6 W
300035032772082.jpg

5 q% {7 Y% n, p; u/ |7 h
图2
( v) w7 M* g  t  f7 B" `+ W! H; Y/ f
300035202932682.jpg

- Q- r  f, }7 L
我为了方便演示统放在usb/src文件夹下:
图3

) s0 G1 P5 C6 Q. E: G7 z) B: ?. H
300035313246246.jpg

8 I2 u* O1 w" \2 x9 ?
现在复制USB的库文件,这些文件不需要我们修改:
图4
# U. q* g- n5 r/ V. N
300035404189967.jpg

: j1 K  J9 b' r# r4 |
上图中的文件统一放在usb/lib文件夹下:
图5

# W$ B! [9 ]4 r/ ?! ?! |
300036032935279.jpg

4 }; h9 N/ s/ ]4 {, @; ?' H, s( V. V7 z0 [4 q5 R# S0 y
         好了现在所需要的文件我们以复制完了。这里先讲一下DEMO程序的主要工作流程:
7 U% y% {0 i3 r$ N& p" O
300036178402768.png
2 {2 k% q* J# x
图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 ------------------------------------------------------------------*/
    . c: m. z4 D" ^0 j
  2. 2 #include "hw_config.h"
    ! N6 ]7 V0 K4 G% w
  3. 3 #include "usb_lib.h"! @$ A2 B4 K) Z( V4 y
  4. 4 #include "usb_istr.h"
    - Y; h2 F. q) e, R
  5. 5 8 d4 @; ?5 e& A5 `* G9 \8 p
  6. 6
    & T! ?4 ?; w8 O: B9 X% U0 r
  7. 7 /*******************************************************************************
    ) Q) J  N  }4 K9 _5 q  m
  8. 8 * Function Name  : USB_IRQHandler
    1 w* Z2 G- L/ }3 P
  9. 9 * Description    : This function handles USB Low Priority interrupts. o7 c: b9 |) h2 M
  10. 10 *                  requests.# k9 a( Z: T; S9 V1 O
  11. 11 * Input          : None, e3 ~4 @& w# l( y! G
  12. 12 * Output         : None8 G6 Z+ b2 l9 u. ]
  13. 13 * Return         : None: |4 H" b7 ~* k! o7 w& Z
  14. 14 *******************************************************************************/7 [4 S2 ~: ^0 \6 P' J0 d
  15. 15 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)|| defined (STM32F37X)4 k/ Y7 v4 @) D' P# o, a' S
  16. 16 void USB_LP_IRQHandler(void)3 f% l" R" s" v' q, e) ~/ l
  17. 17 #else2 L/ R% P' ~6 u
  18. 18 void USB_LP_CAN1_RX0_IRQHandler(void)" o5 p1 b5 B* ^- ~( \2 u' [
  19. 19 #endif0 X) q& c5 ?3 J. A
  20. 20 {3 W! W# S5 Y  H! B& R9 T
  21. 21   USB_Istr();
    : T- Q# v4 E5 w5 |$ i
  22. 22 }
    ; j4 v* \4 h! a0 z; V
  23. 23 ; F6 L; Y+ ?! [1 ~5 `1 c3 S4 @' H
  24. 24 /*******************************************************************************  C$ f. e# o; q
  25. 25 * Function Name  : USB_FS_WKUP_IRQHandler) S+ B% |9 W4 V& f3 n5 E+ M
  26. 26 * Description    : This function handles USB WakeUp interrupt request.
    ( l, ?* y/ @) g3 g, ?5 O3 `
  27. 27 * Input          : None) _5 e! W" r) ]3 Y2 W
  28. 28 * Output         : None' q6 x4 ^, \4 E* L7 r
  29. 29 * Return         : None
    4 B5 P9 J! A  ?+ E% q
  30. 30 *******************************************************************************/" q- Y$ Y1 u) c8 F: {2 z7 ^
  31. 31 0 W% n+ O: k3 F4 h
  32. 32 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)% ]: f# l% l& I& V% G$ ?
  33. 33 void USB_FS_WKUP_IRQHandler(void)( i3 N; h& k0 g& b
  34. 34 #else
    ; D6 F1 [2 Y& n: w' _3 ]1 m
  35. 35 void USBWakeUp_IRQHandler(void)9 m0 f  @. B% h& I
  36. 36 #endif( ~& v/ u0 A- e: Z9 \
  37. 37 {
    % n7 @9 b9 b8 ?, V3 \* @
  38. 38   EXTI_ClearITPendingBit(EXTI_Line18);9 q. B& D8 `, }  t3 Q8 q* Y
  39. 39 }
复制代码

3 q$ O; r' c. N; G8 w- w
2,修改代码hw_config.c删除无用代码,新建立2组,读FIFO和写FIFO的函数。后面会用到。
代码如下:
代码2
  1.   1 /* Includes ------------------------------------------------------------------*/
    : \  V- O8 F8 {$ Q3 N0 l. k' X9 D
  2.   2
    # P6 B5 p' Z' l  K6 i. {  |5 H
  3.   3 #include "usb_lib.h"
    + K/ y+ W& F, \4 i5 P. z" X& X2 E6 }! ^
  4.   4 #include "usb_prop.h"! f" h4 h6 z1 H/ h  D
  5.   5 #include "usb_desc.h"
    : F7 L/ `1 T- M) B9 U
  6.   6 #include "hw_config.h"
    6 K& z1 C* c% [; P8 U
  7.   7 #include "usb_pwr.h"
    + t8 a/ U  j- h9 ~8 `4 R
  8.   8 #include "Queue.h"4 ~# I  P/ z( X! N
  9.   9
    0 T% H/ p0 l" [$ ]+ v5 z
  10. 10
    ' Q0 H* I  D0 r. @( Z
  11. 11 /* Private typedef -----------------------------------------------------------*/
    * U( i% h- O6 b2 x$ C( V0 {, l
  12. 12 /* Private define ------------------------------------------------------------*/: t: r$ J6 G/ d
  13. 13 /* Private macro -------------------------------------------------------------*/' {% h. V0 t$ @* ~; z
  14. 14 /* Private variables ---------------------------------------------------------*/
    / C* T0 i3 H6 Q( N% Z5 j
  15. 15 ErrorStatus HSEStartUpStatus;
    ) W; F* {7 I9 Z* a* Z* p" X5 t; s6 Q
  16. 16 USART_InitTypeDef USART_InitStructure;" y. a3 u) S3 v5 b% d# u" q
  17. 17 EXTI_InitTypeDef EXTI_InitStructure;
    5 G. g( @2 M0 b9 q% q- G/ B
  18. 18 9 i' p; y! i. O( {: l" T
  19. 19 9 G3 M/ d* m* A5 B# W8 c
  20. 20 #define USB_COM_RX_BUF_SIZE         (1024 + 256)* n/ a' c% J+ _
  21. 21 #define USB_COM_TX_BUF_SIZE         (1024 + 256)  j* k8 O- ^$ O7 _
  22. 22 ( @; g# |; h2 {  G
  23. 23 static QUEUE8_t m_QueueUsbComRx         = {0};
    4 X6 `4 p' G6 _. H" k4 @' I9 ]0 c
  24. 24 static QUEUE8_t m_QueueUsbComTx         = {0};
    ! v6 G% {* M1 q- w2 {" p5 ^0 D
  25. 25 static uint8_t  m_UsbComRxBuf[USB_COM_RX_BUF_SIZE]      = {0};     0 e) i) M4 v% y
  26. 26 static uint8_t  m_UsbComTxBuf[USB_COM_TX_BUF_SIZE]      = {0};   
    : l  A' k; ~, m; N' C6 l8 p; g
  27. 27
    % J# a* W0 i' j) ~
  28. 28 static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len);2 H$ @: `$ q) N& X% @" c
  29. 29 /* Extern variables ----------------------------------------------------------*/$ k) J5 W% B! {8 N3 k! @# k( l
  30. 30
    0 V+ W, k8 Y( a# B# A% f/ l
  31. 31 extern LINE_CODING linecoding;/ y( Q: B6 h. q7 M, [" D) y  \4 l
  32. 32
    ' E. b# o/ b5 i8 [) c) V
  33. 33 /* Private function prototypes -----------------------------------------------*/
    5 H, z0 R" g7 e! p
  34. 34 /* Private functions ---------------------------------------------------------*/
    . a" k% n! [7 N5 R+ O5 l; ~5 n
  35. 35 /*******************************************************************************
    * a7 M3 z( O) y. F3 \
  36. 36 * Function Name  : Set_System) w/ p) F! S0 n5 r! h5 R
  37. 37 * Description    : Configures Main system clocks & power
    % O/ I% V0 m/ g4 ~
  38. 38 * Input          : None.
      Q% n+ ~* H" C  v
  39. 39 * Return         : None.
    , R! z' Y9 J: f( l
  40. 40 *******************************************************************************/
    - l/ m+ H! _' x% h
  41. 41 void Set_System(void)
    ; r( O" v# y9 A& x9 b+ S3 f
  42. 42 {1 k% a7 r( L2 ~2 e6 G" t
  43. 43   GPIO_InitTypeDef GPIO_InitStructure;3 A* n$ w5 {' M" c0 L, t6 \
  44. 44 : I. a& S& f; K" S% |3 X4 N% F
  45. 45   QUEUE_PacketCreate(&m_QueueUsbComRx, m_UsbComRxBuf, sizeof(m_UsbComRxBuf));
    , H1 q' y3 K$ w  N/ h: q/ C! R
  46. 46   QUEUE_PacketCreate(&m_QueueUsbComTx, m_UsbComTxBuf, sizeof(m_UsbComTxBuf));
    , K( V5 |, m7 s7 Y# j( X( A
  47. 47   
    6 {5 C, Q  i3 B3 q9 x
  48. 48   /* Enable USB_DISCONNECT GPIO clock */, Q! I0 s$ \+ f( ~: D
  49. 49   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);
      r5 c6 `- m- E! ~$ y
  50. 50
      r/ I" W) m2 w& I2 _! B' x7 ~
  51. 51   /* Configure USB pull-up pin */
    $ |. Y3 s, m! L
  52. 52   GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;; e7 R' y% R: L+ s6 [( |" E
  53. 53   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;, G/ r( d# p% }( ?  ?: b; s
  54. 54   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;+ w% m6 |5 e: {8 c/ p/ z
  55. 55   GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);! s7 M$ J" L" Z: V6 c# G4 Q
  56. 56   
    8 Z" n, r4 f  t6 l& h& ~
  57. 57   /* Configure the EXTI line 18 connected internally to the USB IP */
    . z& q% n) m/ K6 E2 q% [
  58. 58   EXTI_ClearITPendingBit(EXTI_Line18);, R9 O) P1 l2 w7 F2 w
  59. 59   EXTI_InitStructure.EXTI_Line = EXTI_Line18; + k) i* h& t0 H, J8 _5 N' o
  60. 60   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    9 A6 g4 {5 H$ s# x0 r2 W2 u# Z
  61. 61   EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    ) T1 h9 m" E- F/ X+ Z
  62. 62   EXTI_Init(&EXTI_InitStructure);# r) L. S2 p  ^4 b
  63. 63
    5 V9 H8 @- V; s
  64. 64   
    : ^# x4 S% }# W. f1 Y
  65. 65 }
    0 M+ V% d9 L7 _; w
  66. 66
    # U# K/ O9 R/ }
  67. 67 /*******************************************************************************
    . D2 v3 @# S# {
  68. 68 * Function Name  : Set_USBClock
    # _  I# Q2 l6 ?+ E7 k5 s% r) U
  69. 69 * Description    : Configures USB Clock input (48MHz)
    : t9 W* g8 g9 b$ i
  70. 70 * Input          : None.
    ( a- N% ^# h8 _& I2 O- Z( d
  71. 71 * Return         : None.+ a) j2 g' I$ _: d
  72. 72 *******************************************************************************/% s0 S* f; U5 J  ?* r
  73. 73 void Set_USBClock(void)' N7 l0 }, `5 g  J
  74. 74 {$ t  b. v1 J! y& _
  75. 75   /* Select USBCLK source */
    . V$ `( t) I' O; ?7 L" x
  76. 76   RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
      F) v+ y' P5 L6 ^
  77. 77   % u% ]3 A( O" ^0 R- K; ~) e
  78. 78   /* Enable the USB clock */$ r8 X7 N; \& B2 d. g
  79. 79   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
    9 T0 k, E1 m  X2 c9 @
  80. 80 }
    / C6 z) a6 }( @7 T
  81. 81 - v* f  H' C. |9 `6 i1 l4 B) B
  82. 82 /*******************************************************************************. c7 G- G3 @9 \+ ~9 f2 I( {
  83. 83 * Function Name  : Enter_LowPowerMode
    0 L' b- X+ i7 j1 S2 M) M$ [. M
  84. 84 * Description    : Power-off system clocks and power while entering suspend mode2 C7 b. v" }- H% p
  85. 85 * Input          : None.
    & {; N0 j# a; ?
  86. 86 * Return         : None.
    3 w4 k8 j: U7 O
  87. 87 *******************************************************************************/
    4 P3 w& i$ ~8 E5 r" U3 H
  88. 88 void Enter_LowPowerMode(void)' D  Z9 s7 @  I" m0 f& g
  89. 89 {4 @; f' G1 N5 j& S+ A
  90. 90   /* Set the device state to suspend */* R& J: Q1 `9 i  F, k0 j
  91. 91   bDeviceState = SUSPENDED;5 L8 @0 M6 Z8 j) b( X2 c% J
  92. 92 }+ r4 D9 A0 \# \2 A- _. }
  93. 93 4 i; c/ C9 r+ ^3 L& U( [% H( \" g
  94. 94 /*******************************************************************************! D  U# |1 t! z1 C3 `( I
  95. 95 * Function Name  : Leave_LowPowerMode
    ; ]! b4 m" g6 p1 R+ z2 U# x7 K
  96. 96 * Description    : Restores system clocks and power while exiting suspend mode, ~! u, T4 x: R& N3 v* H
  97. 97 * Input          : None.
    6 Z. C! e" O; g- n5 t
  98. 98 * Return         : None.- ~& _. @$ R# N# U8 W
  99. 99 *******************************************************************************/
    & x: k" v: c4 x0 B
  100. 100 void Leave_LowPowerMode(void)% {/ j4 L7 }- L1 u4 p( [
  101. 101 {" G+ q: a3 T7 m) j
  102. 102   DEVICE_INFO *pInfo = &Device_Info;- I- t5 l" ~% p3 }7 M: F1 v
  103. 103
    / w9 i; F" |7 X& m8 O; u4 s; X
  104. 104   /* Set the device state to the correct state */
    8 J/ e+ m8 Q( h* B
  105. 105   if (pInfo->Current_Configuration != 0)
    ( X7 k* p8 w$ @1 s6 k2 x
  106. 106   {
    4 X6 F5 i) F( Q
  107. 107     /* Device configured */! [2 _% @% h9 s, E
  108. 108     bDeviceState = CONFIGURED;
    / w; N2 t+ F/ G" E7 b9 _* [
  109. 109   }7 u5 O3 R# F% o% ^5 O; n/ c  V) v
  110. 110   else
    - e8 Q( p" B# j; s) i: I
  111. 111   {8 x4 i2 a, W' [6 l4 h
  112. 112     bDeviceState = ATTACHED;  @' B0 d- D4 t; f
  113. 113   }
    . x( a, g( r; b) b* ~6 u
  114. 114   /*Enable SystemCoreClock*/
    ' u* N+ a' z2 j3 [. g, |
  115. 115 //  SystemInit();
    + M7 r( S6 Z3 J, q; w, M5 p
  116. 116 }
    ; O3 V% j* n  O6 {
  117. 117
    - W, s) a# x) X, u! J+ U& \" D
  118. 118 /*******************************************************************************
    / U* o4 I' O. |0 I# ]
  119. 119 * Function Name  : USB_Interrupts_Config0 ^$ l9 F3 l, T
  120. 120 * Description    : Configures the USB interrupts: e& m8 ]2 {3 q' |) e( m  x& ?3 I
  121. 121 * Input          : None.
    # C7 P5 W; ~1 m: g9 y1 b
  122. 122 * Return         : None.
    6 H! Z+ y& ]; |: d: h, l
  123. 123 *******************************************************************************/1 x/ D8 s9 x) W9 O) `* A- @
  124. 124 void USB_Interrupts_Config(void)4 J: O- L: _$ B
  125. 125 {0 S+ a7 ^5 F# ]* K3 j5 F( _
  126. 126   NVIC_InitTypeDef NVIC_InitStructure;
    $ U9 L2 y% N1 o) _& n9 \
  127. 127
    # W9 r: ^% p# I8 p6 L+ k+ n
  128. 128   NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;5 w$ g/ M' @8 L! f4 |- A
  129. 129   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    0 y0 Q  h, g$ g2 X' B
  130. 130   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    3 R% E2 p  u; K0 a0 @
  131. 131   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    , k8 N4 `6 X3 w
  132. 132   NVIC_Init(&NVIC_InitStructure);- C( N0 f0 v; X# H6 u
  133. 133   
    % z4 g: g; D: ?5 j, Z  J
  134. 134     /* Enable the USB Wake-up interrupt */
    ! h8 C$ ?2 m* n3 A$ q3 \7 w
  135. 135   NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;3 `4 t- F$ g- t9 a/ e
  136. 136   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    8 _3 L" @* O; `1 q3 Y
  137. 137   NVIC_Init(&NVIC_InitStructure);. s! A- \7 _$ w1 R
  138. 138 }
    4 ~. J/ y& H# N2 E
  139. 139 . e( F$ v6 O4 S
  140. 140 /*******************************************************************************
    # d6 e/ X% q& R7 X. z3 K5 K
  141. 141 * Function Name  : USB_Cable_Config8 {& _& v2 k" K' @# G
  142. 142 * Description    : Software Connection/Disconnection of USB Cable
    $ r; X. |$ Y1 Q: U2 C- W
  143. 143 * Input          : None.
    1 o; R' @) x& @' a0 h
  144. 144 * Return         : Status$ ~8 H1 t& b4 u* s( Q, Z7 u
  145. 145 *******************************************************************************/
    5 a, t/ v* J/ H) _6 X; h
  146. 146 void USB_Cable_Config (FunctionalState NewState)
    ' ~# @# N( m$ t, H
  147. 147 {
    1 Z7 Q6 J" w; k$ d0 T
  148. 148   if (NewState == DISABLE)6 S. H7 n7 K& P0 L
  149. 149   {
    1 L% ~7 d1 ?5 z* S1 z6 F, M) \
  150. 150     GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);( P7 e+ A$ a* D! z; @5 {
  151. 151   }
    2 c7 a0 M1 ~+ [* u
  152. 152   else
    % K* e$ n: i4 N% V/ j* F
  153. 153   {- w/ Y4 `- X9 k8 ~" B3 A% G0 m
  154. 154     GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
    9 E$ l) Q" k) M* U4 j. |4 |
  155. 155   }
    1 e/ ^: O) p6 L
  156. 156 }5 f2 Y+ r! G/ G! n' R
  157. 157 ' \1 ~; D* [! H5 P+ j  @
  158. 158 /*******************************************************************************
    , J) j) {- a! M
  159. 159 * Function Name : void USB_Config(void)
    ) ]- k1 ^: Q$ Q4 ]" n
  160. 160 * Description   : USB系统初始化" R$ R+ w  ~7 D/ n3 F
  161. 161 * Input         :
    0 j% k+ l" v5 |$ u1 E
  162. 162 * Output        : 2 a* W. H9 w' x1 W# v) Z! k% @
  163. 163 * Other         :
    & ~1 j7 Z1 g! C( P2 ]
  164. 164 * Date          : 2014.11.28
    2 o4 r. E, h2 A4 s3 P7 o  c% o
  165. 165 *******************************************************************************/
    * G$ i* O/ h) s  y, a( ~' y8 }
  166. 166 void USB_Config(void)# x* M9 W7 A8 i
  167. 167 {: Y% M! j  K4 J. u  e
  168. 168     Set_System();
    & J- z7 g; |; j# E
  169. 169 0 J  z1 @, I" T- X3 c/ o# D2 F/ i# g
  170. 170     Set_USBClock();
    3 Z) v( R9 Q, h3 k& P
  171. 171
    7 q8 y6 s) q4 n4 l8 O% H. s
  172. 172     USB_Interrupts_Config();2 A  k" |  X+ S
  173. 173 " _0 n& ~+ e& [6 v' N7 P& p$ {
  174. 174     USB_Init();
    4 F0 N0 |/ e0 w
  175. 175 }
    ( q; `2 E( d; Y  R$ ~. C& x9 i
  176. 176
    9 c+ _% A( M5 s% p  Z. }$ W
  177. 177 /*******************************************************************************! Q4 P, z; I# |3 J5 b
  178. 178 * Function Name : uint32_t USB_RxRead(uint8_t *buffter, uint32_t buffterSize)8 E5 s6 R' ^! Q' \; a: C. D/ A5 S
  179. 179 * Description   : 从USB接收缓存中读数据+ Y8 x! H2 |% t: M6 I. D  _" Z
  180. 180 * Input         : + [; N5 f# I( B5 y
  181. 181 * Output        :
    ) e- F: W% y: b0 y7 i) a
  182. 182 * Other         : 3 C+ {- O9 }* q" p0 L' ~
  183. 183 * Date          : 2014.11.28* w0 A/ u$ K8 I, N
  184. 184 *******************************************************************************/
    0 v3 n. ~) R* f+ l9 `9 a# K& H
  185. 185 uint32_t USB_RxRead(uint8_t *buffter, uint32_t buffterSize)# E- ^( N- L, t: C& ]* d# B
  186. 186 {+ @" p5 I; G. }- {1 X- ]3 B
  187. 187     return QUEUE_PacketOut(&m_QueueUsbComRx, buffter, buffterSize);
    ! j! g  W1 e" |/ \( `- L
  188. 188 }
    8 E& e2 _3 X) V" _' c! ^% M) A
  189. 189 /*******************************************************************************% T5 M/ Q! X: z
  190. 190 * Function Name : uint32_t USB_RxWrite(uint8_t *buffter, uint32_t writeLen)
    9 j: G- C/ Y' `7 `$ b" p: c
  191. 191 * Description   : 写数据到USB接收缓存中1 p7 j3 B3 d4 f, q# S! ^( X5 U
  192. 192 * Input         : 3 I6 @6 `4 M5 w6 v0 I+ C, x4 Z7 F# w
  193. 193 * Output        : " ?5 e& L# {) }- y
  194. 194 * Other         : # |. \: W6 }( k0 A- |# ^
  195. 195 * Date          : 2014.11.28
      F$ ~2 _$ U* b, r$ K; l/ x
  196. 196 *******************************************************************************/
    : A" G2 z) C0 k  U
  197. 197 uint32_t USB_RxWrite(uint8_t *buffter, uint32_t writeLen)+ t; k. L0 ]+ T) ~4 M& }
  198. 198 {6 ~2 r. f6 p' y9 c3 b
  199. 199     return QUEUE_PacketIn(&m_QueueUsbComRx, buffter, writeLen);
    ' @- q) |8 R, g5 v" J1 r
  200. 200 }
    , B& v* G; Z4 w# q0 f% p1 Y
  201. 201 /*******************************************************************************
    % m7 Y) b* }: L& T2 a
  202. 202 * Function Name : uint32_t USB_TxRead(uint8_t *buffter, uint32_t buffterSize): D0 K$ Z$ u# P; B) B4 G
  203. 203 * Description   : 从USB发送缓存中读数据% {! e* O" m: e
  204. 204 * Input         : 7 Q$ d7 \: h" j; V0 ]0 P  T+ s3 ]. Q
  205. 205 * Output        : ! ^6 x8 ], }* J
  206. 206 * Other         :
    2 S$ F) L8 F* w3 A
  207. 207 * Date          : 2014.11.28  P) e9 s  _8 |  l5 e
  208. 208 *******************************************************************************/, ^: r$ e5 H  w; R
  209. 209 uint32_t USB_TxRead(uint8_t *buffter, uint32_t buffterSize)
    , [3 @7 E8 g2 H- P
  210. 210 {* w4 @# L5 w# `/ D( X1 H
  211. 211     return QUEUE_PacketOut(&m_QueueUsbComTx, buffter, buffterSize);;
    $ I! \' e7 d. F7 c' |
  212. 212 }
    7 n7 ]( y( a. u  e/ |) h5 Q
  213. 213 /*******************************************************************************
    2 P& B# L8 m) [# b; g
  214. 214 * Function Name : uint32_t USB_TxWrite(uint8_t *buffter, uint32_t writeLen); `% {% h! U7 Z! A
  215. 215 * Description   : 写数据到USB发送缓存中
    , z, e  j  w3 K* m6 Y7 c
  216. 216 * Input         : 0 Y; g& b( ^, ]4 }9 g+ ?. r  Z" ]
  217. 217 * Output        : / n* q( `9 u4 E) i& G
  218. 218 * Other         :
    # Z4 \: }7 S) R  ~( |' ?, J
  219. 219 * Date          : 2014.11.28
    ) J) B6 k0 I1 h( R( a. A; \
  220. 220 *******************************************************************************/
    % y# E+ T7 \8 d4 E; m* w
  221. 221 uint32_t USB_TxWrite(uint8_t *buffter, uint32_t writeLen); V% f# e4 h) s7 |3 @, s9 G1 X+ d
  222. 222 {' `1 `/ l# r0 P, x; ]# z5 `: X
  223. 223     return QUEUE_PacketIn(&m_QueueUsbComTx, buffter, writeLen);
    ! |# {6 S6 e. ~& |, h6 j
  224. 224 }
    + b0 |1 @: `. ^0 n0 O' D: R8 ]- s
  225. 225
    / z" Z4 F0 r* ~: q' B* O; f
  226. 226 4 S7 l2 a, z8 v3 G/ O
  227. 227 % a+ |: S0 R% \
  228. 228 /*******************************************************************************
    % T& ~  M0 P- Z; g0 i3 |, Z
  229. 229 * Function Name  : Get_SerialNum.' r9 M- t( e( C3 g
  230. 230 * Description    : Create the serial number string descriptor.# p6 r* M2 C4 _2 s) U- ?  p
  231. 231 * Input          : None.
    9 b4 w4 A! r, k/ x8 u2 s! {
  232. 232 * Output         : None.9 T+ @  M  i* q' C9 M( O$ W
  233. 233 * Return         : None.
    4 ^# |- T0 i; x; s% d
  234. 234 *******************************************************************************/
    ; S3 C  ]0 P7 `# X/ `  h
  235. 235 void Get_SerialNum(void)2 ~( K" K8 s% W; M) u4 P( ]; @$ W
  236. 236 {' I' e8 D( L  N0 W6 [
  237. 237   uint32_t Device_Serial0, Device_Serial1, Device_Serial2;
    ' J; c* D; }$ R4 p6 m
  238. 238
    & _  t# r, Z) e7 F; @' k8 P. {
  239. 239   Device_Serial0 = *(uint32_t*)ID1;
    ! [+ C* u+ n2 |( [
  240. 240   Device_Serial1 = *(uint32_t*)ID2;
    7 A/ ~: `3 ~, Z+ Q2 q3 c
  241. 241   Device_Serial2 = *(uint32_t*)ID3;  6 k/ J, X' U( b1 I6 s
  242. 242 ) M7 ~8 d4 V& _% f. {6 [
  243. 243   Device_Serial0 += Device_Serial2;, {/ Z0 ?. i' x7 N  V
  244. 244
    & ^$ G" b: j) k$ P( X
  245. 245   if (Device_Serial0 != 0)" p7 f0 X" B# \/ F* z  N6 A5 H
  246. 246   {9 V2 @1 V7 k- E7 b
  247. 247     IntToUnicode (Device_Serial0, &Virtual_Com_Port_StringSerial[2] , 8);% R+ K. i5 g7 j7 \+ z8 d: |
  248. 248     IntToUnicode (Device_Serial1, &Virtual_Com_Port_StringSerial[18], 4);
    $ \" z; K* F  \/ o2 X
  249. 249   }
    ' T. A4 A$ V, `. @
  250. 250 }& Z$ i/ I! V1 v6 k# e- [3 x
  251. 251
    - H# R3 j6 L) _  l+ y
  252. 252 /*******************************************************************************! ~; G0 o+ c: Q' s+ D5 F7 I# z! o
  253. 253 * Function Name  : HexToChar.
    " u+ b' F8 N" ]; Z7 `
  254. 254 * Description    : Convert Hex 32Bits value into char.4 j3 v' I* V+ `
  255. 255 * Input          : None.: ]1 R+ y! j. Q% ~; w& x
  256. 256 * Output         : None.- C: v8 t/ S' U9 U) M
  257. 257 * Return         : None.
    9 V( N9 a/ d) G2 [
  258. 258 *******************************************************************************/
    2 v* ]& U. l* h; I
  259. 259 static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len); p3 i7 n; n2 j. D
  260. 260 {
    - L! w& A/ {4 P$ {5 S# S, Y
  261. 261   uint8_t idx = 0;
    - f8 p: M/ i* Z1 L
  262. 262   / u. F) f: f( T
  263. 263   for( idx = 0 ; idx < len ; idx ++)
    ! `! Q: L! n0 d5 L
  264. 264   {
    3 \- ?, [* T% m- a& h& }
  265. 265     if( ((value >> 28)) < 0xA )
    0 V8 u9 `/ n% G! u7 _/ P2 i
  266. 266     {* J7 ]% l9 n' o: o; u
  267. 267       pbuf[ 2* idx] = (value >> 28) + '0';+ z/ _9 O+ o1 O5 b6 _0 J/ t! p9 v
  268. 268     }( U$ I. q6 d4 t7 T4 G) T+ e$ o
  269. 269     else
    3 k, V( b! }1 R$ l
  270. 270     {
    7 P" t; ~4 ]! r8 h7 t
  271. 271       pbuf[2* idx] = (value >> 28) + 'A' - 10; 8 P; P: w. Y  G7 |3 b* G$ p, z
  272. 272     }9 {( O7 c7 `( l- p- v3 X
  273. 273     / |* _4 G& ]+ L" f( e8 v& x
  274. 274     value = value << 4;$ I" P& H* H! h
  275. 275     
    * k& `0 K7 I% o
  276. 276     pbuf[ 2* idx + 1] = 0;
    . ?2 w3 O" x8 p# U+ a: L6 @" `
  277. 277   }
    6 i! E* G- {( n. k0 |9 E
  278. 278 }! N' \9 X  b& q# f. ~7 g
  279. 279
    6 b* `& g7 H9 {0 a
  280. 280 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码

5 S: k: H6 W, D( N4 L; R" x: F
9 g1 ~, A+ b% m' B  h
这里要讲一下为什么要屏蔽SystemInit(),因为demo只运行虚拟串口功能,在USB未插入的情况下,是进入低功耗状态,插入时从低功耗状态退出后会调用此函数。当然我们在项目中一般不会这样,系统是否运行和插USB接口没有联系。所以我在下文中把进入低功耗代码屏蔽了,自然也就不用唤醒代码了。
图7

; U- D+ R, Q/ i7 L% X; Q) \2 l  P
300038465597900.jpg
% |5 a' Z3 d/ I$ c1 i
关于USB口使能控制引脚,需要根据开发板的引脚定义来修改宏定义platform_config.h文件中,笔者使用的是神舟3号开发板,控制信号刚好和demo相反,所以修改hw_config.c代码如下:
代码3
  1. 1 /*******************************************************************************
    + n0 n1 K* K$ n
  2. 2 * Function Name  : USB_Cable_Config6 _* A+ @& I: ]4 @9 z
  3. 3 * Description    : Software Connection/Disconnection of USB Cable# K7 P5 ]$ ~5 o5 b: O
  4. 4 * Input          : None.
    , t; T/ A$ `2 S0 A6 Y' o1 j' ]6 I
  5. 5 * Return         : Status' L# K9 c3 x. K; u( K
  6. 6 *******************************************************************************/$ ?6 s( S! d( c- R. _# R
  7. 7 void USB_Cable_Config (FunctionalState NewState)/ g" W( I& x& o% ]3 s5 h
  8. 8 {" r2 Z/ J8 a3 \9 G
  9. 9   if (NewState == DISABLE)5 [( J5 _0 E: L. S  `
  10. 10   {$ x/ O: L* p9 }; [9 L$ ~
  11. 11     GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
    + i# w- {* l( \$ B) O: u9 v. n
  12. 12   }( U2 n/ h- O1 b
  13. 13   else3 ^& M' h* B" z- d7 b+ h& ^1 m
  14. 14   {  P* C2 c: M. r/ F
  15. 15     GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
    " S! A2 r9 @7 e# P7 U5 v
  16. 16   }
    $ e8 }' }2 v  @3 S4 Q' Y2 s1 W7 L
  17. 17 }
复制代码

/ j# u! K7 ]6 f& c
3,现在修改USB 回调函数中的代码usb_endp.c文件。使用下文代码替换:
代码4
  1.   1 /* Includes ------------------------------------------------------------------*/) O5 ]4 U# l, u. f8 y1 E
  2.   2 #include "usb_lib.h"
    5 d* k7 ^2 R1 }3 W2 R  ]9 T1 s
  3.   3 #include "usb_desc.h"' u8 E2 O' I- u2 J4 t9 D; y! f' _
  4.   4 #include "usb_mem.h"( ^( ^) e. t% B/ t
  5.   5 #include "hw_config.h"# t% s# h  F" q2 T( q5 r
  6.   6 #include "usb_istr.h"% }7 Y8 a) M% u- e* s# }9 |( I, K
  7.   7 #include "usb_pwr.h"
    % r, k7 @8 O! z' [% P  O1 f7 M9 h9 ?
  8.   8
    ) E5 u8 z3 ]  r/ D, ~" J
  9.   9 /* Private typedef -----------------------------------------------------------*// }3 |2 P2 C- T! {! c+ ]/ a
  10. 10 /* Private define ------------------------------------------------------------*/
    6 Z! h( C# T  l; @6 B
  11. 11
    2 C/ {- K0 c. K3 q
  12. 12 /* Interval between sending IN packets in frame number (1 frame = 1ms) */
    ( [7 k* c( s" Y7 H% e
  13. 13 #define VCOMPORT_IN_FRAME_INTERVAL             5
    / [- H3 m3 U0 \6 S" Z1 U
  14. 14
    ; X; M" F, Y- e, H7 ^, j- `7 v5 y# ~8 T
  15. 15 /* Private macro -------------------------------------------------------------*/5 F( J: d% p3 ^, \
  16. 16 /* Private variables ---------------------------------------------------------*/( {( f3 y5 Q/ U& C5 m$ ]) @6 z0 Z
  17. 17 static uint8_t txBuffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};
    # |) J- H, {4 y0 F, M' m
  18. 18 static volatile uint8_t txFlg = 0;
      r* |( x! X( s# j5 [  Z
  19. 19 static volatile uint32_t FrameCount = 0;
    7 Y( t7 z8 y9 M4 Y8 c$ v
  20. 20 ' D5 ^/ {" u6 j' S5 v, H' B' \+ s
  21. 21
    $ W1 `# H" e6 _7 S+ P
  22. 22 /* Private function prototypes -----------------------------------------------*/. x5 e9 E5 F8 n
  23. 23 /* Private functions ---------------------------------------------------------*/
    5 l5 a1 ^. S6 H5 ^
  24. 24
    ! i9 F# p, @: n. t- g  O) I+ D6 e
  25. 25 /*******************************************************************************9 _6 L0 u! H% V! ~3 c% E. X
  26. 26 * Function Name  : EP1_IN_Callback
    9 O7 Y3 O1 K& |
  27. 27 * Description    :
    9 j2 ^, [0 `+ _1 _: P  r/ ]
  28. 28 * Input          : None.
    1 z" U+ F' v- f$ ]8 J" [1 m
  29. 29 * Output         : None.* O* j( U+ i  |0 S8 x
  30. 30 * Return         : None.9 i2 u; B. w( i8 u7 N8 Z' U
  31. 31 *******************************************************************************/
    0 i" x# f9 L3 p/ @, u  M
  32. 32 void EP1_IN_Callback (void)
    / u# s4 R* r9 k6 j2 [$ M8 K! [& r, k
  33. 33 {
    * ?( |8 ~- i6 \- C' r/ [4 \- O
  34. 34     uint16_t len = 0;
    . A: F3 t) m0 A4 y
  35. 35     ( F. n+ z  O& D5 T# l  |! O7 F- V
  36. 36     if (1 == txFlg); P5 e  }8 K- B
  37. 37     {: S) q. A; [8 t
  38. 38         len = USB_TxRead(txBuffter, sizeof(txBuffter));5 H; @& t1 w$ J0 h7 }
  39. 39 6 g  o: c0 n; N: q+ h# V/ \
  40. 40         if (len > 0)! ?. i' }1 E, ~+ C9 `" R, p
  41. 41         {
    ! M/ w1 \0 M' v2 I: A" E8 m6 V
  42. 42             UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);
    # L3 S, j- I2 s( @- w
  43. 43             SetEPTxCount(ENDP1, len);
    ; e8 y0 R! w* Q
  44. 44             SetEPTxValid(ENDP1);
    0 |  t5 k: F6 g* |  q
  45. 45             FrameCount = 0;9 b+ h' S# d) A/ o4 M
  46. 46         }
    2 p% P1 g! W, ^! O: I* P6 t
  47. 47         else
    8 ]0 h8 z' m. u4 L
  48. 48         {! ?! d1 A4 A* a; ~! H  b& J
  49. 49             txFlg = 0;# B( R* q! c9 q8 T) x& a1 I# \
  50. 50         }
    & t* n4 Z& N: {
  51. 51     }
    . I# }1 ?4 L: I& V' F5 a# C- g* j
  52. 52 }: T- m# J  m; y$ x5 v* M6 P* Z: t
  53. 53 % S* s8 T, }2 o2 m& Y4 j
  54. 54 /*******************************************************************************
    * x3 b6 c. W1 `" H/ V$ T( K
  55. 55 * Function Name  : EP3_OUT_Callback
    8 B. C3 L. M% L6 I3 J( y
  56. 56 * Description    :, I3 a/ X, H4 s7 K) c! p1 d
  57. 57 * Input          : None.
    5 T, V" z9 b! b( l
  58. 58 * Output         : None.- y: u/ |! |: [0 C" y
  59. 59 * Return         : None.8 m/ h( h1 n# m& {0 H/ I& V
  60. 60 *******************************************************************************/# s9 h7 V7 ]( q" S4 T, g3 K% h
  61. 61 void EP3_OUT_Callback(void)
    " i- e: \3 `; t! t# ]# m: E6 s
  62. 62 {
    $ T$ R! X; ^$ ^% |& \1 `  Z
  63. 63   static uint8_t buffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};% ~2 t1 g, @' d" S
  64. 64 - c7 ]: s# F1 W+ a+ l
  65. 65   uint16_t USB_Rx_Cnt;- {) L7 g7 s4 ^0 k5 {
  66. 66     E4 u7 m7 r' w1 Q
  67. 67   /* Get the received data buffer and update the counter */! i* w8 R6 ~6 ^9 f. x7 i/ h
  68. 68   USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, buffter);' w9 v0 T( Y8 L2 P1 j/ V
  69. 69   # S( Y4 d0 ^! Z& R( v$ ]5 U
  70. 70   /* USB data will be immediately processed, this allow next USB traffic being " K6 D; V- R/ |; m  m3 m- c: \6 B2 b% D
  71. 71   NAKed till the end of the USART Xfer */
    9 i. {( p6 p% k" q
  72. 72   USB_RxWrite(buffter, USB_Rx_Cnt);
    0 j% `/ L& X+ _* I- p
  73. 73 " W; n2 g  i5 k8 L1 M
  74. 74   /* Enable the receive of data on EP3 */
    / Q/ k1 X5 o4 g, C0 w
  75. 75   SetEPRxValid(ENDP3);+ S. f1 n4 B" W8 U
  76. 76 $ B4 p" |3 M  Z: j* s) h' ~
  77. 77 }
    % t, o0 p, R' w: F9 H) w0 }! H
  78. 78 # q, M# j0 K& v6 t
  79. 79 ! B& }( M, y3 D- i& l
  80. 80 /*******************************************************************************2 F7 f1 S3 l) z* w
  81. 81 * Function Name  : SOF_Callback / INTR_SOFINTR_Callback
    " y5 R4 ~8 s7 v* {0 x; ?7 r
  82. 82 * Description    :
      Q$ ?  X, t1 E, }  V, l' v% F
  83. 83 * Input          : None.
    5 W2 }2 x! D; O3 @
  84. 84 * Output         : None.. y3 W+ y) q& \: O# |. ~3 `
  85. 85 * Return         : None./ u' ?" A, B( j7 _  z1 i
  86. 86 *******************************************************************************/, e1 i5 D3 d. b6 e- u* a
  87. 87 void SOF_Callback(void)
    * l( F% ]: {4 [
  88. 88 {* |* I: V0 _( I& G8 G
  89. 89     uint16_t len = 0;
    , m( ?) E4 K0 p! p. D' z  g0 a
  90. 90 * Z0 R+ k4 V  S8 b3 e% g8 |
  91. 91     if(bDeviceState == CONFIGURED)! o) @: ~+ w8 A2 l+ J9 u
  92. 92     {
    & H1 I% [% S  F! o% r
  93. 93         if (0 == txFlg)
    - @% K# q+ B: k. T
  94. 94         {& ~5 i+ O* w. r& s. A6 A! N" {
  95. 95             if (FrameCount++ == VCOMPORT_IN_FRAME_INTERVAL)
    5 y) N3 w$ a( O1 f8 F8 ?' S2 O- D
  96. 96             {9 V5 c+ a' N9 M# [
  97. 97                 /* Reset the frame counter */1 R' a* r* [0 k
  98. 98                 FrameCount = 0;
    ' K4 p( Z+ e" T# }1 E5 x
  99. 99 % f% ]0 S! G4 }
  100. 100                 /* Check the data to be sent through IN pipe */
    8 ~. L' `4 N( C/ e
  101. 101                 len = USB_TxRead(txBuffter, sizeof(txBuffter));
    % Y3 q1 z# _; t$ f: I3 d
  102. 102   Y4 D3 V; i# }9 _% W! ?; G
  103. 103                 if (len > 0)0 c+ T  c4 H+ t0 _4 k: \0 g' o( L
  104. 104                 {
    6 @5 _) \- ^; ^
  105. 105                     UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);, X) `, [9 z( S6 O
  106. 106                     SetEPTxCount(ENDP1, len);
    $ |% q, _6 C2 Y4 J7 z  i( X
  107. 107                     SetEPTxValid(ENDP1);2 X7 ^- @% C/ j7 Z
  108. 108 ! k0 u2 G6 L! [1 Z
  109. 109                     txFlg = 1;7 @; L4 [' m  k: j- J  r
  110. 110                 }4 H; s5 [3 `4 Y3 S5 e. v, V7 H9 @
  111. 111             }
    & g; M$ B3 b( Q: _; X
  112. 112         }4 ?& j4 s; C* ~* P- @% l
  113. 113     }  
    : t& g/ j; y+ Y2 P5 e* D  c! R
  114. 114 }
    ) s5 w4 }  u8 E) g1 m
  115. 115 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码

$ e# B1 z9 [! a0 P+ k( }3 m
6 \# m0 p! q0 H1 o/ ?- y
这里讲下大概意思,函数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也一起存放在上文章开始的链接中。

7 \: D% K! n, P! [  S! t9 i6 L& e
收藏 评论0 发布时间:2022-1-13 21:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版