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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 16:43
1、配置时钟
6 _5 X4 _4 T& Y$ Y  ~, C/ a  E& q' ?+ T  T$ ~& k+ q3 W
, b: v' Q, b% Z: {: A9 o
& R: _( d2 p( t( u
2、开启USB: I: |" u8 I4 g, E1 L

+ b& \: y/ t7 ], z& y- c, A6 I) M
UCX2@5]84KU3W[76%RHOVCU.png
) N( S* o; ?6 Y+ F; y* U1 P: Q, }1 G
3、开启USB设备:虚拟串口
$ A, d. ~$ P" E% h4 l1 n
6 f% u0 Y; x$ o" M
I$UEK76OJ(2AC73PZ8H8.png 1 a3 e- U! {& f; }' p8 u# c

( g* f) c6 A3 {  {4、生成工程8 q6 I9 m! N* R, V  f, G
1 c& L8 m+ l% E; T6 `4 g' j
K[HLH9IHFYCL7WP4S6TH]60.png 5 s0 k; s1 w+ C) `3 }$ G9 A
- U( C# z3 P) A6 ]; P
}LV9[7`$L8SX0R~YI%$L_J2.png
% M% {) e+ b8 P& @$ o6 Z
1 C) @% s" a- T( `7 X5、修改代码实现回环收发数据测试. g7 R+ I  x' q. ]: G
在usbd_cdc_if.c文件中新定义一个结构体:1 j; g; x6 X2 ?% z
$ ~, \1 _6 B1 V3 [! f
  1. USBD_CDC_LineCodingTypeDef USBD_CDC_LineCoding =: F. a4 M; R& N8 w
  2. {
    : W& b0 V& f% `* \1 I/ f  O- W
  3.         115200,      // 默认波特率: L1 w) H4 W7 n" H# V
  4.         0X00,        // 1位停止位
    ' w& C+ U: d- z8 s$ e1 ^1 O
  5.         0X00,        // 无奇偶校" r/ @% C9 R1 e
  6.         0X08,        // 无流控,8bit数据位# r1 I% `7 Q3 B5 N7 W  g1 z
  7. };
复制代码
2 `* r+ I4 R) C$ Y
找到CDC_Control_FS函数,找到CDC_SET_LINE_CODING和CDC_GET_LINE_CODING分支,添加以下代码:
! W2 f$ F1 g2 [0 ]0 @6 z$ T1 v1 k(CDC_SET_LINE_CODING:你在用串口助手选择波特率时候,STM32就会调用这个分支进行修改USB波特率)
, r1 C$ [6 d1 L) ^. |(CDC_GET_LINE_CODING:获取STM32的USB波特率)! M) O8 S+ Y8 k. O
+ s; o% T5 x' ^3 ]1 ^5 [2 \
  1.     case CDC_SET_LINE_CODING:( H, _( n0 a. C  H+ k( [: d
  2.             USBD_CDC_LineCoding.bitrate = (pbuf[3] << 24) | (pbuf[2] << 16) | (pbuf[1] << 8) | pbuf[0];
    - }- X( m, e/ R0 O
  3.             USBD_CDC_LineCoding.format = pbuf[4];
    6 W, I0 U. r# N, E% V
  4.             USBD_CDC_LineCoding.paritytype = pbuf[5];0 l8 v/ _- m' Q- e, k  f# Y
  5.             USBD_CDC_LineCoding.datatype = pbuf[6];  Y9 T# r/ o& d% k. _
  6.     break;5 }5 Z5 F: j2 A3 }: e9 F, D
  7. 7 h% F4 }! N1 Z% e0 Q2 q5 F) W6 H
  8.     case CDC_GET_LINE_CODING:
      ~, [6 ]+ j7 C+ \
  9.             pbuf[0] = (uint8_t)(USBD_CDC_LineCoding.bitrate);! N6 q' [4 |" `1 @
  10.             pbuf[1] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 8);% h+ a! w# f7 N7 {( \# u! E4 K8 l' f. {
  11.             pbuf[2] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 16);6 h; I: e9 \) ?$ z$ `
  12.             pbuf[3] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 24);! F( a+ `$ d8 A# H8 |4 T
  13.             pbuf[4] = USBD_CDC_LineCoding.format;
    9 }5 C. l# a) I) }* ~! \2 c1 J4 ]
  14.             pbuf[5] = USBD_CDC_LineCoding.paritytype;$ Y! `( t' L! d+ g" M' U
  15.             pbuf[6] = USBD_CDC_LineCoding.datatype;
    8 p" {1 u" W  R" m8 {' E, N
  16.     break;
复制代码
: i8 z" c+ {6 E9 k$ ?5 h
8 E+ \$ M9 G, a, F
如下图所示:. J2 D0 ^$ l' W8 R3 V0 b

! P# v+ B& {7 ^2 O- n T)H0BG43H6K~UPAIF}J9427.png
& x3 o3 v; n9 @' S. B& v2 b% w& T0 y- w& ~( f8 Z7 T9 U& u6 C
找到CDC_Receive_FS函数,这个函数如果USB虚拟串口数据收到就会被调用,我们在这个函数中将收到的数据在发回去,只需要添加CDC_Transmit_FS(Buf, *Len);这一句即可,如下图:# s7 U/ j4 Z" @' j; x5 o5 @$ B

/ n0 T" a9 Q# t: P6 J SE7I_1J@RK6T)`VW]S])9[4.png ! k; S; Z( r3 e0 |/ b& t

' {. i/ m1 x% L( c% U) y8 T2 D然后编译工程并下载,接上USB之后,设备管理器COM出现一个新的端口:5 O3 ]2 F6 _  M( r; H4 P% g2 @
* _' F! ^7 Y6 p5 _5 C! }: C
BFQ4_%XA00@)UKV%VEYN6EI.png 5 B, @2 I% b/ i+ |+ C3 s% y) _+ j

