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

【经验分享】快速实现STM32 USB虚拟串口功能(回环测试、USB转TTL的功能)

[复制链接]
STMCU小助手 发布时间:2022-4-10 16:43
1、配置时钟
! l, E# d5 m% O  J$ Z+ f0 Y  p( b" d; }
, O5 z8 E6 h0 Z( M
$ B1 j- v  R: V1 q8 s( c* @6 m( R
2、开启USB
6 k' d8 x3 Q8 e/ ^6 k  m& N$ F! G! l; P/ L9 t, }) Q$ b
UCX2@5]84KU3W[76%RHOVCU.png
0 c% t7 M1 V1 e' T( q. `9 r' R% s, ~* t! j8 r4 V
3、开启USB设备:虚拟串口
" u/ k' t, b# g6 l7 b9 K5 |% W, ^1 V  H: [7 x$ E3 m
I$UEK76OJ(2AC73PZ8H8.png $ ]& ~. V, E$ h2 G+ c, H% R! P

# Q3 G. K4 \/ Y) i" \  Q' ]4、生成工程4 O8 [; L- U  N7 H* W
7 f. z* X) N% O
K[HLH9IHFYCL7WP4S6TH]60.png
3 l) k/ X0 @0 Q0 q5 N
# }; f) D9 Z% Y& B5 B& O; q }LV9[7`$L8SX0R~YI%$L_J2.png
2 y. J7 `2 H. F0 M8 S5 ]- x
) h& `+ q4 i+ x5、修改代码实现回环收发数据测试
. Z/ x* \' L5 i2 J: R0 G, c; y# w2 n0 b在usbd_cdc_if.c文件中新定义一个结构体:0 K/ a) r6 {; _9 w5 H5 n

6 ?/ \8 V% e' r3 ^2 ]( u
  1. USBD_CDC_LineCodingTypeDef USBD_CDC_LineCoding =+ u. _( S! P7 u) |
  2. {6 G/ v3 {- N# H; I  U, D
  3.         115200,      // 默认波特率
    1 ~. ~" a+ }$ L
  4.         0X00,        // 1位停止位. D/ r1 X" i- }) \# L0 G
  5.         0X00,        // 无奇偶校
    ( J/ j$ |$ Q# Z% a9 F# y& l* Y4 a
  6.         0X08,        // 无流控,8bit数据位
    - s! J0 L1 V1 }7 @0 W& M$ R% q
  7. };
复制代码

( G  C0 R! l/ m* l, v" m* Y9 i找到CDC_Control_FS函数,找到CDC_SET_LINE_CODING和CDC_GET_LINE_CODING分支,添加以下代码:
) y, E6 y8 y0 J' H0 r(CDC_SET_LINE_CODING:你在用串口助手选择波特率时候,STM32就会调用这个分支进行修改USB波特率)
$ |. X0 \7 m, k, t/ Z& c(CDC_GET_LINE_CODING:获取STM32的USB波特率)
4 q$ ?: t8 `& W% J5 i2 _5 Y
: ?" \% S" g. v5 E9 z# u5 ^" m, Y
  1.     case CDC_SET_LINE_CODING:/ @. c6 u5 S6 x1 O1 f  J7 b1 N: O
  2.             USBD_CDC_LineCoding.bitrate = (pbuf[3] << 24) | (pbuf[2] << 16) | (pbuf[1] << 8) | pbuf[0];" R) o% n4 H' |8 K7 w- C6 h
  3.             USBD_CDC_LineCoding.format = pbuf[4];
    " ]- @( `' g2 ]) C' P. @- O( O4 p
  4.             USBD_CDC_LineCoding.paritytype = pbuf[5];
    * }# t* `. J+ L2 V, j7 {' w
  5.             USBD_CDC_LineCoding.datatype = pbuf[6];
    * j  |! Y7 v0 o( ~8 \1 U
  6.     break;
    ; e6 S+ d* t) Q' M. J& Z  A
  7.   O' D8 [( S7 {- n. w; v
  8.     case CDC_GET_LINE_CODING:, |3 b" F. x0 I
  9.             pbuf[0] = (uint8_t)(USBD_CDC_LineCoding.bitrate);/ L0 b. e7 V" O& l  L% |
  10.             pbuf[1] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 8);& m/ U# O" ^) X; S4 J
  11.             pbuf[2] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 16);& z7 b7 p1 @  O  V% R6 F
  12.             pbuf[3] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 24);% ]6 ?3 a$ E7 Z  G- G
  13.             pbuf[4] = USBD_CDC_LineCoding.format;
    3 K# ]/ N3 n8 l( p  |; ?
  14.             pbuf[5] = USBD_CDC_LineCoding.paritytype;
    8 I0 r0 J% J! p: z
  15.             pbuf[6] = USBD_CDC_LineCoding.datatype;
    ( P; Q( A; x1 p& }
  16.     break;
复制代码

9 F; ?9 E. |+ p* j6 Z) C; v2 R9 l, H
: O, f  t& t0 M. J8 z如下图所示:
5 E5 A9 Y4 t6 ~& r( j" j9 g/ e9 s) |! ?) f: f
T)H0BG43H6K~UPAIF}J9427.png
4 \  F, U! U- {$ ?7 s- @
& l( @, S. a2 `. q6 j+ S' V; ~2 F找到CDC_Receive_FS函数,这个函数如果USB虚拟串口数据收到就会被调用,我们在这个函数中将收到的数据在发回去,只需要添加CDC_Transmit_FS(Buf, *Len);这一句即可,如下图:' |: i* @/ n6 {) U# I4 R$ \* R2 |# t

2 u+ g. I* x$ o- S* R SE7I_1J@RK6T)`VW]S])9[4.png 3 Z$ ^% l# Y0 Y2 P1 s  ?

4 U! v. S& k; U3 ~: r: P& A然后编译工程并下载,接上USB之后,设备管理器COM出现一个新的端口:
1 E7 @5 u6 x$ h& ^! ^' s6 }" ]* r  W5 c1 S: M3 r) r
BFQ4_%XA00@)UKV%VEYN6EI.png
! y7 T; H# |' y8 G  Z% a" t7 c6 B( ]0 n$ d% z$ R. n' b* B! i5 T
我们使用串口调试助手给它发数据:; D2 D" t8 V; g

