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

【STM32U3评测】实现双通道串口通信系统

[复制链接]
donatello1996 发布时间:2025-5-23 17:55
     拿到了nucleo-U385开发板,在KEIL环境下编程,需要下载CubeU3支持包,在ST官网即可下载,并且在CubeU3支持包内还有KEIL环境所需要的pack安装包,这个应该是最近才做的一个方便开发者开发的一个机制:
+ B+ x6 c. c, J& G" r
1.JPG
! Q( a* c( f' d; @我直接用点灯的例程来改串口例程,方便省事:& H  J* s  X2 L8 f
2.JPG
( F5 N! W- y$ m5 L1 c2 M整理好的例程结构如下:
6 s; p# F( F% h/ l1 F6 t- Y% l
3.JPG
; Y# {5 w& g4 e# H, ]根据原理图可以得知,开发板的STLINKV3 VCP连接的串口是UART1,即PA9 PA10,可以直接与电脑的串口助手进行通信,另外开发板上还有PA2 PA3引脚,这个引脚被复用为LPUART1:& |+ w5 f- O  i# Y, {
4.JPG 5.JPG . t$ q" b! T" ~) y! R" e: {) S
我这个帖子就实现UART1和LPUART1的双通道串口通信,其中把LPUART1的接收功能打开,使用空闲中断和DMA进行接收,先看看UART1的初始化代码:
  1. <font face="微软雅黑" size="5">UART_HandleTypeDef huart1;( b0 j/ E* r7 i# E2 Q) a* ]( j

  2. 9 @: I) e% M' Q/ [
  3. int fputc(int ch , FILE *f)
    ( n$ _. H: o/ z; W2 b$ e7 G
  4. {$ t1 |% f( o- E4 i
  5.     while ((USART1->ISR & 0X40) == 0);
    * e! _4 ]+ z9 s0 z
  6.   USART1->TDR = (uint8_t)ch;
    1 e* Y, z; d) e# {+ F4 I8 i
  7.     return ch;- i& [! E. K) f" _+ f) H
  8. }# R; h* j, _- l1 X9 [" p
  9. $ P! z- @0 C8 s2 G, I' o
  10. void UART1_Init(uint32_t baud)) d, `! Q0 f( t: X# \" Y
  11. {
    / o8 R7 L& h) v
  12.     GPIO_InitTypeDef GPIO_InitStruct = {0};
    - \! z; M$ P. }- P. f, j
  13.     RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    & @5 b7 s# k# z/ M, B; h4 f
  14. " V6 \+ @8 r- x
  15.     __HAL_RCC_USART1_CLK_ENABLE();
    : w) M! p/ _8 ~! |6 z6 A- s- `: n9 X; W
  16.     __HAL_RCC_GPIOA_CLK_ENABLE();
    ) S+ B2 r* m: }. v# p

  17. 0 ^$ X5 }8 I) l) b8 P
  18.     PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;0 A. {- A  O6 g3 a7 w) k1 i
  19.     PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
    ! Q  V: v; W9 c  L& D' l7 e
  20.     HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);: Y& ?0 e% U0 @6 n6 ^* _; J

  21. , X0 z6 f* D, \/ F3 ^  m
  22.     GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
    5 [+ J% a6 w! g7 R! X6 j
  23.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;* ~4 R) {* H! d/ b. [# }
  24.     GPIO_InitStruct.Pull = GPIO_PULLUP;
    + c9 @  }8 }3 `8 S0 V1 Y
  25.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;/ N9 o' I4 S7 W# V# e: ]7 }! \
  26.     GPIO_InitStruct.Alternate = GPIO_AF7_USART1;6 h5 m% A' r0 V% ?& K* b+ j: F, {
  27.     HAL_GPIO_Init(GPIOA , &GPIO_InitStruct);$ k+ m# z( s# K/ n" N) V. g
  28. </font>   <font face="微软雅黑" size="5">  Q9 |  `0 K! p) P# {
  29.   huart1.Instance = USART1;
    % i# h- Y# }! N  S! f  f$ e' \
  30.   huart1.Init.BaudRate = baud;
    . S0 J7 a+ O* T  r8 S. Z5 I
  31.   huart1.Init.WordLength = UART_WORDLENGTH_8B;9 e- A' J9 S; d" _4 r  W  s2 Z
  32.   huart1.Init.StopBits = UART_STOPBITS_1;, C( R, Y, K0 T. k- g
  33.   huart1.Init.Parity = UART_PARITY_NONE;1 X! s- u: l7 ?' T+ d3 r
  34.   huart1.Init.Mode = UART_MODE_TX_RX;5 T$ L- @$ I2 ]. U4 T) d8 s/ ^
  35.   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;- q% h# [0 G) ~) }! m/ P# N
  36.   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    4 f0 g4 k! r5 L1 z7 q5 q
  37.   huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;" O5 \. P2 P$ Y* R
  38.   huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;/ y' K* i* G1 b; l4 c: Y& [
  39.   huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;' Q1 y- j7 h( `4 F1 O
  40.   HAL_UART_Init(&huart1);
    - {/ l0 S* }, q
  41. }</font>