/ p( _3 ^& u+ [4 s, U+ R我们使用串口调试助手给它发数据:
+ B; j, Y0 g7 p. m$ I5 u& U# M% n: {0 D' r* f
RPIRUN@UGV1QJJ_K[@3MXJJ.png / `7 D, B! H4 p& D
9 l2 F; T! s4 }# z" q
6、实现USB转串口功能% N/ I8 ?& g/ e: X; }0 \
发数据流程:串口调试助手发送数据->STM32的USB数据接收->STM32转发到串口3
3 k. t4 n) w+ y收数据流程:STM32的串口3收到数据->转发到USB->STM32的USB发送到串口调试助手/ z: H* s* q# d* W! B6 t

, s4 n2 f9 I/ b6 e4 x: V8 x8 x第一步先在这里加入串口3的初始化操作:! |: Q- Y: i$ x. `- a
$ b# d" k$ D8 X* C( g+ e+ Y; S
K6[8}~]R%6HJKW$FW[Q]X9I.png
- G/ j+ M# o( V! Q+ g* ]
8 @/ P+ }) Y& z贴一下串口3的初始化代码,这里我用到了队列,因为实际测试发现串口3接收数据量比较大的话,那么转发到USB虚拟串口的时候会丢数据,所以这里采用了缓存队列,当串口接收到的数据到达一定数据量之后才做一次转发到USB的操作,并且开启了空闲中断,作用是转发最后一包数据:: a# L% {5 d" b4 g8 Q
* q9 ~* U" H% b2 ]& @) r, G& A
关于队列的使用可以查看我的另一篇博客:C/C++语言实现的一个缓存队列
' v5 V$ {% ?* |1 R& L4 W0 h) |3 e' |: j" }& P
  1. /*
    : g8 U- \. Z! t# D4 q* V
  2. * myusart.c
    2 O* K: m0 [9 \) ^- I) h
  3. *  b5 I. ~+ m/ Z  _# a
  4. *  Created on: Mar 22, 2021
    3 K- ?4 Q' B! @
  5. *      Author: hello
    9 B' {" }' l* o" {% i4 h- Q9 s% }
  6. */0 t" S7 `" q4 o1 b
  7. #include "myusart.h"
    1 }# R. I8 U) C1 u7 h
  8. #include "myqueue.h"; @5 v7 Q8 M1 O  E: H) S' ?
  9. 8 c) W5 F: A. u$ x8 m8 [4 j9 s
  10. // 队列大小,定义为USB_CDC的发送包大小
    ! x( m/ _  K: [
  11. #define QUEUE_SIZE APP_TX_DATA_SIZE% M5 U2 d! j4 N
  12. 0 g" _: {. m! @. `' B, T/ @
  13. // 队列数据空间。请使用宏QALIGN4,目的是为了根据队列大小计算实际需要的队列存储空间大小并对齐4字节; E$ e2 M0 I% [' Q( W( f
  14. uint8_t QueueBuffer[QALIGN4(QUEUE_SIZE)];
    ; j0 _4 o2 V0 [# g

  15. 9 @; l( n6 v# R+ v* ~( w& p
  16. // 队列句柄
    ; b# h+ X8 Q$ o6 U- p
  17. Queue Uart3QueueHandle = {0};
    $ p6 S$ }2 b: B  G9 ]' q/ g
  18. #define UART3_QUEUE_Handle (&Uart3QueueHandle)
    0 X( L" i4 t: v1 ~+ ]: g

  19. 8 }$ A% C0 R& C. [
  20. // 串口转发到USB的缓冲,定义为USB包的一半大小
    + c4 z; g/ K% j$ D) T% H
  21. static uint8_t buffer[APP_RX_DATA_SIZE >> 1];0 P; p6 E" A8 u/ w) @2 z: u3 `
  22. - R9 c; Z/ y0 d% g
  23. void UART3_Init(const USBD_CDC_LineCodingTypeDef *USBD_CDC_LineCoding)
      A: c' L2 t, u( Y( p: _
  24. {  f  C2 F7 F; w0 h
  25.         __HAL_UART_DISABLE_IT(&huart3, UART_IT_RXNE);
    : k! c0 }: s' B, p
  26. . O+ s2 E" f9 G
  27.         __HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE);
    0 E& V% x, D1 B

  28. ! m: f5 D! o' e7 A1 X+ C
  29.         HAL_UART_DeInit(&huart3);
    ; {3 [" r' q, {1 y5 B, G

  30. & x9 |7 m9 p9 p: h( U# n* p
  31.         huart3.Instance = USART3;9 y: ^$ G# ]7 I9 l! \, ~3 [3 |
  32.         huart3.Init.BaudRate = USBD_CDC_LineCoding->bitrate;
    1 z7 Y* M$ p% S/ ]. f" e* f! R
  33.         huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    , z. q5 q' ^! a/ \
  34.         huart3.Init.Mode = UART_MODE_TX_RX;! x/ f) h7 _1 K& J+ ?
  35.         huart3.Init.OverSampling = UART_OVERSAMPLING_16;
    # z4 \- }! S1 j/ {3 Y6 O

  36. ! n/ o9 V  i# m/ _) h  D1 \9 [' }; P
  37.         switch (USBD_CDC_LineCoding->paritytype)
    ) ]% B; J! {* _, V
  38.         {! {6 |3 l( A4 k! Y2 n
  39.         case 0:
    0 r- z' B( Z- J* z' q8 r! L
  40.                 huart3.Init.Parity = UART_PARITY_NONE;
    + \5 T6 \. u* Y7 n3 R
  41.                 break;
    9 a! O0 G2 j7 k, q+ q
  42.         case 1:
    # G7 X5 ^1 s( v* B) _3 z
  43.                 huart3.Init.Parity = UART_PARITY_ODD;8 {: ^, z1 R  T/ ~
  44.                 break;; S* F" b/ h9 x( q: w
  45.         case 2:( g8 U: M+ ~& h: R& @; h9 [8 a. E
  46.                 huart3.Init.Parity = UART_PARITY_EVEN;( \" g1 v% Y: i* S4 }3 u' a
  47.                 break;
    * h" _2 w2 g6 H7 I2 z) V: `5 V
  48.         default:+ G7 Q( f/ H+ }( h
  49.                 huart3.Init.Parity = UART_PARITY_NONE;
    * M2 C2 k: j. p2 M( I, b. e
  50.                 break;
    : r$ {$ j( D0 s. G5 A, j5 K# H
  51.         }8 Y6 }* ^6 Y; D' O7 Z

  52. ! A- q( R9 q* I3 b6 k
  53.         switch (USBD_CDC_LineCoding->datatype)( f9 A. D* l" l% M- q
  54.         {
    , ?1 y* m2 S/ B9 `8 V2 a9 j4 _
  55.         case 0x07:
    ) a9 \/ \9 x' [- n2 U( C' \' `2 Y. M
  56.                 huart3.Init.WordLength = UART_WORDLENGTH_8B;/ j& G/ \0 d9 F( e
  57.                 break;
    7 ]! L" j* z- O7 z* ^
  58.         case 0x08:# g0 V0 X& V7 S6 c) h
  59.                 if (huart3.Init.Parity == UART_PARITY_NONE)) c0 L, r& U) \# t
  60.                 {! E3 {2 m& B% `0 [& d
  61.                         huart3.Init.WordLength = UART_WORDLENGTH_8B;% {, Y/ U5 n! }
  62.                 }
    2 s0 @- v0 x) E7 `+ ~; ]
  63.                 else: B0 O; l' Y: J9 W
  64.                 {
    ! G; E. ?/ M* ?
  65.                         huart3.Init.WordLength = UART_WORDLENGTH_9B;, a) j9 Y7 E7 h' x) ]
  66.                 }
    4 ~" \8 u; }& F$ J2 V0 t
  67.                 break;
    ! [9 E+ r! |& F5 P
  68.         default:# ?- _# }: @  E) i  z0 i7 ?
  69.                 huart3.Init.WordLength = UART_WORDLENGTH_8B;
    2 K! {6 Y6 ^% |) Z* t
  70.                 break;% a+ x; ?) {/ L: n
  71.         }
    6 I. D" H! ?3 t0 Y+ }, h- @

  72. ( F% D: m5 B  D
  73.         switch (USBD_CDC_LineCoding->format)2 k9 e2 W" \4 f- g9 @; j
  74.         {
    8 q. w2 q3 [7 G
  75.         case 0:
    # r) |* J( `1 ?9 j
  76.                 huart3.Init.StopBits = UART_STOPBITS_1;
    7 b, E* y9 g8 [0 \; y
  77.                 break;
    8 y4 n% l" h& m  D
  78.         case 2:
    7 e! [  U! _' F3 m$ V( @
  79.                 huart3.Init.StopBits = UART_STOPBITS_2;& E& c6 R: }$ O* L2 o% p2 a* R! w. k
  80.                 break;
    6 J$ @- g& d" g
  81.         default:% r7 `: `7 Y: ?7 U  k
  82.                 huart3.Init.StopBits = UART_STOPBITS_1;
    # R6 a: B7 O. j
  83.                 break;
    $ j* O$ I/ f! g4 n/ t
  84.         }
    ( O* e5 N" ~$ n- d, c4 K
  85.   C# l& c/ D" S! S6 l- p$ k
  86.         HAL_UART_Init(&huart3);
    " \# d# A& s" ~6 V
  87. 7 A' q3 t; _; f4 s& K( Z0 y! z
  88.         Queue_Init(UART3_QUEUE_Handle, QUEUE_SIZE, QueueBuffer);
    3 J9 L! F! L" P9 E4 s
  89. & a" ^0 Y# \6 N6 l; |0 F# @
  90.         __HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE);6 O  e7 y3 K4 ^! U

  91. ' Z) l+ O& }! ]" ^9 e0 `1 ^
  92.         __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
    - d/ D( y# s) H" x
  93. }
    % W/ Y! l1 t) E5 `7 ?

  94. 1 `3 M2 J; ^: s' R3 t
  95. void USART3_IRQHandler(void)
    . D5 f7 {, ~3 F7 `: @( q2 g5 \
  96. {
    ) U- @2 v. E; j
  97.         static uint32_t nsent = 0;3 T# l+ j% `. A7 g/ z
  98.         static uint8_t dat = 0;) K1 Q6 Z( S7 }0 [. W0 R* T
  99. ' t$ U3 W' E5 s$ N3 v& @
  100.         if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_RXNE) != RESET)
    / d! F+ E4 {: z6 R8 p- G* y
  101.         {7 R4 _" f4 N2 j3 s
  102.                 __HAL_UART_CLEAR_FLAG(&huart3, UART_FLAG_RXNE);
    / B. }, P8 h; H5 g
  103.                 dat = huart3.Instance->DR & 0XFF;
    ; A9 R% {  g3 b
  104.                 Queue_PutByte(UART3_QUEUE_Handle, dat);                     // 入队一个字节的数据
    - C" ^# y. ?3 _
  105.                 if (Queue_GetUsed(UART3_QUEUE_Handle) >= sizeof(buffer))
    3 _3 Y' d; L9 D: [% D; a1 M
  106.                 {0 ?7 b0 Q- ]3 z/ t( W6 k
  107.                         Queue_Read(UART3_QUEUE_Handle, buffer, sizeof(buffer));
    " D: [/ T. t% e: }
  108.                         CDC_Transmit_FS(buffer, sizeof(buffer));                // 转发到USB
    1 M% v# h( E" i
  109.                 }
    5 L* g8 E2 e) X( L6 i! R5 t* z$ |
  110.         }
      b4 H7 l* I1 e. v' T+ Q1 E
  111. + N2 U! ~) c2 E3 W
  112.         if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET)
    9 Y! Y% K, b( C6 P% \5 D  {: ~
  113.         {
    - O1 `0 h" T& v$ |4 b/ i5 R
  114.                 nsent = Queue_GetUsed(UART3_QUEUE_Handle);
    . }4 r4 J  v) e8 ]  i
  115.                 if (nsent != 0)' @- o- [6 `0 b* y
  116.                 {
    , o9 \8 R# {& e
  117.                         Queue_Read(UART3_QUEUE_Handle, buffer, nsent);
    4 U( M+ n$ O3 W3 V/ k
  118.                         CDC_Transmit_FS(buffer, nsent);               // 转发到USB
    3 [" L4 b7 J) B  t1 I. }
  119.                 }+ o! F7 v) H2 H, X+ F" b( q
  120.                 __HAL_UART_CLEAR_IDLEFLAG(&huart3);
    * J) Z- a  `+ b/ T3 p" c. N+ j
  121.         }' @9 G/ B& T3 h5 [! }" z
  122. }
    + s% Y. E, g7 z. m
  123. - d2 X+ u& s: W7 a& p# G- n
  124. void UART3_SendData(const void *buf, uint32_t len)0 p4 K& A5 z  A/ n9 B) {
  125. {- E5 e6 j0 X; v% \% ]4 V( N3 _
  126.         const uint8_t *p = (const uint8_t*) buf;. j! s) q4 m0 p: A# [
  127.         while (len--)
    3 m9 p3 `9 H/ P5 M
  128.         {6 e9 a2 Z, b  P3 f* x
  129.                 while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TXE) != SET);
    * Z2 b' {( X1 g3 v+ k9 G0 E: U) N
  130.                 huart3.Instance->DR = (uint8_t) (*p++ & 0XFF);
    * W6 `2 G! z. I4 D7 D
  131.                 while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TC) != SET);5 I! J- G, b6 i) r1 s( l7 d
  132.         }
    6 r$ m/ f3 R! h4 {
  133. }- L3 z* ^6 {7 f1 J7 @
  134. 0 x# @* r, p7 _, ]- E5 m2 A
  135. //#ifdef __GNUC__
    & J# o9 u7 w9 P, Z
  136. //#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    ( `; w# q' w# C
  137. //#else8 e: {; P' l1 q# k8 D! f+ r( y
  138. //#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    7 j1 G& k# X, n5 O  u+ x1 n( @
  139. //#endif
    9 I- f5 v& A& ~
  140. //PUTCHAR_PROTOTYPE
    2 G/ b* W9 b; \, e! B$ _) A4 [
  141. //{
    # t* f) x6 J: c4 b" `
  142. //        while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TXE) != SET);
    8 r9 f: e" p& {0 O9 V
  143. //        huart3.Instance->DR = (uint8_t) (ch & 0XFF);, E' \  X) M; S& o  y" ~9 _
  144. //        while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TC) != SET);+ j; ?0 r0 j: w1 q7 m$ N& j
  145. //        return ch;
      _8 P5 T8 U- X( H8 z
  146. //}
    / B( f% @, b' p- u5 `5 I8 n
复制代码
" S8 g# n: m0 A& n3 ], W
然后在添加USB转发到串口的操作:
- p/ m  {% H8 a- q' T7 E
7 j1 o4 Y9 \! y7 n" n7 u3 G% E8 O6 _9 a0 J9 z& u3 m/ Z

/ R  `9 x, n4 T1 }) l这样就实现了一个类似于USB转TTL模块的功能!
9 ]# s1 Z7 ^; z
0 U7 e7 q9 D6 o( y/ |. h& p' n
& h, I1 D% i7 M) R
# j( ?" t7 {  l  D+ D
EYYRTTQR59WIH1(2H8[88A2.png
赞 收藏 评论0 发布时间:2022-4-10 16:43

举报

0个回答

所属标签

相似技术帖

官网相关资源

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