拿到了nucleo-U385开发板,在KEIL环境下编程,需要下载CubeU3支持包,在ST官网即可下载,并且在CubeU3支持包内还有KEIL环境所需要的pack安装包,这个应该是最近才做的一个方便开发者开发的一个机制:5 r" j6 `' n) h; N' h
, I6 b. j: u* ^# j" S, F我直接用点灯的例程来改串口例程,方便省事:2 O( U) a4 a* }
5 X' e3 a" b- X5 ^; [整理好的例程结构如下:7 Z3 h1 Z% q4 F5 P
+ p$ x" w3 g( W3 ?9 u& k$ w- n1 }* e
根据原理图可以得知,开发板的STLINKV3 VCP连接的串口是UART1,即PA9 PA10,可以直接与电脑的串口助手进行通信,另外开发板上还有PA2 PA3引脚,这个引脚被复用为LPUART1:
. X! Q" L+ }* g
3 R2 f$ k$ O: S5 n2 |; j
我这个帖子就实现UART1和LPUART1的双通道串口通信,其中把LPUART1的接收功能打开,使用空闲中断和DMA进行接收,先看看UART1的初始化代码:- <font face="微软雅黑" size="5">UART_HandleTypeDef huart1;
% r, {, x$ i9 ^% v: k
& i5 u v+ g) M- int fputc(int ch , FILE *f)- F6 K: h2 m+ c0 O- `% u, \6 u
- {. U3 G: K |2 v2 Z, i, f9 e$ ?
- while ((USART1->ISR & 0X40) == 0);& t- x: V* p5 ]7 E, ^ W
- USART1->TDR = (uint8_t)ch;
! h) a2 }2 D) g - return ch;
p$ Q/ U. Y2 d& ?: G% r - }; c& m8 |; l# e2 v4 T8 b
- , ?4 P2 _$ |3 t$ P, s9 Y( E( @. k5 k Q
- void UART1_Init(uint32_t baud)) r8 O9 Z0 T# y4 o h" s/ S& E- k
- {* G9 K: Q$ ~" ?7 c
- GPIO_InitTypeDef GPIO_InitStruct = {0};- g" D9 X" k9 X; k4 A6 o8 e+ k
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
c4 a4 i: ~' ]+ h* a w" W9 B6 B! o
( `0 n7 x: o0 } [- L- __HAL_RCC_USART1_CLK_ENABLE();; ^+ q) B/ K6 o) `( |) p$ t
- __HAL_RCC_GPIOA_CLK_ENABLE();
* J1 D O' B- [1 |+ _
/ z+ }3 Z2 U6 B7 q# \- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;% J3 v1 X' L5 v
- PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
! g8 g0 r0 r9 V6 t - HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
7 {7 V' L ]7 i2 \/ m T. f - 0 |) ?- R3 E S4 q# B, t( T- S
- GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
( F3 t a9 [+ E4 W% M" g - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;2 k7 J9 W- p* T4 j3 u4 \
- GPIO_InitStruct.Pull = GPIO_PULLUP;% ]) O6 x) A( N9 H# k! s
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;% ?6 Y1 o4 c1 i' s
- GPIO_InitStruct.Alternate = GPIO_AF7_USART1;0 r, t/ e) ]& d' |) G
- HAL_GPIO_Init(GPIOA , &GPIO_InitStruct);
9 E$ d& ?7 F4 h8 T - </font> <font face="微软雅黑" size="5">
0 e6 p& H2 s% { - huart1.Instance = USART1;2 ]& q# o$ h9 [# T0 _
- huart1.Init.BaudRate = baud;
) x- I) x- l" x- X* X& _. @. f' U - huart1.Init.WordLength = UART_WORDLENGTH_8B;2 S: ]1 {5 W- e7 r
- huart1.Init.StopBits = UART_STOPBITS_1;- J; f6 _, Y7 O) h$ \+ `1 D6 c
- huart1.Init.Parity = UART_PARITY_NONE;
6 {& [3 G. l& r8 k - huart1.Init.Mode = UART_MODE_TX_RX;! t! g9 G: Y R" }/ `# \6 E3 a# f; Z
- huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;" [9 Y' y( r6 p( A9 m7 u
- huart1.Init.OverSampling = UART_OVERSAMPLING_16;
, _' R# A8 {! O8 \; f - huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;, A! _( Y9 W! a7 j' U+ H" x8 ^
- huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
, V# ?! m/ n4 a; } - huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;6 b4 V4 l; K- ~: e% u
- HAL_UART_Init(&huart1);
0 C8 Y: r/ j: N( P" y; ` - }</font>
复制代码 非常简单,只要熟悉STM32编程的没有一点难度,然后是LPUART1:* V7 {5 Q, h6 S1 p5 r( n
- <font face="微软雅黑" size="5">UART_HandleTypeDef hlpuart1;2 w- R# [* x( B' ?& C
- ' a2 S% I7 y8 z3 ?
- DMA_NodeTypeDef Node_GPDMA1_Channel0;
" \) M* X% q: q' n - DMA_QListTypeDef List_GPDMA1_Channel0;' N# ~+ s, F" T- z% j
- DMA_HandleTypeDef handle_GPDMA1_Channel0;
" }0 j7 l: T8 b. V - 4 N3 B' }% X- b+ ~3 Q
- void LPUART1_Init(uint32_t baud)5 ~7 z& j J; y; `; ~
- {. g# F: q' `: S1 [" j0 H, u
- GPIO_InitTypeDef GPIO_InitStruct = {0};9 X. v. N& w1 v; W$ w" u* U
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
: { |% H7 _* x0 l! t, s* A- T - DMA_NodeConfTypeDef NodeConfig;
7 x6 n0 Y2 d; H( h N- O1 Y
" H& ]. B5 K* J/ |0 |- __HAL_RCC_LPUART1_CLK_ENABLE();
9 L& O: T! O) `7 t( c+ B - __HAL_RCC_GPIOA_CLK_ENABLE();2 [- W3 b( I# F! }9 B- p" F5 t) N. `
- __HAL_RCC_GPDMA1_CLK_ENABLE();) E/ n; z$ P8 T
. a( I4 m [* l2 x A) q& e- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1;1 G9 `! ^7 h6 |
- PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK3;
; j4 |8 i# B( I - HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); Y4 `! g' S1 h2 _* c. _, {" p# U
- : c, W/ y; {; q5 G c2 X
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;# h0 N! [; ?: r) F: U1 \
- GPIO_InitStruct.Pull = GPIO_PULLUP;4 x0 z- u) @9 M2 J& R0 }+ A8 q/ [" c( Z
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;7 e l$ t* I3 k! \/ t
- </font> <font face="微软雅黑" size="5">4 }% C9 p* O. s
- GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1;& {6 y- _- d) k' _8 l5 x% L
- GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
9 l, |7 h2 T5 _+ G, S% k; p- e: c - HAL_GPIO_Init(GPIOA , &GPIO_InitStruct);
7 w# R; Y: `) | j8 B: V) ? - </font> <font face="微软雅黑" size="5">7 [/ v6 o' s G& Z% I5 P, S& i
- hlpuart1.Instance = LPUART1;
, t2 T. ], Q2 B - hlpuart1.Init.BaudRate = baud;
2 Z+ k& w2 u9 u* q - hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;2 i6 G; ?" B7 s/ r
- hlpuart1.Init.StopBits = UART_STOPBITS_1;% s" q; L$ }( x X8 p
- hlpuart1.Init.Parity = UART_PARITY_NONE;
. X! @& j x5 c: p$ @4 ? - hlpuart1.Init.Mode = UART_MODE_TX_RX;7 E, ^( O: }7 X* B' W
- hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
4 D0 r- n7 [* j+ `# x4 y- r4 I - hlpuart1.Init.OverSampling = UART_OVERSAMPLING_16;7 Z r( j# _8 v: x4 j6 Q
- hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;6 s# |) v* h5 B+ n
- hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;/ r( X; Q P. j5 d2 I2 H9 G1 O
- hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
' O9 @7 Q _1 {" l/ g: X% N6 a - HAL_UART_Init(&hlpuart1);! z) A- V$ A5 W3 Z1 ^
- </font> <font face="微软雅黑" size="5">
; o; @1 m1 ]5 N" c; ` - __HAL_UART_ENABLE_IT(&hlpuart1 , UART_IT_IDLE);( Y3 p r2 L9 a3 J7 }
- HAL_NVIC_SetPriority(LPUART1_IRQn,1,1);
2 w' ]& d; F8 T' V, u6 z6 o' { - HAL_NVIC_EnableIRQ(LPUART1_IRQn);
F2 R% Z# C4 R1 X8 x6 v - </font> <font face="微软雅黑" size="5">6 o2 [/ ~2 c3 b7 w$ T, }& N1 B- q
- NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;* x' W2 h' }: j
- NodeConfig.Init.Request = GPDMA1_REQUEST_LPUART1_RX;
$ ?9 h1 }& f2 i& M, r) `' y - NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;8 q; v6 F: o$ ^9 b
- NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;0 N1 l" f+ n2 t
- NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
) H9 u, N4 D0 Z - NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
% N) c- H9 w9 r/ a. o - NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
8 U/ R, X9 F5 d- G- k - NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
/ P* t, h% R7 H8 X - NodeConfig.Init.SrcBurstLength = 1;' E- u4 E5 z+ h/ b; g, l2 P7 K, p
- NodeConfig.Init.DestBurstLength = 1;
: B. K" P6 S4 Q4 e: \2 \ - NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;4 `6 s& M& N4 g( ?. J1 {& i' h4 k5 l
- NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;4 p9 h4 I8 q3 l4 v
- NodeConfig.Init.Mode = DMA_NORMAL;! C# Z2 I# Z7 t2 {4 F
- NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
" ]) C5 s9 |+ Y# y* I V- t - NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;* X% F1 H+ L2 w
- NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
: K: Z+ d9 s5 q - HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel0);
~ m& @: N) F - 7 \9 u) B" {8 ?; J o
- HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel0, NULL, &Node_GPDMA1_Channel0);/ e1 l# r. X1 U
- % N- m; s7 G( ?. h
- HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel0);( J7 R* e& i8 U; C" |
0 ]! E# r4 \' o+ ~- handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
& M' l# K0 P7 H3 N$ x1 o( Y - handle_GPDMA1_Channel0.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;) V9 V$ @! h# W. u) D& b A
- handle_GPDMA1_Channel0.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;. h9 S9 w. [0 k
- handle_GPDMA1_Channel0.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;( L S/ L7 f3 R. s7 ~0 S
- handle_GPDMA1_Channel0.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;( B' T5 R% [8 ?( V2 j0 D0 y5 v
- handle_GPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
! a7 |0 m2 f) M) N8 e, T1 F0 u6 j - HAL_DMAEx_List_Init(&handle_GPDMA1_Channel0);
5 G: z6 @$ x% q0 N - ' K' g! Z# s! x( N1 s) o* U
- HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &List_GPDMA1_Channel0);; S1 d1 m' j0 ?- Z
4 c4 k6 s0 e9 S4 E& n0 |- __HAL_LINKDMA(&hlpuart1, hdmarx, handle_GPDMA1_Channel0);
8 U9 M$ O# n* Z6 Z
8 V0 `# ?! W6 Z$ h1 h; f( h8 p5 l- HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV);
. T ]+ F; l* p - </font> <font face="微软雅黑" size="5">
: c* k, |; L4 F, @; U) N - HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, 0, 0);
. t* `) B8 [% ^. t6 {! |0 |7 W - HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);+ U! s+ L! l- U, D6 N5 A
- }
3 _1 L' b* M6 P- ^
: }0 B2 { T# t1 A- void LPUART1_Send_Char(uint8_t ch)
3 M6 ~9 Y/ O3 `( R/ f# L9 {0 @ - {
) O& B$ @1 t7 @, t1 P* H3 Q/ ? - while ((LPUART1->ISR & 0X40) == 0);
6 X4 y/ K$ d2 L - LPUART1->TDR = (uint8_t)ch;- Q2 C! C/ [+ z9 c
- }) [/ [3 R2 K8 h* `2 L U& ^( ?
/ O: i9 F) c( T: P! m; ]- void LPUART1_Send_String(uint8_t * s)
u9 B( g0 v: K% ]8 |2 m - {
% Z9 k$ N C9 w - uint32_t i; _1 h, e3 ?1 a, C# V4 z3 ~
- for(i = 0 ; s != '\0' ; i++)4 ?; h. i: e0 J( w2 B
- LPUART1_Send_Char(s);. A; n* Z2 D; u% M
- }7 m" @; ~ x4 F; c/ _ ?" V
5 g/ b$ W7 T: X1 V6 h1 I' V" Y- void GPDMA1_Channel0_IRQHandler(void)" @( e5 h$ ]* F# N1 M2 Y0 N
- {
8 Y l6 v6 m2 b! t& m* n - HAL_DMA_IRQHandler(&handle_GPDMA1_Channel0);! C0 t: J8 L- D: C% p/ i- P3 f
- }7 z2 f4 g) K; [* A* x8 l7 r
5 `" ]7 r/ d8 ~& Z/ M- uint8_t aRxBuffer[RXBUFFERSIZE];. \& @8 _+ z1 v1 x9 G% w
- - m+ K, L3 A+ X8 }; e6 L3 e* Y
- void LPUART1_IRQHandler(void) ^# Z' y* U* S# P9 g& ^
- {
3 R9 m S3 p" j ~6 ? - // int temp;( k- r% w7 L4 m ~1 A5 A5 S, W
- if(LPUART1->ISR & UART_FLAG_IDLE)
5 M8 f0 A0 }( l O - {
" E M& _) o F! V9 Z2 v* t - __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
7 C) d# K. i- m6 c, F* d - printf("LPUART1_IRQHandler. %d %s\n" , GPDMA1_Channel0->CBR1 , aRxBuffer);
. _+ d- ?; h6 v& e - </font> <font face="微软雅黑" size="5">! z& r1 `1 q+ S% z
- HAL_UART_DMAStop(&hlpuart1);' [: p" y+ I i$ A3 L7 p- K: \( y
- HAL_UART_Receive_DMA(&hlpuart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);- r( P! t% |" O, `* I
- // rx1_len = BUFFERSIZE - DMA1_Channel5->CNDTR;- A% d3 J4 e) X1 F+ u" _/ ]
- // uart1_recv_end_flag = 1;
8 p1 J ?/ }) l3 l9 v* g - }5 W. y+ v4 g' O9 M
- }</font>
复制代码 在ST的新系列里面,有个特殊机制,使用任何形式的DMA通信必须要打开DMA中断,这个在F103系列是不需要的,是F4以及之后的大部分系列都需要,另外,在F4之后的系列中,对于外设要用的DMA,可以自由配置通道Channel(流Stream/节点Node)等,其实是一个东西,就是DMA通道的意思,不同系列的名称不同,只有F103和F4系列的特定外设是绑定在特定DMA通道的。像本帖子,就把LPUART1的RX功能设置在在GPDMA的通道0(后续还把SPI1的TX功能设置在GPDMA的通道1)。
# c7 E$ F' w/ Q
/ d) e2 k; s7 L, ]3 }! P
8 v N: `$ b# \/ A, O/ t* n
- @* d, x: p0 ?4 U2 X8 f- V: U看看运行效果,使用两根typec线分别连接开发板的STLINKV3接口以及用一个USB转TTL模块接在PA2 PA3引脚上:$ y6 A: i$ u# n3 c! W; O
: R3 d0 K J$ I" w) R. a* {6 k/ z: P
首先上电之后UART1和LPUART1都会打印信息,然后,对LPUART1发送数据,UART1会打印接收到的数据以及接收长度(100-DTR寄存器值)。 |
你好,板载ST-LINK电脑可以识别不到吗?
没看懂你的表述是什么意思
就是把板载ST-LINK的C口接入电脑,电脑可以识别到ST-LINK吗?
[md]那肯定可以识别啊,不识别怎么下载代码发帖子😄
使用的是全功能的Type-c线吗?
没听说过typec线还分什么全功能不全功能的,我直接用手机充电线来接开发板的,一端是typeA的HOST,一端是typec,把线连接电脑和手机,能识别出手机的存储卡,那就肯定可以给开发板用