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

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

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

( e# V7 L% B0 y" E( a, a9 L* `
5 Z& W% X$ z) \* m! p
首先打开官方demo我们开始进行移植,第一步复制我们可用的文件,操作如下:
Projects\Virtual_COM_Port文件夹下,复制红线部分
图1
* V5 E# d6 e" z: B/ U- o) c0 K
300035032772082.jpg
. X' Q# b* r: u" y3 ?
图2

, [( d4 S8 B$ j) h# B' s) C
300035202932682.jpg
' ]7 J1 e" s8 K! E% ~: _0 o
我为了方便演示统放在usb/src文件夹下:
图3
; x# n. S9 n( {$ ]' ~
300035313246246.jpg
! t" O( H$ z6 D$ V8 _( V
现在复制USB的库文件,这些文件不需要我们修改:
图4
* W2 p, y! h# B, l
300035404189967.jpg
# z. b* @* ^# M4 g/ _
上图中的文件统一放在usb/lib文件夹下:
图5

2 C/ b$ L' W9 K4 |
300036032935279.jpg
9 V/ I) ?: N" D2 E& M, i

* f7 O5 X1 u" V. W2 a" M
         好了现在所需要的文件我们以复制完了。这里先讲一下DEMO程序的主要工作流程:

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

  E* U8 {7 k) @3 f* p" M, e* n% g: f# @
这里要讲一下为什么要屏蔽SystemInit(),因为demo只运行虚拟串口功能,在USB未插入的情况下,是进入低功耗状态,插入时从低功耗状态退出后会调用此函数。当然我们在项目中一般不会这样,系统是否运行和插USB接口没有联系。所以我在下文中把进入低功耗代码屏蔽了,自然也就不用唤醒代码了。
图7
4 t4 U6 l" W2 b! S7 H$ l
300038465597900.jpg