复制代码
非常简单,只要熟悉STM32编程的没有一点难度,然后是LPUART1:
: n, J* t- Z- P1 r/ f! J
  1. <font face="微软雅黑" size="5">UART_HandleTypeDef hlpuart1;
    5 I, i6 Q' G6 G8 W4 ~

  2. . V2 v4 Q6 L% K) I
  3. DMA_NodeTypeDef Node_GPDMA1_Channel0;
    $ W4 Z; o! I% E! A) U
  4. DMA_QListTypeDef List_GPDMA1_Channel0;% Y* m3 X) H6 M- \1 M
  5. DMA_HandleTypeDef handle_GPDMA1_Channel0;: }9 k0 z: P* ?5 ]# D. V) f
  6. $ ~; D1 f  v4 [# ]
  7. void LPUART1_Init(uint32_t baud)2 e  N5 b) N' k) U: R; a
  8. {
    6 y+ I: h' V. Y7 B) u
  9.     GPIO_InitTypeDef GPIO_InitStruct = {0};
    1 }2 \# r& h0 K0 I$ ^6 L
  10.     RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    ' s1 ^9 G( T: j, m2 ]1 D( E
  11.     DMA_NodeConfTypeDef NodeConfig;
    + O& X3 v' B# h, X# B7 L$ z, i$ I

  12. ! M9 D, z6 t- S( c1 x
  13.     __HAL_RCC_LPUART1_CLK_ENABLE();
    & n5 n# @+ Y2 k/ A; Y
  14.     __HAL_RCC_GPIOA_CLK_ENABLE();; z- l" z! L" ^) O  ?; J( L
  15.     __HAL_RCC_GPDMA1_CLK_ENABLE();
    2 o  }5 v/ w  C& w

  16. ( H! C; q# K0 |$ t, R
  17.   PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1;6 t, r" d# U6 n9 ^# Y3 l8 m
  18.   PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK3;( v6 w  N/ r* Z, J# U9 n
  19.     HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
    0 C+ Q/ H* X! t
  20. % d4 N  ~# {) `9 N& L3 ]# V
  21.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    3 B; N4 Z6 i: Y
  22.     GPIO_InitStruct.Pull = GPIO_PULLUP;- J2 l& k" _: }* i0 V3 L$ O3 {
  23.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    8 h, J4 ^7 u7 E- b. ?/ w2 @
  24. </font>   <font face="微软雅黑" size="5">
    " j" z2 x* }4 C
  25.     GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1;
    % j7 O- K  U; K/ h: P5 V9 I% j" ~
  26.     GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;2 X0 i% [+ U( u
  27.     HAL_GPIO_Init(GPIOA , &GPIO_InitStruct);
    2 M- I$ j* t* N7 b
  28. </font>   <font face="微软雅黑" size="5">5 Y, A" \  `4 s2 \: z  }( V! e
  29.   hlpuart1.Instance = LPUART1;/ G4 v/ W/ |+ Z9 g- ~# K
  30.   hlpuart1.Init.BaudRate = baud;) p# z) w/ |0 S! Q: o5 ~  J  k" e
  31.   hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;1 V& v* @* v+ n' D8 L/ b
  32.   hlpuart1.Init.StopBits = UART_STOPBITS_1;
    # J3 \/ Z- C* }9 K1 J& ~
  33.   hlpuart1.Init.Parity = UART_PARITY_NONE;
    # m: K8 S+ x7 X. Y, ?" x7 E) M
  34.   hlpuart1.Init.Mode = UART_MODE_TX_RX;
    & N  E/ ~! R2 o7 R4 |- l5 G
  35.   hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;$ ~; E$ B, T9 X. |+ C7 q
  36.   hlpuart1.Init.OverSampling = UART_OVERSAMPLING_16;
    ( U- B' [3 \: U/ i# Z: @0 T
  37.   hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    0 A* x/ h- X) u- e% K, T
  38.   hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
    , H$ n$ Q) ~  b- D
  39.   hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;* u/ V( b3 P6 L$ t
  40.   HAL_UART_Init(&hlpuart1);
    ; }* J9 o4 a# j- F3 b
  41. </font>   <font face="微软雅黑" size="5">
    5 o" t4 B1 C4 Y, H# U' e; _
  42.     __HAL_UART_ENABLE_IT(&hlpuart1 , UART_IT_IDLE);# P  o8 u2 K% ^& J2 F- u# O2 q
  43.     HAL_NVIC_SetPriority(LPUART1_IRQn,1,1);
    0 m6 b9 w9 x6 j0 q( E( k4 t3 l$ |
  44.     HAL_NVIC_EnableIRQ(LPUART1_IRQn);
    ' a* W  J0 I: ~4 m: {
  45. </font>   <font face="微软雅黑" size="5">
    3 f  t' ^# U0 t* ~- \
  46.     NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;& Y- _0 _4 G  v" z
  47.     NodeConfig.Init.Request = GPDMA1_REQUEST_LPUART1_RX;/ F7 I6 p$ Z, e' N1 U+ N$ h1 i
  48.     NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;. w1 r+ I' O% h% ^- y
  49.     NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
    + i; J* ?' Y6 d' m3 J# f
  50.     NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
    / h9 L  Q, a) E, O# x6 n
  51.     NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;6 u1 ]) Q* L  W9 ^& }9 S: k7 n9 L
  52.     NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;* c5 [! u, ^/ @" X5 q/ f
  53.     NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
    4 d8 f7 @0 j' G- N" U- Y/ _
  54.     NodeConfig.Init.SrcBurstLength = 1;! o# e! J6 R6 q9 l! l+ _
  55.     NodeConfig.Init.DestBurstLength = 1;$ g$ S+ ]( m  A; H; v. j9 Q6 @
  56.     NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
    - [2 y* d/ z& ~  L
  57.     NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
    : H' O9 Y/ {/ Z! x8 ^3 E
  58.     NodeConfig.Init.Mode = DMA_NORMAL;8 m( A, B0 \& q7 m, p4 ]
  59.     NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
    & I' ?3 ]' ^& @+ W* L7 ~
  60.     NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
    5 x; t+ F" l' v5 D5 s# R
  61.     NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;, A1 u2 ?7 Y: |& N% Y' f) F# _
  62.     HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel0);
    . I# a" g4 H) j9 B
  63. ! c0 {- d7 y! {' U# `
  64.     HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel0, NULL, &Node_GPDMA1_Channel0);
    ; q- L) }8 H  n

  65. 8 A3 o* \8 t1 t
  66.     HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel0);: V, t4 D: {: {8 |$ \

  67. + s+ G1 Q' ]! O. G
  68.     handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;  Y9 I) s7 f0 I* k/ M
  69.     handle_GPDMA1_Channel0.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;, t, K) u$ g8 @
  70.     handle_GPDMA1_Channel0.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;- I5 d8 {' {: N
  71.     handle_GPDMA1_Channel0.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;! x/ T( ~& e8 j
  72.     handle_GPDMA1_Channel0.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;2 {6 x) b* q% ]1 R2 o$ G
  73.     handle_GPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
    ' R) e! U7 r3 H5 R' K
  74.     HAL_DMAEx_List_Init(&handle_GPDMA1_Channel0);
    ) s. V6 T6 |5 J  |' t* h4 a
  75. / J' y( z1 e2 z$ z3 g3 T3 I
  76.     HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &List_GPDMA1_Channel0);" V% d1 D! W' U0 h- r# b

  77. 4 [  J- E* T; T# g
  78.     __HAL_LINKDMA(&hlpuart1, hdmarx, handle_GPDMA1_Channel0);
    ; t1 v5 f1 c5 N: N0 w& V
  79. ; l$ r. |# R' t1 p+ Z! W% f
  80.     HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV);
    3 j6 i$ u4 a/ I5 y
  81. </font>   <font face="微软雅黑" size="5">
    $ l9 V% p: L2 \+ v# `, R
  82.     HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, 0, 0);/ V+ N# ]! p: _5 y* O
  83.     HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);! q( ^9 f/ e$ T1 V( f
  84. }- A/ [6 g+ B% A  j/ ~: M% R4 ?  j

  85. * Z7 I/ D$ N- T+ _3 X9 n) k
  86. void LPUART1_Send_Char(uint8_t ch)
    ! W# @7 w& H. `8 L/ U
  87. {
    4 S  [! o0 p" @) D1 _6 w
  88.     while ((LPUART1->ISR & 0X40) == 0);& z/ z' t; C' r* ?
  89.   LPUART1->TDR = (uint8_t)ch;0 p0 q; s# X/ ~7 F# N3 H1 }
  90. }3 l4 X* F' ?/ t5 K& I  E

  91. ) T2 I) Y1 }: |+ `
  92. void LPUART1_Send_String(uint8_t * s)
    / [: m* m1 p8 H1 p- t* ^# f6 }
  93. {
    $ t% s3 @. ?9 c
  94.     uint32_t i;
    7 P7 H* h0 E1 H8 Q! [
  95.     for(i = 0 ; s != '\0' ; i++)2 ~/ d/ E* Q6 W' N, s
  96.         LPUART1_Send_Char(s);
    " E+ d3 s* ^  Y' F
  97. }: d& u+ f& u! c- X1 q/ w' A5 T
  98. 4 s* d# ?' b, S* X2 g* n" ~
  99. void GPDMA1_Channel0_IRQHandler(void): F& b, ]5 O  }8 Q7 u
  100. {
    # T$ z6 k4 I3 L2 e
  101.   HAL_DMA_IRQHandler(&handle_GPDMA1_Channel0);
    6 n$ R: i5 {4 }( m2 P& p
  102. }
    ; f! S. N. P0 Q5 `7 W: r

  103. 5 D9 [9 @, H' k4 K1 v9 Z: y
  104. uint8_t aRxBuffer[RXBUFFERSIZE];2 W  z, W; X( q+ i1 A$ u
  105. 0 i, x+ S. Z/ _0 p' ]& m5 @$ G
  106. void LPUART1_IRQHandler(void)                    , P/ V& o' {& F2 l4 K4 r/ U- A0 h7 \
  107. {
    . u& t1 Q1 v  V, q
  108. //    int temp;6 ?* p  Y8 V* Q. b  L
  109.     if(LPUART1->ISR & UART_FLAG_IDLE). G( u" W8 Q+ H8 \6 m5 d* @
  110.     {
    & z6 O) S* T. y4 l4 y' q: {
  111.         __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
    6 ^3 L5 y; m& ]3 G
  112.         printf("LPUART1_IRQHandler. %d %s\n" , GPDMA1_Channel0->CBR1 , aRxBuffer);% c1 q) t1 o8 _9 Y; X0 W7 l8 V  ?
  113. </font>        <font face="微软雅黑" size="5">
    2 s% h. L" o3 @( n5 ?: `
  114.         HAL_UART_DMAStop(&hlpuart1);6 ]0 G4 S# n0 }- [, N% J
  115.         HAL_UART_Receive_DMA(&hlpuart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
    % q" M( O# A! k% \3 y! f& j
  116. //        rx1_len = BUFFERSIZE - DMA1_Channel5->CNDTR;) m3 l4 [  [* ]2 C" q' g4 E7 c
  117. //        uart1_recv_end_flag = 1;0 k9 M0 ]) a8 r# r
  118.     }: g  S- a) n5 v3 U
  119. }</font>
