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

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

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

3 Z$ a0 Q& u/ G7 {5 O9 D
首先打开官方demo我们开始进行移植,第一步复制我们可用的文件,操作如下:
Projects\Virtual_COM_Port文件夹下,复制红线部分
图1
! N0 z# ^- h: _# y. i8 M9 G! N) r
300035032772082.jpg
! g( [% c- ?* f5 s6 ]5 E& E
图2

6 W- H+ Z6 x/ R& A/ m% ?
300035202932682.jpg
! X7 [* C; p7 C2 K: K6 u
我为了方便演示统放在usb/src文件夹下:
图3
3 O, P9 u, y0 A8 J" Y% i$ b
300035313246246.jpg

/ Y- C! J, d  M2 U2 g/ s; F7 V
现在复制USB的库文件,这些文件不需要我们修改:
图4

7 l9 f! q0 L2 J1 x+ u0 @  f+ T  M. D
300035404189967.jpg

5 }' i0 K+ [# h" E0 ?$ u
上图中的文件统一放在usb/lib文件夹下:
图5

2 [9 m. G. E4 S6 B7 i
300036032935279.jpg
4 I- E1 k; T% }/ o8 s% o3 j

$ M) e, q; b9 Y0 H0 x- ?
         好了现在所需要的文件我们以复制完了。这里先讲一下DEMO程序的主要工作流程:

& {7 I; D  V8 S5 w- L7 T  r4 w% }
300036178402768.png
% @' u. _4 g& B9 ?1 ?/ j8 _
图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 ------------------------------------------------------------------*/
    " M: q# p4 E8 C& Q5 k
  2. 2 #include "hw_config.h"$ L+ v( M1 m, i  Q) O
  3. 3 #include "usb_lib.h"
    * M9 D" k+ j8 ]" D. F+ R
  4. 4 #include "usb_istr.h"
    4 ^4 r  a2 l3 }: a1 Q& t4 q! f$ @
  5. 5
    : z2 [; Y, W) K( E
  6. 6
    5 Q. O& P' T( M( p
  7. 7 /*******************************************************************************4 E* `4 H* i( p7 ~
  8. 8 * Function Name  : USB_IRQHandler
    7 z' n, n* H  @0 ?# ~
  9. 9 * Description    : This function handles USB Low Priority interrupts6 `7 c* J6 g& r
  10. 10 *                  requests.+ N: f; I  [: a
  11. 11 * Input          : None
    * a* A* s* _- Z; C
  12. 12 * Output         : None& B" ^$ ?2 a5 P: j' w
  13. 13 * Return         : None* u( m& Q: Y% M6 O! e9 d0 z3 h
  14. 14 *******************************************************************************/2 I4 }, G- a6 w. k- v+ ?3 k
  15. 15 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)|| defined (STM32F37X)
    ; f# T6 s, s: ]
  16. 16 void USB_LP_IRQHandler(void)
    9 [% q, l8 C/ i; T
  17. 17 #else( q7 M( a% w( Z& u7 e
  18. 18 void USB_LP_CAN1_RX0_IRQHandler(void)
    , `: t. o. @* |3 Y
  19. 19 #endif
    & s) m& z# Z& f6 \1 X( R+ W
  20. 20 {: {# a, K6 @+ ~
  21. 21   USB_Istr();
    ! e  ]) F) i  }' H, a: W
  22. 22 }
    0 }$ V) p' s' t2 ]8 }6 w4 s
  23. 23 # t' {% O- P. U& m
  24. 24 /*******************************************************************************
    . Z) P; b/ F" T+ I
  25. 25 * Function Name  : USB_FS_WKUP_IRQHandler
      O; ~9 e7 Z3 h/ T
  26. 26 * Description    : This function handles USB WakeUp interrupt request.. A" G) t! V; w" n  ~$ r+ ]
  27. 27 * Input          : None2 E9 _4 @, G: Z. Y4 @) d
  28. 28 * Output         : None
    $ }' ?6 u0 \; ?9 m
  29. 29 * Return         : None
    ) t7 t3 l. K5 `, V0 S
  30. 30 *******************************************************************************/
    8 W1 T3 }* y' T7 L% g( W
  31. 31
    ! b( z4 X5 P4 A$ C
  32. 32 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)- V4 o% ^; e8 ~! l' ]! b+ @
  33. 33 void USB_FS_WKUP_IRQHandler(void)  h! u% u& U0 I: j/ s- A' g% Z
  34. 34 #else
    4 `1 G* I. p) a- A. J1 M) K7 I
  35. 35 void USBWakeUp_IRQHandler(void)8 S  S: f5 A% h. ^4 x* w* h
  36. 36 #endif; j- {1 }9 s2 w" O$ k+ Z
  37. 37 {
    , Q' x- ~( y* f2 |4 u% ^( L
  38. 38   EXTI_ClearITPendingBit(EXTI_Line18);0 k4 p' i( }6 s  n" [2 w
  39. 39 }
复制代码
% l6 X, P* b- T9 w  V
2,修改代码hw_config.c删除无用代码,新建立2组,读FIFO和写FIFO的函数。后面会用到。
代码如下:
代码2
  1.   1 /* Includes ------------------------------------------------------------------*/
    : {2 q3 s( c& Y4 {
  2.   2 4 V5 v3 |+ O7 ~
  3.   3 #include "usb_lib.h"
    3 y; H/ x# V8 F1 d. Q. |
  4.   4 #include "usb_prop.h"  I9 n2 w: C/ E$ p
  5.   5 #include "usb_desc.h"' [% s4 \8 j% ?/ X- z  G8 O
  6.   6 #include "hw_config.h"  x4 H+ ]1 q: L: V* C5 Y
  7.   7 #include "usb_pwr.h"3 u' E+ o8 A1 N7 ]) I
  8.   8 #include "Queue.h"
    + f2 W& q% u9 H0 S: s4 S1 I0 W  k. z
  9.   9
    3 y' M" Y) O% o! X( e, U8 n( c  q
  10. 10 ! `, X6 D; r% O  w/ O4 H
  11. 11 /* Private typedef -----------------------------------------------------------*/+ i: T+ I0 q9 T+ k% Y! k
  12. 12 /* Private define ------------------------------------------------------------*/$ F( w0 ^/ {/ H5 {$ a
  13. 13 /* Private macro -------------------------------------------------------------*/
    9 r5 o6 W# C0 q. i6 A5 z
  14. 14 /* Private variables ---------------------------------------------------------*/
    + M( H+ z1 n# r# u
  15. 15 ErrorStatus HSEStartUpStatus;4 Z9 U* j1 ?2 V3 E) V: F- ^; W
  16. 16 USART_InitTypeDef USART_InitStructure;
    . z4 t" s- `" J- \- ^7 r, U
  17. 17 EXTI_InitTypeDef EXTI_InitStructure;
    - n% z9 q& I8 m3 [& G6 m% t/ l
  18. 18 ! C% u; ^$ l* W2 {
  19. 19 9 [$ ?8 l& P4 Y
  20. 20 #define USB_COM_RX_BUF_SIZE         (1024 + 256)
    & }% O$ w' s3 G) s) ~: w- J" p
  21. 21 #define USB_COM_TX_BUF_SIZE         (1024 + 256)  L" w- l- ~" ]3 ?) k; F
  22. 22
    / o( A+ k- _' f) \
  23. 23 static QUEUE8_t m_QueueUsbComRx         = {0};
    $ {3 M- }9 S7 J4 P0 E6 b' H/ q
  24. 24 static QUEUE8_t m_QueueUsbComTx         = {0};
    2 [* B4 Y1 j* V1 B
  25. 25 static uint8_t  m_UsbComRxBuf[USB_COM_RX_BUF_SIZE]      = {0};     
    * t) V0 }# N+ ^
  26. 26 static uint8_t  m_UsbComTxBuf[USB_COM_TX_BUF_SIZE]      = {0};   
    5 {) T! J( u1 }9 W
  27. 27 8 b( s7 B7 ?+ J# K2 _  V- ^
  28. 28 static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len);2 w$ C9 u9 K1 R/ ]5 {
  29. 29 /* Extern variables ----------------------------------------------------------*// ^, F: F0 s+ o  q* p# I
  30. 30
    " l; E0 a$ e) t- C/ a0 ^- ]
  31. 31 extern LINE_CODING linecoding;" L  U$ D( s% L5 B5 Z
  32. 32
    / N* Z" G9 f! N3 T" O$ y
  33. 33 /* Private function prototypes -----------------------------------------------*/
    % p) C+ z+ [; r
  34. 34 /* Private functions ---------------------------------------------------------*/8 t4 [! ?6 p' m; S
  35. 35 /*******************************************************************************
    9 _6 N7 T& M7 |* u  {4 @, o, M( Y
  36. 36 * Function Name  : Set_System- q0 g2 W+ r. N
  37. 37 * Description    : Configures Main system clocks & power
    ' a9 Z$ Y* q7 u' `* I4 h& f. j& w
  38. 38 * Input          : None.3 t4 |+ W1 v7 o+ o9 ^" d. c% g/ }+ Y9 m
  39. 39 * Return         : None.
    8 k/ V) \1 d4 {6 g1 {
  40. 40 *******************************************************************************/& _3 _) {6 z$ n1 i7 l  s
  41. 41 void Set_System(void)6 ^; U: M/ y. e! ?
  42. 42 {' H- d2 g8 b  i7 e
  43. 43   GPIO_InitTypeDef GPIO_InitStructure;
    4 {( H! ]3 a3 }- P, g
  44. 44 : j2 `* W, r0 j9 P0 l
  45. 45   QUEUE_PacketCreate(&m_QueueUsbComRx, m_UsbComRxBuf, sizeof(m_UsbComRxBuf));* j' C2 W5 R9 t1 u, A
  46. 46   QUEUE_PacketCreate(&m_QueueUsbComTx, m_UsbComTxBuf, sizeof(m_UsbComTxBuf));
    3 m* H: x/ \& a6 X, `' U( N* M5 H
  47. 47   # ]: H* N. l. j+ d
  48. 48   /* Enable USB_DISCONNECT GPIO clock */+ P. w5 D, V4 _# h
  49. 49   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);% R8 Z0 B, g6 ?
  50. 50
    + ]" g; O  _) g# N3 d7 E; U# L
  51. 51   /* Configure USB pull-up pin */
    3 A# F5 y6 n! M, |2 g" h1 j
  52. 52   GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
    5 e. p2 O. O6 z/ V
  53. 53   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;) e( {- q& A6 C2 {. q
  54. 54   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    % M% [! N7 E% N
  55. 55   GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);
    & M, ~4 Z8 g8 q
  56. 56   
    2 s, ^- C1 p3 {$ [. Y
  57. 57   /* Configure the EXTI line 18 connected internally to the USB IP */) Q% D& O% L3 Q) E  W  Y
  58. 58   EXTI_ClearITPendingBit(EXTI_Line18);# U5 a3 M" L5 o( n; I! M
  59. 59   EXTI_InitStructure.EXTI_Line = EXTI_Line18;
    4 ~& m, _! |4 J: q
  60. 60   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    * Z2 |1 |+ H1 Z! ?# f: y, ]
  61. 61   EXTI_InitStructure.EXTI_LineCmd = ENABLE;8 P$ V! k7 q  N: P: F9 w6 v/ C
  62. 62   EXTI_Init(&EXTI_InitStructure);
    + L( r5 z6 W) X) a: U/ P3 B
  63. 63
    . A& K& }! _& s
  64. 64   ! Y; Q" V" G+ t  F5 a) U
  65. 65 }
    + H- b7 s4 z, Q# K
  66. 66 / ~+ j7 B  K5 Z
  67. 67 /*******************************************************************************
    # h: x4 Y* i! [! z. |* x: T
  68. 68 * Function Name  : Set_USBClock
    % @( `) p- D  O( ~: h/ d1 ^
  69. 69 * Description    : Configures USB Clock input (48MHz)
    / u- @0 X" G3 u8 k% Z
  70. 70 * Input          : None.
    + h5 i0 S- t9 T5 Y
  71. 71 * Return         : None.; g' \# _5 A" }6 m% D# b
  72. 72 *******************************************************************************/
    4 r% Q9 U2 `* _( E' l$ x
  73. 73 void Set_USBClock(void)+ A2 {( G* k! W9 L8 @& M
  74. 74 {: }, b) H  `/ `; C/ ~2 N4 j
  75. 75   /* Select USBCLK source */* ]+ T4 [2 @( A+ R& {/ v
  76. 76   RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);7 f; F2 p1 n3 B6 X. v7 k
  77. 77     K& b" y5 E" ~9 w! p
  78. 78   /* Enable the USB clock */
    + n) I8 M% B' w  k6 d
  79. 79   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);- v  M3 h$ ~! @( l  G6 a+ z- Y
  80. 80 }
    " U+ v  [- U2 J( M* a& q
  81. 81 2 Z' Q# t5 @3 Q2 _
  82. 82 /*******************************************************************************
    1 s, b7 H2 f- {' p) h
  83. 83 * Function Name  : Enter_LowPowerMode
    & ?# m" h# e) r0 U1 |; n% `, B& ^
  84. 84 * Description    : Power-off system clocks and power while entering suspend mode
    8 t- \1 `( V7 _. \
  85. 85 * Input          : None.
    4 M  l2 ]# g' k7 \: {+ Y
  86. 86 * Return         : None.% }& l4 B( D) P+ {% I
  87. 87 *******************************************************************************/
    2 [8 y" Q& `2 A+ {7 A( K
  88. 88 void Enter_LowPowerMode(void)4 R- Y' R* s8 l; M: [) P
  89. 89 {! l; W; ~+ X+ {" q
  90. 90   /* Set the device state to suspend */2 J$ {, H6 \& z! ^7 c
  91. 91   bDeviceState = SUSPENDED;. g* u5 Z, G0 y, Q
  92. 92 }+ a9 f; S2 g4 o3 b% [
  93. 93 $ \6 Z8 F: V, E3 v! Q
  94. 94 /*******************************************************************************
    8 P- j1 v2 F3 Q$ U
  95. 95 * Function Name  : Leave_LowPowerMode/ [0 H# q, |. J' P0 m2 x/ m
  96. 96 * Description    : Restores system clocks and power while exiting suspend mode
    " i  T- e1 V" R% S( H, a0 j1 O2 M
  97. 97 * Input          : None.! h  l- X5 I/ D2 q
  98. 98 * Return         : None.! F5 w& r5 C* |0 `1 x2 M) q6 q
  99. 99 *******************************************************************************/- ^. z% T/ a0 m! }' F
  100. 100 void Leave_LowPowerMode(void)' c2 f) F2 Y# J+ w
  101. 101 {
    5 x! F$ q3 u1 u0 b3 Z4 H( J
  102. 102   DEVICE_INFO *pInfo = &Device_Info;5 \9 H6 _; y" @; d* t4 s
  103. 103
    # ~- k- R3 D8 K. i0 h4 p
  104. 104   /* Set the device state to the correct state */
    ; I3 i  X2 P0 E; c, K: a2 `
  105. 105   if (pInfo->Current_Configuration != 0)
    $ r/ W; q9 D6 {
  106. 106   {
    0 m# E. v3 j- ]0 ~: Y& a/ N0 t
  107. 107     /* Device configured */
    $ E7 X3 A  G' s9 H6 d+ i% i! N' h
  108. 108     bDeviceState = CONFIGURED;
    % ^* k2 w( m* t7 W' \* T
  109. 109   }
    0 N+ E) Q# i; M# z1 W3 p" ^
  110. 110   else1 o( m( x% `* \1 X% F
  111. 111   {, R8 |# [# f1 M' N8 A$ |
  112. 112     bDeviceState = ATTACHED;$ m0 j  i7 K) e# A( {( L9 P8 F
  113. 113   }
    * w# T2 s0 {& _; t
  114. 114   /*Enable SystemCoreClock*/
    " v3 X+ e$ o7 R2 q; e5 R) X
  115. 115 //  SystemInit();2 D( I' k; M0 g: }5 o8 d( J& x9 ?% n( e
  116. 116 }
    / s$ \/ Y2 R  u! f/ w, j
  117. 117
    2 p1 P1 x" s% c; a
  118. 118 /*******************************************************************************
    ( |+ L+ H8 e/ ]9 `: {% K
  119. 119 * Function Name  : USB_Interrupts_Config
    , ^! R) d- |( E+ v
  120. 120 * Description    : Configures the USB interrupts
    3 F3 f- T$ k9 y4 l2 T; B
  121. 121 * Input          : None.
    3 B4 D5 g: F: G) s
  122. 122 * Return         : None.
    : S' S  C( g& ~8 M, s5 o' f; C
  123. 123 *******************************************************************************/% |" ?6 G0 n5 d3 O! r
  124. 124 void USB_Interrupts_Config(void)
    : p" l3 O4 t  e) Y6 }+ a# r
  125. 125 {  Q1 G7 m) X. f9 H" V5 Z0 J
  126. 126   NVIC_InitTypeDef NVIC_InitStructure;
    8 s- T3 O- Q/ x
  127. 127 $ k/ A( Q5 T( g/ c
  128. 128   NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;( }5 U3 L$ E; J' C5 \6 m8 \+ {' |
  129. 129   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;4 ]; j( k  e2 q1 |: u( I: T  W  [, l3 c
  130. 130   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    + [! r2 @+ d! F. U/ r/ O2 i* c
  131. 131   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;5 M- @& {% C- N- g) N
  132. 132   NVIC_Init(&NVIC_InitStructure);
    ) I. O! C# N% `
  133. 133   
    5 m% A2 ~0 K5 J& K6 S
  134. 134     /* Enable the USB Wake-up interrupt */
    5 F1 k* S* h$ T9 g8 t
  135. 135   NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;, f2 H% o+ r$ D' \( X* H; y* }
  136. 136   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;3 {$ n% X1 O4 S
  137. 137   NVIC_Init(&NVIC_InitStructure);
    7 G: |) G1 W5 z+ q
  138. 138 }6 T: U% y8 m2 T4 l% Y
  139. 139 ; D: q* i7 Q) @+ M0 l8 k
  140. 140 /*******************************************************************************# C& C3 T5 A; y: w: l) M
  141. 141 * Function Name  : USB_Cable_Config
    * U# G1 h8 ?* V$ L1 q
  142. 142 * Description    : Software Connection/Disconnection of USB Cable- L4 i' w. J1 E% }& r+ h
  143. 143 * Input          : None.% C0 g7 C6 ?# U7 B
  144. 144 * Return         : Status
    : V3 s. b9 _* X6 k9 C$ Z$ C
  145. 145 *******************************************************************************/
    ' M. n9 [7 U- j' ^* ]
  146. 146 void USB_Cable_Config (FunctionalState NewState)
    5 _; K5 e+ q( v  L& Z
  147. 147 {
    9 g% {. P% t: k3 ?& \3 u
  148. 148   if (NewState == DISABLE)* _; O0 ]2 T) w, k4 y
  149. 149   {
    : J  A- I5 J7 u8 L* k1 s+ ?
  150. 150     GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
    . G8 d7 ]) g7 Q
  151. 151   }
    # z* K( A7 |8 [" @. u/ v6 a/ A/ p
  152. 152   else8 M7 A; s2 U/ b( e- b7 M5 y3 Q
  153. 153   {1 ~2 {5 X5 n+ r4 ]8 P
  154. 154     GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
    + G8 y' J8 `6 H% X+ d) Q
  155. 155   }
    % ], d# n  H! D- J" Y# e6 y) G% `
  156. 156 }* p; O6 i$ P6 @- |$ Q
  157. 157 ! N1 |& e1 Z; N1 ]
  158. 158 /*******************************************************************************
    " C2 ~. c* K" s6 o  N  ?5 @
  159. 159 * Function Name : void USB_Config(void)* ^! H9 L3 g9 ^+ ]
  160. 160 * Description   : USB系统初始化
    2 d$ g$ G$ u5 Q4 w
  161. 161 * Input         :
    # j+ Z5 j4 O9 [: l4 Y5 Q
  162. 162 * Output        :
    0 q4 h/ C& N. }) l7 S6 \
  163. 163 * Other         : 0 w3 w; Z9 V  ~7 _
  164. 164 * Date          : 2014.11.28
    & |* \; X5 S6 ~  w
  165. 165 *******************************************************************************/) k6 e) ?$ T4 ?4 ?* s+ ^
  166. 166 void USB_Config(void)3 z( J' {6 b) c/ D$ h
  167. 167 {6 g/ @# Q+ u3 k/ Q
  168. 168     Set_System();; A% Y3 _1 W/ }8 Z
  169. 169
    - E/ \+ r9 h) ^. Y; ~* Z; Y3 m, q
  170. 170     Set_USBClock();8 ^2 W/ ^' G5 A/ {8 x
  171. 171
    / P; m" O  ?% X9 P% s! d5 I
  172. 172     USB_Interrupts_Config();
    0 G" E/ X% L' {5 w, j: V; {
  173. 173
    % a8 o" E; c+ A6 Z% r# I- {) p
  174. 174     USB_Init();- b. [7 U, n. I  l
  175. 175 }! k8 b2 w2 c+ }
  176. 176 , u! z1 I, @1 x! }  `
  177. 177 /*******************************************************************************
    " @/ [  J0 ?5 d) e
  178. 178 * Function Name : uint32_t USB_RxRead(uint8_t *buffter, uint32_t buffterSize): Y0 J$ G, Q+ y7 v
  179. 179 * Description   : 从USB接收缓存中读数据
    $ u0 {6 |" p: z  G5 p
  180. 180 * Input         :
    0 w) C) w  I0 R# e7 m
  181. 181 * Output        :
    2 ]( W; w1 z* ?' b
  182. 182 * Other         : ; l/ N& y( p+ _) e* X
  183. 183 * Date          : 2014.11.28
    7 v) `# e( B3 w1 ~' p8 l
  184. 184 *******************************************************************************/. z- k& P7 ?+ P$ p% w0 V
  185. 185 uint32_t USB_RxRead(uint8_t *buffter, uint32_t buffterSize), k9 m0 d  [; H' |
  186. 186 {* k5 U! z8 W  l  \
  187. 187     return QUEUE_PacketOut(&m_QueueUsbComRx, buffter, buffterSize);9 S# g& n% [: k3 C7 U+ X
  188. 188 }
    4 ^! Z8 }6 N+ }  l. x
  189. 189 /*******************************************************************************
    ' F$ N2 z! O; L8 r; t  P
  190. 190 * Function Name : uint32_t USB_RxWrite(uint8_t *buffter, uint32_t writeLen)
    4 [. ?" W' Y( o  M  z
  191. 191 * Description   : 写数据到USB接收缓存中, A; K# h% |! I/ O' o
  192. 192 * Input         :
    4 Y6 p' j1 Z2 z( @' k6 ?$ a5 T% ]* n
  193. 193 * Output        : 0 u( [3 D' H+ \1 Y& T" N4 S! k/ h
  194. 194 * Other         :
    . h; U, m. u. G3 [1 w2 }! ?
  195. 195 * Date          : 2014.11.28! U1 }, _4 m+ |) c+ t3 q% R
  196. 196 *******************************************************************************/
    ; S$ I7 g1 K( m! w0 _& U
  197. 197 uint32_t USB_RxWrite(uint8_t *buffter, uint32_t writeLen)
    8 F% U. Z& l/ D* V; m
  198. 198 {$ p7 u0 f4 N7 L- W7 Q" c
  199. 199     return QUEUE_PacketIn(&m_QueueUsbComRx, buffter, writeLen);2 t0 }( V- }' ]3 R5 G" V- o8 j4 U3 i
  200. 200 }: m8 E9 i2 H/ Q
  201. 201 /*******************************************************************************" p7 z+ _8 @& t% x
  202. 202 * Function Name : uint32_t USB_TxRead(uint8_t *buffter, uint32_t buffterSize)
    % j9 A$ ^+ ~+ E
  203. 203 * Description   : 从USB发送缓存中读数据
    ) ]1 R. H$ v0 v$ i. e
  204. 204 * Input         : # y) Q3 v" s9 |) S& s! F3 H
  205. 205 * Output        : * R: i" J6 I# }. d& y1 J5 i
  206. 206 * Other         :
    " H* F2 ~( P- }) x8 F/ @
  207. 207 * Date          : 2014.11.288 F2 a, n8 z& `" ^* G8 |
  208. 208 *******************************************************************************/
    # g8 N: b9 |, i/ N  V  S( f
  209. 209 uint32_t USB_TxRead(uint8_t *buffter, uint32_t buffterSize)
    $ q0 [" D8 ~0 v; m' a
  210. 210 {
    8 _6 L; s2 w( k4 U( n  }
  211. 211     return QUEUE_PacketOut(&m_QueueUsbComTx, buffter, buffterSize);;* a5 u$ W$ H+ w+ n
  212. 212 }
    0 o* j' @* J9 j& F
  213. 213 /*******************************************************************************
    / C2 M6 K5 p" V2 J, ?/ I2 R
  214. 214 * Function Name : uint32_t USB_TxWrite(uint8_t *buffter, uint32_t writeLen)9 Y# |, U5 \+ l0 e* J' E! [' |
  215. 215 * Description   : 写数据到USB发送缓存中4 P6 S. K$ Q. F3 B. V) G; z
  216. 216 * Input         :
    8 J' a# M% {4 |( M0 W
  217. 217 * Output        :
    1 x9 e  n  {+ q9 x
  218. 218 * Other         :
    : e- w  B3 ], ~! U8 {6 Z! b% Z, K) v
  219. 219 * Date          : 2014.11.28* w" U/ X/ J8 W* B9 ^+ O" ^5 N8 f
  220. 220 *******************************************************************************/1 p1 A' c/ Z* F; O2 |% d: S
  221. 221 uint32_t USB_TxWrite(uint8_t *buffter, uint32_t writeLen)
    , G" z3 o6 V/ u/ U% O3 A
  222. 222 {
      O* P% U6 l( R' \9 K. D$ h/ q: N
  223. 223     return QUEUE_PacketIn(&m_QueueUsbComTx, buffter, writeLen);
    ( x5 l4 E, ?# O5 k, T* Q7 y
  224. 224 }8 `9 g( a* {: v2 ~$ c
  225. 225 . {3 T5 r: e1 i, f+ J0 j0 @
  226. 226 " I& G1 t3 ^; ]7 ^. ]4 V0 `; q3 |
  227. 227
      E$ B& v$ j# q- U
  228. 228 /*******************************************************************************
    ) F' {: Y( f! Z# _4 j, O% |
  229. 229 * Function Name  : Get_SerialNum.
      N/ T# b: L1 O5 G$ U2 B+ G
  230. 230 * Description    : Create the serial number string descriptor.
    / S5 B$ u0 f. _. j8 c0 n
  231. 231 * Input          : None.
    . U. _; \/ F: r/ v
  232. 232 * Output         : None.4 D4 F) g' {- f' ^& e5 d; O' u
  233. 233 * Return         : None.
    8 L, {6 o" k1 d0 l: ?
  234. 234 *******************************************************************************/: q2 J- x& I" h7 J
  235. 235 void Get_SerialNum(void)
    ! i" L) H/ D8 ?/ `
  236. 236 {+ l1 k, k5 m( _% W# f6 `* E6 w
  237. 237   uint32_t Device_Serial0, Device_Serial1, Device_Serial2;
    9 Z$ e$ F' I: s2 q
  238. 238 3 u* G- X0 f; X1 ]$ g9 a1 h  V. {
  239. 239   Device_Serial0 = *(uint32_t*)ID1;# a1 @! d8 A2 e" C
  240. 240   Device_Serial1 = *(uint32_t*)ID2;0 H5 V7 [" l7 W: e
  241. 241   Device_Serial2 = *(uint32_t*)ID3;  , m& G7 d+ p$ h3 v% t$ ?% ?6 X
  242. 242
    & a( b' E" z# @# f: W' v3 L
  243. 243   Device_Serial0 += Device_Serial2;
    " ^4 ~) m4 H; [! t. h; t/ Y. X
  244. 244 % H2 r8 D  }; T  x0 b
  245. 245   if (Device_Serial0 != 0)
      K2 `* ~$ W/ h/ K( z+ t5 x" u0 T( j
  246. 246   {
    % @. C& P4 I, ^* O3 g* P) V
  247. 247     IntToUnicode (Device_Serial0, &Virtual_Com_Port_StringSerial[2] , 8);, N6 g: f& r$ C+ a4 M
  248. 248     IntToUnicode (Device_Serial1, &Virtual_Com_Port_StringSerial[18], 4);
    7 ^% X6 C8 q4 K% I" U7 p/ l
  249. 249   }
    9 ~; h: S( e5 C/ D! ]: D
  250. 250 }
    9 L9 U4 n9 w. M0 }
  251. 251 % u/ Z1 \7 i' L% K6 P! ?* R
  252. 252 /*******************************************************************************2 N9 x! f8 ]: E, N9 n/ z$ N
  253. 253 * Function Name  : HexToChar.
    # W" _) F& S9 a0 o; }
  254. 254 * Description    : Convert Hex 32Bits value into char.$ O/ N6 ~2 c) W9 V# |1 n4 Y. g
  255. 255 * Input          : None.
    + X, d' p6 {  s
  256. 256 * Output         : None.0 U5 u+ G; _+ X! Z* ?: l9 ~( b
  257. 257 * Return         : None., J  {+ C# a& T- h+ o
  258. 258 *******************************************************************************/5 b9 `4 X$ K/ p7 e' ]
  259. 259 static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len)
      `! e7 c2 E/ X" B* n$ y# _. L
  260. 260 {
    / S) j# e3 U; e* j  {
  261. 261   uint8_t idx = 0;; f# y0 }% V' f% u" Q7 D  M5 m3 i2 u
  262. 262   1 L+ c) B; H* g- t2 a' y  ]! K. D( A
  263. 263   for( idx = 0 ; idx < len ; idx ++)/ ^/ N2 V! _6 b$ e/ t$ {" x
  264. 264   {
    . r) Q; d# ]. C* N6 T2 b3 C% n. A
  265. 265     if( ((value >> 28)) < 0xA )
    + m- a& p1 G. e+ ^! `/ v: H+ N& o' \1 @
  266. 266     {
    6 o7 j! y# m5 b$ t8 P
  267. 267       pbuf[ 2* idx] = (value >> 28) + '0';
    & [3 B2 x  f3 Q( f, C" Y3 j7 i
  268. 268     }
    ; i0 K6 z: x- [# B2 I
  269. 269     else- K! t! Q% D$ b1 s7 ?" `* g* q
  270. 270     {
    3 t. E" j7 ^. s& S* ~6 f
  271. 271       pbuf[2* idx] = (value >> 28) + 'A' - 10;
    / |: p1 C: J2 x6 J
  272. 272     }# g9 S6 X. X) A+ ~4 O$ D
  273. 273     
    * {- A0 p: h8 R8 _' [
  274. 274     value = value << 4;$ |& `6 Y3 n# T/ }; w/ f- Q6 Y
  275. 275     4 F% C# Y4 l  U
  276. 276     pbuf[ 2* idx + 1] = 0;
      k$ P* `7 m/ B2 K) O- |
  277. 277   }
    & `- B% P* W8 n% B5 ?9 o3 u
  278. 278 }, y1 A: i% b+ v! R% R
  279. 279 $ \; [4 s8 A' B+ o1 Z. i6 t
  280. 280 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码
9 N8 g$ R( ?! c0 p

6 R$ p2 s$ V' u( s9 f4 J" S
这里要讲一下为什么要屏蔽SystemInit(),因为demo只运行虚拟串口功能,在USB未插入的情况下,是进入低功耗状态,插入时从低功耗状态退出后会调用此函数。当然我们在项目中一般不会这样,系统是否运行和插USB接口没有联系。所以我在下文中把进入低功耗代码屏蔽了,自然也就不用唤醒代码了。
图7
2 r  m6 B7 a+ Y; f/ @2 }% E" v
300038465597900.jpg
% `6 D! u* v/ Q
关于USB口使能控制引脚,需要根据开发板的引脚定义来修改宏定义platform_config.h文件中,笔者使用的是神舟3号开发板,控制信号刚好和demo相反,所以修改hw_config.c代码如下:
代码3
  1. 1 /*******************************************************************************% O& A+ Z# e/ ]/ D# A! V( A" N7 W
  2. 2 * Function Name  : USB_Cable_Config2 j7 G" F/ M/ M( O( r+ Y
  3. 3 * Description    : Software Connection/Disconnection of USB Cable
    ' o. D  i+ A7 b0 m6 Q* v  @
  4. 4 * Input          : None." ?7 m4 r8 W2 N$ v5 I2 G# ]
  5. 5 * Return         : Status
      u! I0 P* l$ Z! q. t* t4 |8 d
  6. 6 *******************************************************************************/. B+ c" D' d3 \, e
  7. 7 void USB_Cable_Config (FunctionalState NewState); y) K- d3 Z  y, G
  8. 8 {4 i. _2 X* [2 w
  9. 9   if (NewState == DISABLE)& {, O" E  S, [& Y" _
  10. 10   {: ^( z( _3 z2 q
  11. 11     GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
    ! \) n+ p( n: A0 s9 S2 t
  12. 12   }
    # {3 ]8 a% ?! F. J
  13. 13   else
    / t: ~& y& |5 Q9 ?  N$ _
  14. 14   {# u3 S5 H. |! |0 Y0 W. Q( m
  15. 15     GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);5 {+ [( V3 J+ k0 c; V* [. c6 B( G6 e
  16. 16   }& M# {+ X! a, L. ?
  17. 17 }
复制代码

1 o* t1 N' Y5 B! ^2 k
3,现在修改USB 回调函数中的代码usb_endp.c文件。使用下文代码替换:
代码4
  1.   1 /* Includes ------------------------------------------------------------------*/
    3 @+ A( H/ @- m5 k/ `. [
  2.   2 #include "usb_lib.h"& J  P# G. L4 I! C4 w6 _
  3.   3 #include "usb_desc.h"
    ) U+ D# X3 J- i: d' X1 ^( q  `
  4.   4 #include "usb_mem.h"
    $ n* o8 h# U+ ?$ _
  5.   5 #include "hw_config.h"9 ]- T4 r- e1 A( ^6 a9 W
  6.   6 #include "usb_istr.h"9 b, l" y: l. x1 s1 G7 m
  7.   7 #include "usb_pwr.h". h( i% l1 l2 X- N! {" i
  8.   8
    5 f2 Y6 V1 n' x* ~; l
  9.   9 /* Private typedef -----------------------------------------------------------*/+ a7 J0 {8 d$ y9 x" N
  10. 10 /* Private define ------------------------------------------------------------*/
    6 v5 `" a4 v4 |
  11. 11
    6 `7 a% f. b3 z) n- Y3 {
  12. 12 /* Interval between sending IN packets in frame number (1 frame = 1ms) */
    : {1 |$ T6 Q1 F6 e" Z& m
  13. 13 #define VCOMPORT_IN_FRAME_INTERVAL             54 |. c1 U6 N% B1 }1 N
  14. 14
    9 X/ R1 p- B# ?% f; H1 t
  15. 15 /* Private macro -------------------------------------------------------------*/$ A3 j4 @: _* O. H2 x  i2 |+ q+ B
  16. 16 /* Private variables ---------------------------------------------------------*/. c* R) l, J/ Y- @" m+ `1 B+ b# z  h; v
  17. 17 static uint8_t txBuffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};5 o+ j# D# D$ f) t
  18. 18 static volatile uint8_t txFlg = 0;
    1 E1 l/ M; j. A: ^* A
  19. 19 static volatile uint32_t FrameCount = 0;
    0 b; W* p- }3 v" C. `3 B& P/ _
  20. 20
    ' f& v. F! \2 c, |3 c6 J
  21. 21
    ' K5 k3 |' ~+ R" T' N+ E6 ^
  22. 22 /* Private function prototypes -----------------------------------------------*// k6 e) l; _# ?) u
  23. 23 /* Private functions ---------------------------------------------------------*/. p; R: v9 `+ o: P6 v
  24. 24 , S' }2 d/ E) M! S
  25. 25 /*******************************************************************************
    5 C  A* B- n* ?  r0 }8 u
  26. 26 * Function Name  : EP1_IN_Callback
    7 h$ J9 w. _' ]9 j% R/ m
  27. 27 * Description    :
    $ F: s6 u1 z( i6 K: {1 A$ F
  28. 28 * Input          : None.6 A! Q2 Z" d. O- ]
  29. 29 * Output         : None.
    & U' E/ \  Y* f6 i
  30. 30 * Return         : None.  D* M1 b8 s5 Y* @
  31. 31 *******************************************************************************/
    5 U  d* o/ N& M  n+ R8 N
  32. 32 void EP1_IN_Callback (void)
    ( M2 J( B9 Q4 |7 B9 \% q2 K
  33. 33 {
    1 T% I# Q& ^5 n* k
  34. 34     uint16_t len = 0;. [# V4 Q3 L( e/ J" w  r4 v7 u' _) Z
  35. 35     
    ) l6 X6 V: y; U; d5 B
  36. 36     if (1 == txFlg)6 z% E* e- [/ D' x- V8 G
  37. 37     {8 L9 W2 m/ ?7 U7 S; Q
  38. 38         len = USB_TxRead(txBuffter, sizeof(txBuffter));
    / D- S' K- w% x8 j$ Z5 S6 Q3 z) ^
  39. 39 ) [0 n- ~& V( e* C9 H
  40. 40         if (len > 0)5 H. d  R- x( |# ~3 |
  41. 41         {  _: n) K/ q  Z. O) g) O
  42. 42             UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);6 a& O+ P. q: n* W( g
  43. 43             SetEPTxCount(ENDP1, len);
    % k/ m. C7 }2 V: O
  44. 44             SetEPTxValid(ENDP1);
    * z. K, @0 c$ R* y( q& [
  45. 45             FrameCount = 0;
    7 \$ Y& m: U# d- x% L) B
  46. 46         }
    0 U3 j! L& r0 k0 y0 @8 i
  47. 47         else$ B4 c4 l9 L$ x1 l
  48. 48         {
    ( W' T4 c" J" e  j& J) Z, D$ Z' b
  49. 49             txFlg = 0;5 _/ m& }3 ]6 t, W8 E$ w/ o9 g5 @
  50. 50         }
    8 n1 m% _$ a' K6 u& D1 q
  51. 51     }2 Y  Y: V5 n7 z* u! b  B
  52. 52 }! U/ O( J- n& n* F. x- y
  53. 53 , o; X' O; Q' m3 h/ ]+ N
  54. 54 /******************************************************************************** H, w2 ]# a8 K, m( z$ c$ W
  55. 55 * Function Name  : EP3_OUT_Callback
    : c; L; {) _6 o" A& t2 \
  56. 56 * Description    :& Z$ L" Q1 w# a/ M  y
  57. 57 * Input          : None.  _3 ^/ K# s( {% b
  58. 58 * Output         : None.
    ; ]' k7 t0 t- s5 D
  59. 59 * Return         : None.
    0 [1 N( W6 k+ I) \5 t5 Q. `
  60. 60 *******************************************************************************/
    $ T7 h, A# t) F# G. K  H
  61. 61 void EP3_OUT_Callback(void)
    : d( S' B. m# v$ f
  62. 62 {
    ( B# m& Y. B5 f
  63. 63   static uint8_t buffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};
    5 I4 I" }# e, M6 d
  64. 64
    " u9 V2 G/ u( E8 H/ S
  65. 65   uint16_t USB_Rx_Cnt;4 N  b' j2 ~) t7 e9 `$ ?
  66. 66   1 d( S' h8 n5 E5 c
  67. 67   /* Get the received data buffer and update the counter */$ i) m; x: N! C2 p5 Z: m
  68. 68   USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, buffter);) |5 D" Y- S! H% K. O/ S) h
  69. 69   
    ! u$ p$ A/ B% k- \# A0 p
  70. 70   /* USB data will be immediately processed, this allow next USB traffic being
    + t1 y( U7 R5 b* y
  71. 71   NAKed till the end of the USART Xfer */
    2 \4 c) j& _; p* j9 S
  72. 72   USB_RxWrite(buffter, USB_Rx_Cnt);
    % R/ G1 K' T2 Z) }9 E) n4 V7 O
  73. 73
    , X) r+ t" ]. D
  74. 74   /* Enable the receive of data on EP3 */
    ! q5 M+ }+ _- A8 J7 x
  75. 75   SetEPRxValid(ENDP3);' L2 t+ N; Y, {3 {" ?
  76. 76 * a* z4 L* K: w5 }6 I! A- v
  77. 77 }
    / O. @' ]' ?9 B/ v: b
  78. 78 ; ?( g; Z7 @5 I5 R
  79. 79
      f( U. P+ `3 i" _/ ^4 f
  80. 80 /*******************************************************************************
    % J+ [8 S) M# C" d5 T0 V
  81. 81 * Function Name  : SOF_Callback / INTR_SOFINTR_Callback
    9 ?$ W2 X6 L( v0 j9 w, m
  82. 82 * Description    :
    ; ?8 U' x6 y( V: F
  83. 83 * Input          : None.' d2 _9 a+ h9 S/ C- X2 Y1 T3 Q
  84. 84 * Output         : None.' L9 }* }& q# B( O; n  S
  85. 85 * Return         : None.
    8 ?2 n/ ?2 @8 k2 y/ K! M5 U4 Y
  86. 86 *******************************************************************************/% y8 i, f" x( E) K- J: p
  87. 87 void SOF_Callback(void)
    7 J4 }1 N+ f5 b% s! O3 j  [
  88. 88 {- z( k' M, N, j3 Y
  89. 89     uint16_t len = 0;/ a7 t/ R1 U' g4 Z
  90. 90 " o. J0 |  I& U8 M: [
  91. 91     if(bDeviceState == CONFIGURED)* h: Y, ^# A! H
  92. 92     {
    3 G5 t  b9 r5 H( e7 k! G- L
  93. 93         if (0 == txFlg)
    . \: a" g3 r9 W/ }
  94. 94         {
    ( m) R$ `- f% r6 q6 h% ]3 Q
  95. 95             if (FrameCount++ == VCOMPORT_IN_FRAME_INTERVAL)
      Q! L* w+ w9 ~
  96. 96             {
      E8 Y" A0 i1 h3 |- d
  97. 97                 /* Reset the frame counter */  `. ?3 p$ P) g$ {" F1 c$ u
  98. 98                 FrameCount = 0;
    5 S  D+ G8 x6 _& [
  99. 99
      `3 a' S; X4 s" [9 t) W4 x6 g- @
  100. 100                 /* Check the data to be sent through IN pipe */) M- T/ k9 N* o) T% x+ q+ f6 k6 G; k
  101. 101                 len = USB_TxRead(txBuffter, sizeof(txBuffter));4 u$ M: L; |) h- f1 J% v
  102. 102
    7 V, C. Z0 B. q/ Z; V
  103. 103                 if (len > 0)6 x( I+ v% x/ W8 g0 b
  104. 104                 {
    * }1 g& M, q# g3 E# G
  105. 105                     UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);
    2 ]% b/ f& l0 [6 `" h
  106. 106                     SetEPTxCount(ENDP1, len);2 g1 s8 k) J+ d$ d3 }1 P: ^
  107. 107                     SetEPTxValid(ENDP1);9 k- W9 k3 D& @$ J% H+ G
  108. 108 6 R' {0 g4 E6 Y9 f" o
  109. 109                     txFlg = 1;( M3 F% A  {+ W/ T- v! U5 T7 S
  110. 110                 }
    : a, s$ `$ Z' y0 O& r6 ^" v" g3 s
  111. 111             }
    ) _# r6 e# M0 i4 b& M' K
  112. 112         }( V+ t4 o- C7 b
  113. 113     }  
    , S, [! V5 `/ ]6 C! s
  114. 114 }4 Y) ?9 ~6 `) i2 ?1 ~) w
  115. 115 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码

- E" a! j7 c- U) p! u; V; ^
6 w9 ^( e8 A. k$ o$ _- @
这里讲下大概意思,函数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也一起存放在上文章开始的链接中。

  C  |" P; ^, k: p& E: W
收藏 评论0 发布时间:2022-1-13 21:00

举报

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