5 N( q* d! E+ g! Z2 z# I% Z0 i5 Z
关于USB口使能控制引脚,需要根据开发板的引脚定义来修改宏定义platform_config.h文件中,笔者使用的是神舟3号开发板,控制信号刚好和demo相反,所以修改hw_config.c代码如下:
代码3
  1. 1 /*******************************************************************************
    % K( u" D) r5 q( _) E0 A. d6 G9 `
  2. 2 * Function Name  : USB_Cable_Config) K  R4 w& z' V3 t8 N2 O
  3. 3 * Description    : Software Connection/Disconnection of USB Cable
    ' V4 V' W# ~: F* }# H' v2 w
  4. 4 * Input          : None.
    $ W! I8 F) a/ n6 h
  5. 5 * Return         : Status$ [, N: O5 Q& z2 q
  6. 6 *******************************************************************************/
    * P3 ~& M5 W( c% o
  7. 7 void USB_Cable_Config (FunctionalState NewState)
    " F/ H7 j8 p3 V- h3 E$ j* Q
  8. 8 {0 e1 J1 e! \) B$ x2 ~+ {
  9. 9   if (NewState == DISABLE)
    ; F! P; d& k: c! y( v5 R* s
  10. 10   {
    , u* o1 Y3 |/ j. N- q1 N  w: D5 ]
  11. 11     GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
    7 a- H, d, U# M6 l3 D" r  p
  12. 12   }# v( L0 G: D1 a
  13. 13   else4 O. \5 u8 O. m% W) ^  c3 {0 [6 W
  14. 14   {2 l1 s6 M3 E  r3 {' z. T" s" a
  15. 15     GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);' n; X9 Z+ k" d) i2 D
  16. 16   }
    - D- n7 v- K  k% d5 i, {
  17. 17 }
复制代码

2 u2 a, v, k' d+ s
3,现在修改USB 回调函数中的代码usb_endp.c文件。使用下文代码替换:
代码4
  1.   1 /* Includes ------------------------------------------------------------------*/: R6 A! ^, ~( o% j* E' }0 H
  2.   2 #include "usb_lib.h"
    - i1 y6 T7 `3 i/ `: U3 T8 Z
  3.   3 #include "usb_desc.h"
    4 x4 J$ R7 ?' q8 Y$ E/ f
  4.   4 #include "usb_mem.h"* @, N) A1 K( E8 }
  5.   5 #include "hw_config.h"* i) @* x, N- k3 W  o0 Y: Z1 Z3 n
  6.   6 #include "usb_istr.h"
    4 s( J$ n1 c* Q: v2 g
  7.   7 #include "usb_pwr.h"
    ( g7 T" }3 ~# z  j3 }
  8.   8
      Z; O! Z6 S: w% U6 N
  9.   9 /* Private typedef -----------------------------------------------------------*/0 d: H0 l+ s7 T0 [9 d
  10. 10 /* Private define ------------------------------------------------------------*/
    # G/ Z- s% O+ j2 A
  11. 11 4 _# l5 z4 Y" u% q% w. _4 M
  12. 12 /* Interval between sending IN packets in frame number (1 frame = 1ms) */
    + q) V' m; T* o* c5 L4 V0 t
  13. 13 #define VCOMPORT_IN_FRAME_INTERVAL             5
    : `% \8 s" s' B& i+ O# {
  14. 14
    ; B% M3 ^$ s5 b
  15. 15 /* Private macro -------------------------------------------------------------*/
    1 S- Y5 Q2 R4 [$ v/ z
  16. 16 /* Private variables ---------------------------------------------------------*/
    / t% c  T7 \& V( J
  17. 17 static uint8_t txBuffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};' x3 b5 C6 h; V" R, B
  18. 18 static volatile uint8_t txFlg = 0;
    8 N1 r% T% |) I. G( }
  19. 19 static volatile uint32_t FrameCount = 0;
    9 H  @. e6 ]% V2 m( X. ~9 T
  20. 20
    ' I* H; G. ]6 ?) N) O
  21. 21   v( w3 T3 N# Y; y: K
  22. 22 /* Private function prototypes -----------------------------------------------*/
    0 L# g0 U: p: s8 S
  23. 23 /* Private functions ---------------------------------------------------------*/
    - w" ]9 G6 x: r  U
  24. 24
    0 [/ p  B! }' {) }4 E
  25. 25 /*******************************************************************************
    ; F! q* w& {8 W( \& p
  26. 26 * Function Name  : EP1_IN_Callback: t4 c) D: ^5 ~
  27. 27 * Description    :
    . K7 P0 h! P4 U2 w9 S7 ?# k
  28. 28 * Input          : None.
    - M9 |. p% a+ ^/ ]. K
  29. 29 * Output         : None.+ [; x. _! I$ m* J) ]8 j2 l0 i
  30. 30 * Return         : None.
    # Z! g) r3 z8 {
  31. 31 *******************************************************************************/: T- e* A) |: d) `" C! L
  32. 32 void EP1_IN_Callback (void)
    7 `% l7 J( h; _1 |' y2 }* S
  33. 33 {9 B8 t  C7 I/ m" j( Z& x) a) w  w# G8 B5 E
  34. 34     uint16_t len = 0;  e1 w7 o- z+ ?. t0 Q
  35. 35     
    , L7 a$ x! ~; U2 n$ L0 D
  36. 36     if (1 == txFlg)4 S8 o1 k" o* o% o
  37. 37     {, w/ y% z+ ^+ a  G
  38. 38         len = USB_TxRead(txBuffter, sizeof(txBuffter));
    " y9 ^5 {% w: n! \) W: q: S6 p# D
  39. 39
    ! u/ q" M& B/ L+ Z
  40. 40         if (len > 0)1 Z8 t  U, L* [* K* M1 R6 w: P: u
  41. 41         {' w2 [; W* t8 J% w: B( K; H
  42. 42             UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);
    ( `$ }& @5 s) C/ @0 N
  43. 43             SetEPTxCount(ENDP1, len);( y3 \# H. |! Q2 {; A
  44. 44             SetEPTxValid(ENDP1); / W( Y& c$ ]2 s& z0 O+ l4 h2 X/ ^5 }
  45. 45             FrameCount = 0;' G  s% a( X- t( j
  46. 46         }
    8 Y) y6 [! G  }; m( U5 G. @
  47. 47         else
    ; o6 t5 I8 S- p  }. J6 H
  48. 48         {+ V/ P) V. m6 Z6 L3 [
  49. 49             txFlg = 0;% m5 i" S# K; r0 i% v' I; w
  50. 50         }
    $ t4 g# d/ T- X$ c3 M" K; Y
  51. 51     }
    / i+ A% P! T2 j0 s, x0 f) ~
  52. 52 }
    : f7 V3 e! n. R; h; W7 ^
  53. 53 8 L$ |1 `$ n! ^! Y
  54. 54 /*******************************************************************************) D) h% N" F3 e" q/ m
  55. 55 * Function Name  : EP3_OUT_Callback
    3 y& [4 ^4 A8 L$ }# @- J2 |5 z
  56. 56 * Description    :
    6 `+ N+ P8 S! `4 ^6 [
  57. 57 * Input          : None.
    % U- j2 _' o, g: {
  58. 58 * Output         : None.8 ~/ O- e; w+ d( v
  59. 59 * Return         : None.) R* w6 @4 @; ?* W! b
  60. 60 *******************************************************************************// C9 E8 g8 K+ j/ F) A/ V  u
  61. 61 void EP3_OUT_Callback(void)) B4 j( q) u; s" c! P1 x, x. T
  62. 62 {; P  @4 X6 {0 l5 |
  63. 63   static uint8_t buffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};& v4 P- W6 q  W' i; z2 Z
  64. 64
    6 p9 L' H# |; }/ ~
  65. 65   uint16_t USB_Rx_Cnt;
    4 E, `% y: q. q# j% Z0 _2 `
  66. 66   ' |) B$ h) x$ E9 i
  67. 67   /* Get the received data buffer and update the counter */
    ' n. C- e1 ~' a+ P2 d* {  U
  68. 68   USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, buffter);
    1 X' f- \" M9 U1 M& f" {- K6 T
  69. 69   ! s8 r4 f* i( q; P5 b; k+ ?
  70. 70   /* USB data will be immediately processed, this allow next USB traffic being   h/ A' y0 Y- h& l* M0 O+ N
  71. 71   NAKed till the end of the USART Xfer */
    ! Y$ t% u/ Z# [/ ?4 y
  72. 72   USB_RxWrite(buffter, USB_Rx_Cnt);/ m- K! ~# N( R7 O7 x
  73. 73
    % e( Q3 W: j* g9 V; P( w
  74. 74   /* Enable the receive of data on EP3 */1 u' K0 q5 Z3 E: Y% H& K
  75. 75   SetEPRxValid(ENDP3);
    0 k( n2 V" T- Z& j3 ^- |4 y+ b
  76. 76
    7 f2 D+ i  f  ?+ R# b2 v9 x  L
  77. 77 }
    6 z6 K$ U. g+ G5 \& D$ e
  78. 78
    " D4 j! F; s! K$ k* O, _3 |! w
  79. 79
    1 w% a2 g& X3 n
  80. 80 /*******************************************************************************
    5 x4 z  Y7 B" f  T5 O7 }/ u" @2 {4 X
  81. 81 * Function Name  : SOF_Callback / INTR_SOFINTR_Callback5 \+ D+ w; k" b. P( T
  82. 82 * Description    :
    : {- q8 U' R7 I: `" p8 ^
  83. 83 * Input          : None.: W% M1 d5 Z0 W4 O7 J9 @2 B$ C" d
  84. 84 * Output         : None.
    ' N/ n/ A* f- n8 S& `( h
  85. 85 * Return         : None.
    # R* ~( M4 U+ a0 z6 F) E) {
  86. 86 *******************************************************************************/
    ( n( ]) i9 @; G5 Y0 i+ D2 U! n/ K! ^# w
  87. 87 void SOF_Callback(void)
    9 X; `1 G  J- {( t
  88. 88 {
    / D6 }. v: Q+ p: b& X7 K
  89. 89     uint16_t len = 0;
    . ^* A* T: r: Z/ _( D
  90. 90 % y6 U, H: Q5 }
  91. 91     if(bDeviceState == CONFIGURED)
    7 h5 S# ^0 b$ i5 f9 R# K* X% j
  92. 92     {
    ! K6 g5 ?) X$ H
  93. 93         if (0 == txFlg)& V8 }6 R1 n: c+ K- }0 k
  94. 94         {5 Y& J! [. v5 p0 g1 o
  95. 95             if (FrameCount++ == VCOMPORT_IN_FRAME_INTERVAL)
    5 E* p6 |6 E+ y/ i
  96. 96             {0 S8 @8 O# N( m. n4 @
  97. 97                 /* Reset the frame counter *// k- X: J* }8 t7 l
  98. 98                 FrameCount = 0;2 x5 ~. j1 W6 x8 H% i
  99. 99
    3 C7 I& i$ h8 P* a+ z
  100. 100                 /* Check the data to be sent through IN pipe */7 i2 `% y' q2 U2 t
  101. 101                 len = USB_TxRead(txBuffter, sizeof(txBuffter));
    1 T- F6 U+ G2 k, T4 {) {3 |* \
  102. 102
    # [3 t% J$ ~. R% {! y) L0 f& N
  103. 103                 if (len > 0)
    * v& s/ [/ X: j- D
  104. 104                 {1 a3 Z& p+ O8 H9 T, {. P
  105. 105                     UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);$ ]  A9 R. ?) u: u" }
  106. 106                     SetEPTxCount(ENDP1, len);
    # ~+ J/ p! z* @- [  @
  107. 107                     SetEPTxValid(ENDP1);
    & \) S, P% i% ^! w- G- E+ e
  108. 108 ) x: q9 `) q  l! }7 Z
  109. 109                     txFlg = 1;
    1 g( t8 h; n- d2 ~
  110. 110                 }' r, E' b" i/ v# i' d
  111. 111             }
    & e8 x' M2 X, Q: g. ?
  112. 112         }
    ) ^  t8 B$ Y# V" v' _2 j
  113. 113     }  % f7 Z2 \( E2 Y( C
  114. 114 }
    2 S% A0 v& W  u
  115. 115 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码
3 f( @/ [1 r9 P6 B

% U9 Q% f0 W+ _9 H- q/ S) k0 x
这里讲下大概意思,函数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也一起存放在上文章开始的链接中。
+ K. ^& o+ {/ f
收藏 评论0 发布时间:2022-1-13 21:00

举报

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