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

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

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

5 `3 h" {9 L5 O7 v; Y8 i" u- O; b7 ]3 V/ B/ t9 u
首先打开官方demo我们开始进行移植,第一步复制我们可用的文件,操作如下:
Projects\Virtual_COM_Port文件夹下,复制红线部分
图1
- P% ~* n! l! U9 g1 j
300035032772082.jpg
0 n0 T$ s' J- o" R3 h
图2

: N8 b) N" ~8 W( h7 ^) F: _7 J
300035202932682.jpg

' s' M& W5 H1 [& d
我为了方便演示统放在usb/src文件夹下:
图3
( o0 x4 d/ u' q* t# _
300035313246246.jpg

. H4 o+ ?2 u8 P- I5 E
现在复制USB的库文件,这些文件不需要我们修改:
图4
) |" K) o+ M* G2 A4 I# w
300035404189967.jpg

' w' x3 `2 x5 f6 L# p6 }- A- c
上图中的文件统一放在usb/lib文件夹下:
图5

% T- s6 Y2 b: H" {- L: ?
300036032935279.jpg

* A. {% e# w, q. ]& L- U) `& A" P- d0 X8 h7 {% D% ^- g
         好了现在所需要的文件我们以复制完了。这里先讲一下DEMO程序的主要工作流程:

: @+ Y( t1 Z# ^6 b7 x  L
300036178402768.png

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

5 Y! v/ o" ~5 G: b- m8 S0 d
这里要讲一下为什么要屏蔽SystemInit(),因为demo只运行虚拟串口功能,在USB未插入的情况下,是进入低功耗状态,插入时从低功耗状态退出后会调用此函数。当然我们在项目中一般不会这样,系统是否运行和插USB接口没有联系。所以我在下文中把进入低功耗代码屏蔽了,自然也就不用唤醒代码了。
图7
5 o" ~6 o5 f3 I) w
300038465597900.jpg
% h( Q# l) B. }9 p1 K, b3 W6 U
关于USB口使能控制引脚,需要根据开发板的引脚定义来修改宏定义platform_config.h文件中,笔者使用的是神舟3号开发板,控制信号刚好和demo相反,所以修改hw_config.c代码如下:
代码3
  1. 1 /*******************************************************************************
    7 b0 }, t# v  {9 k0 k
  2. 2 * Function Name  : USB_Cable_Config
    $ J& k  i( U2 t4 j) u" ~$ J
  3. 3 * Description    : Software Connection/Disconnection of USB Cable2 r9 `3 u2 _- ?* S  i5 L5 \
  4. 4 * Input          : None.
    * h5 V& H! D- G. n' _, a$ ]9 q
  5. 5 * Return         : Status
    & G" U; j1 p2 }6 I% ?' V  g* f
  6. 6 *******************************************************************************/
    1 V- S. z3 p3 }4 v. s( ]5 u, h
  7. 7 void USB_Cable_Config (FunctionalState NewState)" r. |2 S3 J- X
  8. 8 {
    & A# ?. `7 }4 p: s/ U! T
  9. 9   if (NewState == DISABLE)
    " H$ p8 s0 L! M8 g* D
  10. 10   {( w+ c0 |- \* [/ L2 s; D( g
  11. 11     GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);, |% T7 w( Z, W+ z1 {# l
  12. 12   }) w; c. B- ]* {+ F% E
  13. 13   else
    - i) n' ~) d0 ^1 d# z# M
  14. 14   {5 }- C. c& X" Q. ?2 k( Z4 s
  15. 15     GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);2 @% u; S) `+ k1 s1 U7 V  \
  16. 16   }0 R% E  Y7 `: x' _$ D
  17. 17 }
复制代码

+ a( k, j- e% p; X7 X5 I
3,现在修改USB 回调函数中的代码usb_endp.c文件。使用下文代码替换:
代码4
  1.   1 /* Includes ------------------------------------------------------------------*/, z4 r5 L4 ]- W# c! e& O- {
  2.   2 #include "usb_lib.h". ~0 E$ T4 s2 O$ X9 [. w  v2 |
  3.   3 #include "usb_desc.h"
    # h1 @, x. n" G* y& d- q
  4.   4 #include "usb_mem.h"
    # R0 n8 O- r& H% R" r/ X* @2 D! n! n3 E
  5.   5 #include "hw_config.h"; M4 o5 Q0 M7 k$ E$ r! |
  6.   6 #include "usb_istr.h"3 o/ r* I! l: k
  7.   7 #include "usb_pwr.h"
    , e0 _: l1 e: Z5 y
  8.   8 1 o& ~( ^8 P" C# A. u
  9.   9 /* Private typedef -----------------------------------------------------------*/
      w& g/ \! m3 J4 z: P
  10. 10 /* Private define ------------------------------------------------------------*/
    7 e* l' ^$ S! x/ i
  11. 11 & b$ N1 z. J$ l4 ?& Q
  12. 12 /* Interval between sending IN packets in frame number (1 frame = 1ms) */
    3 U9 a1 N' s7 K9 @
  13. 13 #define VCOMPORT_IN_FRAME_INTERVAL             5
    6 G$ @8 m& U4 l) A3 \4 Q9 v; {0 g
  14. 14   p0 y+ l6 t' x2 M9 P
  15. 15 /* Private macro -------------------------------------------------------------*/
    8 x' Q& P% _6 J, b
  16. 16 /* Private variables ---------------------------------------------------------*/( F. j; X6 k5 s# `
  17. 17 static uint8_t txBuffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};
    0 ?% i" Q3 p, J" G
  18. 18 static volatile uint8_t txFlg = 0;5 y: s; Y4 v6 O
  19. 19 static volatile uint32_t FrameCount = 0;. \' j3 n7 h9 ^* O5 q
  20. 20 & |7 U) `1 [! n: E6 N5 x
  21. 21
    ; ?: p. R8 L. L3 Y3 U+ R
  22. 22 /* Private function prototypes -----------------------------------------------*/
    ( Y/ ~/ K4 ~4 ~/ i# h, g
  23. 23 /* Private functions ---------------------------------------------------------*/( m$ _) M/ z$ B
  24. 24 1 @" T- f! B/ I0 Z/ X$ z; s
  25. 25 /*******************************************************************************
    ) ]- K% m* Q' Q; s& P! [/ j
  26. 26 * Function Name  : EP1_IN_Callback. w( g2 e$ |7 k$ S  `& L9 G
  27. 27 * Description    :  D* w4 n4 o% O# E+ D9 t. ?
  28. 28 * Input          : None.  F4 s& x2 E; N% s9 {. c: L3 A
  29. 29 * Output         : None.
    : y6 I6 n) _% G! F: v
  30. 30 * Return         : None.0 d: T# W3 x5 G1 _
  31. 31 *******************************************************************************/
    * i3 D1 H9 k0 {. ^" t& T
  32. 32 void EP1_IN_Callback (void)
    1 P% ?/ T5 ~4 K4 A9 ]
  33. 33 {
    6 X, w8 M! K1 J; ?9 r$ k1 o
  34. 34     uint16_t len = 0;
    # c$ h) C& r4 C
  35. 35     
    8 P3 O' b" J5 |6 I2 k2 L  {  N1 k
  36. 36     if (1 == txFlg)
    % s! }4 H& ~5 l9 p  T$ Z
  37. 37     {6 t: c& S" ^& C; ^
  38. 38         len = USB_TxRead(txBuffter, sizeof(txBuffter));) h! m6 N& d& d+ r& {% X
  39. 39 # c8 b" f3 ^; H, p* W& O# \
  40. 40         if (len > 0)
    7 I' G6 Y! z! P3 j  X! x- s
  41. 41         {! i6 B, O* j, i. Q% L
  42. 42             UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);
    5 n/ q7 ]: u  i) O- `
  43. 43             SetEPTxCount(ENDP1, len);
    % r3 M! c# A6 ]) R2 `5 |
  44. 44             SetEPTxValid(ENDP1);
    & R+ Y$ e7 A1 q
  45. 45             FrameCount = 0;
    ) S5 x+ d) W3 M7 J7 [+ z% V
  46. 46         }
      H+ V/ q9 V, Z8 r
  47. 47         else
    1 @4 ?2 Z2 j- x4 A1 i
  48. 48         {
    5 v3 c1 f# q9 [& m& R! S& ~
  49. 49             txFlg = 0;. k0 _" A- p! x" e: ^
  50. 50         }
    , ?% F* _9 \2 L
  51. 51     }( n  V6 [" U. Q" ?& Q+ |
  52. 52 }" z; J' J  R( X3 c
  53. 53
    7 U$ P7 k: U1 t) W8 S4 w0 {  l* \
  54. 54 /*******************************************************************************
    * _. S* _! v. n: e+ c
  55. 55 * Function Name  : EP3_OUT_Callback
    1 Q3 F, X0 R, L3 B1 M$ Q. w
  56. 56 * Description    :
    : K) n+ i, y( q9 k3 Y+ a+ Q# N& ^" u
  57. 57 * Input          : None.
    5 @- |9 T# F) w& m  W: x4 f" `
  58. 58 * Output         : None.
    # [( j* O! T& W- N* \
  59. 59 * Return         : None.
    ; F. [# V% N- s. U7 Z
  60. 60 *******************************************************************************/
    6 g) d; N7 a& h
  61. 61 void EP3_OUT_Callback(void)
    0 j3 u; x7 |( e4 W& s8 \5 ?9 J6 I
  62. 62 {
    ( [- _" c7 X% `" F
  63. 63   static uint8_t buffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};4 [. o* c' e1 f  P9 H% m( Q
  64. 64 9 ^8 ^9 F/ |5 j5 _$ \# p2 y
  65. 65   uint16_t USB_Rx_Cnt;# Z; ]5 [+ [4 P: C
  66. 66   
    + t! D3 H3 I3 U% V
  67. 67   /* Get the received data buffer and update the counter */
      j; @7 d% E/ I! h9 e
  68. 68   USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, buffter);! x1 b+ u1 U  m7 g8 R2 X6 L/ w
  69. 69   
    2 M- C2 J; }/ L' ~
  70. 70   /* USB data will be immediately processed, this allow next USB traffic being * h( Z  r! V/ k
  71. 71   NAKed till the end of the USART Xfer */
    5 P6 U0 C/ u9 c) q& l( M* f
  72. 72   USB_RxWrite(buffter, USB_Rx_Cnt);# L( w$ O; }3 q' J8 J/ B+ {  y
  73. 73 3 s. f0 [4 J# n
  74. 74   /* Enable the receive of data on EP3 */
    , E2 E# q8 e, }  S- M7 f- j' a
  75. 75   SetEPRxValid(ENDP3);
    5 ]# I" _% W1 A+ B
  76. 76 ) n. ]8 O$ @4 _5 u% v
  77. 77 }" T# ~# M, W/ ~; K0 i4 C
  78. 78
    5 l; s$ H0 S7 G6 _5 _
  79. 79
    , @# G% E3 ?& E5 i9 {6 e* g! K  ]  Z
  80. 80 /*******************************************************************************
    4 k4 D0 C# ^* R
  81. 81 * Function Name  : SOF_Callback / INTR_SOFINTR_Callback
    6 Y6 F  O( M& B  M' a
  82. 82 * Description    :# Q0 A4 b$ |& X: p8 m4 r* i0 E' [6 |
  83. 83 * Input          : None.  i& f. ?% a3 Q  V
  84. 84 * Output         : None., N4 Z7 g; A! \) n
  85. 85 * Return         : None.2 P& N6 O8 t1 T! r/ n
  86. 86 *******************************************************************************/
    . O: d3 l) t" t1 e" q! Z- n! [
  87. 87 void SOF_Callback(void)
    , o. }5 J  u- T, y
  88. 88 {
    * k1 j. @+ m& D$ m( X' f: r2 C- |
  89. 89     uint16_t len = 0;& i% l& }  b# g5 ?8 {
  90. 90
    ) g; ]  e! ^& z9 R' n- E9 M: K
  91. 91     if(bDeviceState == CONFIGURED)  ?# a  d9 @9 S7 @0 t
  92. 92     {
    0 r0 ?) C* e5 g4 P: q. W: M
  93. 93         if (0 == txFlg)9 O) f) ?% G; O( t6 P0 ~
  94. 94         {
    : Y5 B4 }, R; @. N  {
  95. 95             if (FrameCount++ == VCOMPORT_IN_FRAME_INTERVAL)
    , n6 ?! n8 p* A) b& I
  96. 96             {3 P, S1 v7 `( }  o/ E8 Z
  97. 97                 /* Reset the frame counter */: l: j3 G0 s1 P7 Y
  98. 98                 FrameCount = 0;% J& x8 @* N. r% Y' v8 O2 `
  99. 99 0 ]0 V, A8 @; J( X+ n$ E! n. ?# D; d
  100. 100                 /* Check the data to be sent through IN pipe */9 ?- c" K" k! z5 K6 X
  101. 101                 len = USB_TxRead(txBuffter, sizeof(txBuffter));
    6 P( m; D- H  D: }1 c
  102. 102 3 [& J' I2 X% c8 m7 T! O$ w; O( I4 N+ x7 O
  103. 103                 if (len > 0)8 _8 y" W/ z# t+ B" j
  104. 104                 {
    " [. y1 L3 r3 k  z, ?. }3 n  o0 H
  105. 105                     UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);
    : ]3 G1 y# S) X" \# Y7 W/ M
  106. 106                     SetEPTxCount(ENDP1, len);' r7 E# P9 ]' H5 X3 M; r4 {* N
  107. 107                     SetEPTxValid(ENDP1);
    3 y/ U9 |: |6 h, Y
  108. 108
    ! Y/ \6 W+ Z1 y$ S4 R8 h
  109. 109                     txFlg = 1;+ [; q% N/ a  |9 }
  110. 110                 }
    ' z% m+ G  W2 ^; F
  111. 111             }6 v, z: U/ b' d8 q  H
  112. 112         }4 g- r% W8 g2 x; f; m" E
  113. 113     }  
    ! ^" z. V$ D' n: X
  114. 114 }
    3 e& k" r8 _/ }. S5 Z0 H9 _
  115. 115 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码

& b! p. W  l9 ]+ G* y3 Y) Q; N4 c5 H+ u0 d0 [/ ~; ?, _
这里讲下大概意思,函数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也一起存放在上文章开始的链接中。

  B. q7 w! Q0 o9 E
赞 收藏 评论0 发布时间:2022-1-13 21:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版