: O. H, f- Z0 z% h; e/ M  f1 ? RPIRUN@UGV1QJJ_K[@3MXJJ.png
8 D$ u9 `6 ~; G' ?& @- K( S8 t$ W4 J. X/ L9 `
6、实现USB转串口功能
: \  A! t5 B3 {% ^# H( d: I发数据流程:串口调试助手发送数据->STM32的USB数据接收->STM32转发到串口3
8 V2 Y! Q+ w0 p# @收数据流程:STM32的串口3收到数据->转发到USB->STM32的USB发送到串口调试助手
; o9 o$ A% m% m5 B- m/ _1 I- F  w  I9 N
第一步先在这里加入串口3的初始化操作:
+ w/ E. D+ b  a2 {: T, x
: N' A/ C" s4 a- j3 h8 g K6[8}~]R%6HJKW$FW[Q]X9I.png 5 |* y" e- u* R: h1 F" R% L8 S

$ R* r8 D- ^! e贴一下串口3的初始化代码,这里我用到了队列,因为实际测试发现串口3接收数据量比较大的话,那么转发到USB虚拟串口的时候会丢数据,所以这里采用了缓存队列,当串口接收到的数据到达一定数据量之后才做一次转发到USB的操作,并且开启了空闲中断,作用是转发最后一包数据:" N7 L: g) p+ J3 _' d' G
' o3 W9 N  ?2 ?; d" S$ \
关于队列的使用可以查看我的另一篇博客:C/C++语言实现的一个缓存队列
3 a! T. ]  w$ Q$ e: R) l, ~4 o% z" ~. g% O# k
  1. /*" d2 n3 h8 c+ Y
  2. * myusart.c
    " \) B+ R" X6 h3 p
  3. *' i4 U& F% l* |: K
  4. *  Created on: Mar 22, 2021
    ' ]8 Y0 Z, n% q: h' X! l) W) J
  5. *      Author: hello; m. f  G# Y$ K+ y
  6. */8 P0 T' x* k9 Q
  7. #include "myusart.h"! G1 @- B* l8 @/ N1 G2 a3 n- K3 b) s
  8. #include "myqueue.h"* {; {# Y, P* i9 }3 M! Z% P% ^
  9. . W* N( C5 i- V8 B9 \7 r6 R' P
  10. // 队列大小,定义为USB_CDC的发送包大小# D6 Z# g: L8 D( m
  11. #define QUEUE_SIZE APP_TX_DATA_SIZE
    8 v' A2 Q) L% f2 }6 S" ^+ l, o
  12. * A5 y% i( t6 }1 J9 T
  13. // 队列数据空间。请使用宏QALIGN4,目的是为了根据队列大小计算实际需要的队列存储空间大小并对齐4字节) b3 j9 B) ]8 s1 I: K" f
  14. uint8_t QueueBuffer[QALIGN4(QUEUE_SIZE)];' n7 l3 b2 z2 l0 }/ m0 k
  15. 9 e  ?1 R1 W7 P% ]
  16. // 队列句柄
    ) u2 }2 ^' D* b: `# a, `
  17. Queue Uart3QueueHandle = {0};( ~1 d* s* }  b' E# J
  18. #define UART3_QUEUE_Handle (&Uart3QueueHandle)
    . d" Y% f* B/ ^" Q: S

  19. ( D* C' j0 {. W* H8 ]2 n+ S+ K
  20. // 串口转发到USB的缓冲,定义为USB包的一半大小" [% i% l; j2 q/ p( Q
  21. static uint8_t buffer[APP_RX_DATA_SIZE >> 1];
    + c4 S0 z; Q; M5 E  \' x% g
  22. ! C3 l6 ?3 O* n% u
  23. void UART3_Init(const USBD_CDC_LineCodingTypeDef *USBD_CDC_LineCoding)4 F7 A, ]) o4 O7 U' z7 u
  24. {0 u9 H) P5 v  |! S% L% s& w
  25.         __HAL_UART_DISABLE_IT(&huart3, UART_IT_RXNE);
    $ L8 l7 r) z% J# D

  26. . Z, F6 m. W! v* B; ^
  27.         __HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE);
    . s0 B8 u3 K  |/ B. m* `( j
  28. ) X& V7 }, U! g8 \& n2 m
  29.         HAL_UART_DeInit(&huart3);+ @; H7 N" s2 }+ }
  30. " `: Q) Y% W8 [" c  y( k' n
  31.         huart3.Instance = USART3;  n' k& \3 G: M$ {
  32.         huart3.Init.BaudRate = USBD_CDC_LineCoding->bitrate;
    5 G$ I; ^, v/ n: J; Z/ K1 g
  33.         huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    % ~( H, }. I7 F/ e8 m% r
  34.         huart3.Init.Mode = UART_MODE_TX_RX;# F3 j8 w+ S- q0 _- @. _0 j/ k  `
  35.         huart3.Init.OverSampling = UART_OVERSAMPLING_16;
    * n9 P1 {; G- T+ g( z
  36. - R6 ]3 y( Z# z' H: H& {
  37.         switch (USBD_CDC_LineCoding->paritytype)
    ( I6 I1 L0 [: W, _
  38.         {
    + s4 N8 [9 n3 T$ _+ p0 s: o
  39.         case 0:
    ; I2 G' g% {/ I$ `
  40.                 huart3.Init.Parity = UART_PARITY_NONE;% x' M& D9 ~6 u( C
  41.                 break;6 M3 I- D. {  K) \" @
  42.         case 1:
    % E4 ]" S% K: j0 r3 V
  43.                 huart3.Init.Parity = UART_PARITY_ODD;. x1 `8 f; B5 }
  44.                 break;7 a% G/ g! d  T* y! _
  45.         case 2:
    ( X6 N; T  U% M- G' j0 y
  46.                 huart3.Init.Parity = UART_PARITY_EVEN;
    9 m4 @( p9 Q6 |9 r
  47.                 break;
    1 e; y+ W5 h: y: y2 T7 t4 l
  48.         default:( m- W8 w" U, }% }3 G! ^8 g* r+ h
  49.                 huart3.Init.Parity = UART_PARITY_NONE;
    % M. P( |% y3 b# c
  50.                 break;/ A7 t# ^/ N) L$ N" i  M, a4 l' O
  51.         }. }6 |2 K% ]+ z7 M" v( }2 R

  52. + L9 z+ G5 [: G0 |
  53.         switch (USBD_CDC_LineCoding->datatype)% J7 a  A, \! J" N( F
  54.         {
    . m  \) j- n: T/ S7 L
  55.         case 0x07:0 s1 H$ y; i9 R0 J- Z6 ~
  56.                 huart3.Init.WordLength = UART_WORDLENGTH_8B;: Y' r/ n$ p2 X: d8 e
  57.                 break;$ ?2 w  v1 y. {; _+ y/ f. g# J
  58.         case 0x08:$ m1 @; O* y/ f0 e$ H( |+ l
  59.                 if (huart3.Init.Parity == UART_PARITY_NONE)2 W* u0 c2 E8 D. _" S$ H
  60.                 {
    4 H' y! w9 x' ^
  61.                         huart3.Init.WordLength = UART_WORDLENGTH_8B;$ {. E( p7 g: M9 X; i6 K% w
  62.                 }
    8 A" K6 Q, F& [5 p
  63.                 else
    % {4 n* b2 D" v$ [/ ^4 }
  64.                 {, v) |6 B1 G4 i5 U0 G' w7 `6 @7 L
  65.                         huart3.Init.WordLength = UART_WORDLENGTH_9B;! Q- [+ W& N1 y5 K! y$ O
  66.                 }1 T; ]7 }$ s, X, p! Y6 [0 l
  67.                 break;6 @/ {& [$ R1 j9 N% e' S/ t
  68.         default:
    ( T- M2 m( _' h/ x
  69.                 huart3.Init.WordLength = UART_WORDLENGTH_8B;
    8 M. @( @4 d0 Q! x- H; l
  70.                 break;
    3 h1 X6 \6 t7 R0 Q3 a( h0 p% a
  71.         }! C! M. }6 M  O, N* h9 U

  72. # ^( `$ \3 T# \- ?) m0 S" x# \
  73.         switch (USBD_CDC_LineCoding->format)6 _% x" D4 m: U" V9 E
  74.         {
    - S& b8 d/ [7 r# D/ d/ b6 k; O
  75.         case 0:
    : O0 e0 f' I& ?. l. w+ w
  76.                 huart3.Init.StopBits = UART_STOPBITS_1;0 `& Q1 e) ]- V# c) n" X7 W) S
  77.                 break;
    ' F* s: }% A: s1 R5 [# Y
  78.         case 2:
    / o: g4 J5 O4 m& D! p2 a' F( |
  79.                 huart3.Init.StopBits = UART_STOPBITS_2;
    ' _1 I8 |+ T+ x0 s' s
  80.                 break;
    1 w) K% [: \8 ?, N/ p9 |4 k7 c
  81.         default:
    ( Y# V, k$ v: X4 s1 v8 Y
  82.                 huart3.Init.StopBits = UART_STOPBITS_1;
    / \- v' {& D2 E
  83.                 break;
    ( d' J( r! [$ H! }# {* G3 i, m) L
  84.         }$ j3 E% X. ~: A; e  }
  85. " n) P' M: }( u  [: i. {
  86.         HAL_UART_Init(&huart3);
    8 r( D9 ?. R" @  D2 n/ @) ]

  87. ; ]4 m# Z2 Q  G
  88.         Queue_Init(UART3_QUEUE_Handle, QUEUE_SIZE, QueueBuffer);
    " [; @: Z8 L$ x4 t  m

  89. 0 `% v8 r# h& N+ S2 u& H5 r& h
  90.         __HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE);* W7 M: T4 c, U9 S0 B: b
  91. % e2 V+ _( Y7 n, ?6 Y: n% z
  92.         __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);  e7 h' N$ g7 M+ _2 z8 ~2 T
  93. }
    6 z* n+ l+ L/ b6 |( H0 o9 U

  94. * r/ ^. J/ n8 Z) |* h' e' B) Z
  95. void USART3_IRQHandler(void)4 C' D3 h, Q% R- |
  96. {
    7 S1 }7 J, K) z; {
  97.         static uint32_t nsent = 0;
    " ?0 @2 K  V0 n% E
  98.         static uint8_t dat = 0;4 t- H( B3 I/ h

  99. / z0 L! B/ W  v8 N
  100.         if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_RXNE) != RESET)
    $ @9 R4 S2 J' w* g+ t$ [# I
  101.         {
    % V: s0 f& B& k3 A7 \) |3 v
  102.                 __HAL_UART_CLEAR_FLAG(&huart3, UART_FLAG_RXNE);
    3 ^. Z7 U" Y7 d9 R0 `/ |6 p, ~5 X
  103.                 dat = huart3.Instance->DR & 0XFF;' ~/ Y2 I* g* e1 q
  104.                 Queue_PutByte(UART3_QUEUE_Handle, dat);                     // 入队一个字节的数据
    & Z. y; }+ ]3 r. J- s" M3 ?/ h& l" l# h
  105.                 if (Queue_GetUsed(UART3_QUEUE_Handle) >= sizeof(buffer))
    - Z" y% [- L+ N0 p3 J' O/ ]# _7 ^
  106.                 {
    7 y1 e' ]4 t3 E
  107.                         Queue_Read(UART3_QUEUE_Handle, buffer, sizeof(buffer));
    1 i, a  f- b6 a2 J" v  V2 A
  108.                         CDC_Transmit_FS(buffer, sizeof(buffer));                // 转发到USB# s5 H) c) K' @! I& a0 D
  109.                 }& U- T% n6 t* N" y) A: S
  110.         }
    ' Y8 D) V) V. J2 @: K& D8 `4 ]
  111. 0 r) `9 R" u0 D, k* \
  112.         if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET)
    + B! c9 a4 r6 M9 |! s! G
  113.         {1 d( @8 C7 Z, U- F
  114.                 nsent = Queue_GetUsed(UART3_QUEUE_Handle);& V5 P8 e- H8 o: j+ }% i+ c, P
  115.                 if (nsent != 0)3 \" m/ u& {: o- U2 A8 K+ D& z
  116.                 {# d! j% y% y! b% _7 M" |; Y! L
  117.                         Queue_Read(UART3_QUEUE_Handle, buffer, nsent);
    % {2 e( @5 F" m  W- g6 Q
  118.                         CDC_Transmit_FS(buffer, nsent);               // 转发到USB
    ' ~6 P( {5 G' |1 x+ G
  119.                 }
    8 Z7 Q1 _# u8 T$ [% M
  120.                 __HAL_UART_CLEAR_IDLEFLAG(&huart3);$ Z* s0 `  Y  o. a3 ~
  121.         }. U# r4 I( l4 @0 [
  122. }
    / I; @7 d4 n7 m
  123. 3 N6 v( o  ~  A
  124. void UART3_SendData(const void *buf, uint32_t len)
    / T* \! c3 ?! t
  125. {
    % Z4 b9 A/ v  W. t) W
  126.         const uint8_t *p = (const uint8_t*) buf;- D* _$ r3 [- T2 s$ D
  127.         while (len--)$ b) p$ W+ G" q
  128.         {
    / P% V  ?- X8 X& q3 x& D& g0 O
  129.                 while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TXE) != SET);+ ]8 K9 P6 F- i, z7 K0 a+ D
  130.                 huart3.Instance->DR = (uint8_t) (*p++ & 0XFF);
    ! o2 u# g' q/ e: \" T- V+ A
  131.                 while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TC) != SET);$ g- B& Y  o/ ^" P/ p
  132.         }
    6 Z, t% S; R1 n  q- d! ]: D
  133. }: p8 x6 I( g3 K0 R! n0 g8 F  h
  134. - o# }- y. @1 ?3 H; o
  135. //#ifdef __GNUC__* w; @! F+ H( v# J+ p- e- n
  136. //#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    - N# x4 f& a! \1 h$ U: `: H0 W
  137. //#else
    9 i. s# c+ i8 |
  138. //#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)5 X7 A1 c8 M: J+ `
  139. //#endif2 z* j; f6 e5 w
  140. //PUTCHAR_PROTOTYPE
    ; P, h, F+ P/ ~1 t! h- R) E4 \) |
  141. //{
    ) [4 _4 ^" E1 f4 f& s
  142. //        while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TXE) != SET);2 X( N9 w% i# h+ M9 r: B# T) a; ?
  143. //        huart3.Instance->DR = (uint8_t) (ch & 0XFF);
    / e+ F% d( n' J  b4 D
  144. //        while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TC) != SET);5 S7 E: b/ d  G
  145. //        return ch;1 r+ b" O2 x/ a- c6 x  v
  146. //}; M  S, h" |+ }9 x  Z
复制代码

7 \/ V) K1 e, g然后在添加USB转发到串口的操作:. k6 c1 k: W8 r3 I
3 S: a- S: E( _& y( Z0 R
" l- o1 d$ U/ \5 e% @/ v- n! r+ ^

0 T: [; z0 Y: I; u/ w& Q, F这样就实现了一个类似于USB转TTL模块的功能!
/ a# l1 }8 s2 b# E4 {
9 O; a$ A' r0 K: x. a' o: C* }5 b2 |4 J' u- f" Y  F
8 e+ v0 I7 g8 Q. |6 G% O
# ^" k( B9 A( q. _& B! j
EYYRTTQR59WIH1(2H8[88A2.png
收藏 评论0 发布时间:2022-4-10 16:43

举报

0个回答

所属标签

相似分享

官网相关资源

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