复制代码
在ST的新系列里面,有个特殊机制,使用任何形式的DMA通信必须要打开DMA中断,这个在F103系列是不需要的,是F4以及之后的大部分系列都需要,另外,在F4之后的系列中,对于外设要用的DMA,可以自由配置通道Channel(流Stream/节点Node)等,其实是一个东西,就是DMA通道的意思,不同系列的名称不同,只有F103和F4系列的特定外设是绑定在特定DMA通道的。像本帖子,就把LPUART1的RX功能设置在在GPDMA的通道0(后续还把SPI1的TX功能设置在GPDMA的通道1)。
* G4 e' G7 A( q0 m0 _1 z
$ F: E, s, H, g. V. Y  G) g 6.JPG
. P! Z$ T( y5 b6 Q: k9 y% I# d2 _" @7 i4 j
看看运行效果,使用两根typec线分别连接开发板的STLINKV3接口以及用一个USB转TTL模块接在PA2 PA3引脚上:
2 u7 c5 f. s6 Y
7.JPG IMG_20250523_174406.jpg 7 u' U4 v. B6 ~. r- q
首先上电之后UART1和LPUART1都会打印信息,然后,对LPUART1发送数据,UART1会打印接收到的数据以及接收长度(100-DTR寄存器值)。
赞 收藏 评论6 发布时间:2025-5-23 17:55

举报

6个回答
星海灿烂 回答时间:2025-5-25 15:04:59

你好,板载ST-LINK电脑可以识别不到吗?

donatello1996 回答时间:2025-5-25 23:48:46

星海灿烂 发表于 2025-5-25 15:04
你好,板载ST-LINK电脑可以识别不到吗?

没看懂你的表述是什么意思

星海灿烂 回答时间:2025-5-26 08:58:46

donatello1996 发表于 2025-5-25 23:48
没看懂你的表述是什么意思

就是把板载ST-LINK的C口接入电脑,电脑可以识别到ST-LINK吗?

donatello1996 回答时间:2025-5-26 16:13:19

星海灿烂 发表于 2025-5-26 08:58</p>
<p>就是把板载ST-LINK的C口接入电脑,电脑可以识别到ST-LINK吗?

[md]那肯定可以识别啊,不识别怎么下载代码发帖子😄

星海灿烂 回答时间:2025-5-26 16:53:24

donatello1996 发表于 2025-5-26 16:13
那肯定可以识别啊,不识别怎么下载代码发帖子😄

使用的是全功能的Type-c线吗?

donatello1996 回答时间:2025-5-26 17:42:37

星海灿烂 发表于 2025-5-26 16:53
使用的是全功能的Type-c线吗?

没听说过typec线还分什么全功能不全功能的,我直接用手机充电线来接开发板的,一端是typeA的HOST,一端是typec,把线连接电脑和手机,能识别出手机的存储卡,那就肯定可以给开发板用

所属标签

相似技术帖

官网相关资源

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