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

基于Cubemx与HAL库串口DMA收发经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-2 18:19
STM32 DMA简介

DMA,全称为:Direct Memory Access,即直接存储器访问, DMA 传输将数据从一个 地址空间复制到另外一个地址空间。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器 来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的 内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工 作。

DMA 传输对于高效能嵌入式系统算法和网络是很重要的。DMA 传输方式无需 CPU 直接 控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备 开辟一条直接传送数据的通路, 能使 CPU 的效率大为提高。

如图 所示, 两个 DMA 控制器有 12 个通道(DMA1 有 7 个通道, DMA2有5个通道)。DMA 控制器和 Cortex-M3 核心共享系统数据总线,执行直接存储器数据传输。当 CPU 和 DMA 同时访问相同的目标(RAM 或外设) 时, DMA 请求会暂停 CPU 访问系统总线达若干个周期,总线仲裁器执行循环跳读,以保证CPU 至少可以得到一半的系统总线带宽。


6 V% N& x8 B( \: L

微信图片_20230402181850.png

7 z1 t' t" \+ H* C6 D* l

  • DMA 处理
    ; ]  l! M9 {* E% f6 B. M0 b# n  d

在发送一个事件后,外设向 DMA 发送一个请求信号 的箭头。DMA 控制器根据通道的优先权处理请求。当 DMA 需 送请求的外设时, DMA 控制器立即发送给它一个应答信号。外 号后,立即释放它的请求, 同时 DMA 控制器撤销应答信号

: L& |" K7 u3 U" B/ ^) W( y: }1 V

  • 仲裁器
    / _% _8 y. d. c: P. }8 G3 ]# p

一个 DMA 控制器对应 8 个数据流,数据流包含要传输数据的源地址、目标地址、数据等信息。如果我们需要同时使用同一个 DMA 控制器多个外设请求时,那必然需要同时使用多个数据流,其中哪个数据流优先, 此时由仲裁器来选定。

仲裁器管理数据流方法分为两个阶段。第一阶段属于软件阶段,我们在配置数据流时可以通过寄存器设定它的优先级别,可以在 DMA_CCRx 寄存器中设置, 有最高优先级、高优先级、中等优先级和低优先级四个等级。第二阶段是硬件,如果两个请求有相同的软件优先级,则较低编号的通道比高编号的通道有较高的优先权。例如:通道 2 优先于通道 4。

& R) b& T) w/ U% }

  • DMA 通道( O( Q  h; F4 U

每个通道都可以在由固定地址的外设寄存器和存储器之间执行DMA 传输。DMA 的传输数据量是可编程, 可以通过 DMA_CCRx 寄存器中的PSIZE 和 MSIZE 位来进行编程,数据量最大可以达到 65535。DMA 的外设繁多, 例如 DMA1 控制器,从外设产生 7 个请求,通过逻辑或(例如通道 1 的三个 DMA 请求,这几个是通过逻辑或到通道 1 的,这样我们在同一时间,就只能使用其中的一个)输入到 DMA1 控制器,此时只有一个请求有效。


0 X4 n2 j+ U) p. d5 l 微信图片_20230402182102.png 8 ~, e0 I2 C# Q1 Q/ O

- }4 P( b! [9 k& D% m% V

STM32 的 DMA 有以下一些特性:

●每个通道都直接连接专用的硬件 DMA 请求,每个通道都同样支持软件触发。这些功能 通过软件来配置。

● 在七个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),假如 在相等优先权时由硬件决定(请求 0 优先于请求 1,依此类推) 。

● 独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和 目标地址必须按数据传输宽度对齐。

● 支持循环的缓冲器管理

● 每个通道都有 3 个事件标志(DMA 半传输, DMA 传输完成和 DMA 传输出错),这 3 个 事件标志逻辑或成为一个单独的中断请求。

● 存储器和存储器间的传输

● 外设和存储器,存储器和外设的传输

● 闪存、 SRAM、外设的 SRAM、 APB1 APB2 和 AHB 外设均可作为访问的源和目标。

● 可编程的数据传输数目:最大为 65536

- J, ~8 O% K7 w! W" e

STM32串口DMA使用详解

本次我们使用的硬件环境是之前开源的板子,falling-star board,使用串口1。

9 i4 M6 L$ F/ b8 R

cubemx配置

关于时钟配置、串口基本配置请参看:cubemx的正确打开方式一文

接下来直接进入配置串口DMA:

选择串口1,基本参数如图,都是老生常谈了,easy~

% u" c9 o6 z3 D/ P1 o
微信图片_20230402181846.png
( \: T6 X# N' ^, \% C5 k8 {( H" y8 |8 \  E: J% d- K9 @- C

选择DMA Settings,主要有一下几个地方,基本上不需要改动,根据自己的使用情况确认即可,需要注意的是,发送和接收并不是一定要成对出现的,可以只选择DMA发送或者DMA接收

6 v* z* S4 n# c+ W; C8 [5 _& @
微信图片_20230402181843.png # }7 J% f  d# c

$ G+ e5 \: N1 w% N

中断设置,DMA中断可以配置,可以不配置,同样也是根据自己的实际需求情况,串口中断需要配置,下面会用到,优先级根据自己任务的优先级确定,分好“轻重缓急”即可

8 N7 _% }! c& n. l- A
微信图片_20230402181839.png
. l7 a5 o8 H: K  G/ ^  I  H$ p" q+ Y9 ]0 N; D: v6 i. P: d

配置非常简单,主要是在此前串口功能基础上添加DMA功能,over

% ^2 _& g/ K1 ^- g: o* v1 q

串口DMA代码设计串口DMA源码API介绍

上面提到的配置项,都封装在一个结构体里面

  1. /** @defgroup DMA_Exported_Types DMA Exported Types1 S6 e( T$ T5 w4 i, I
  2.   * @{
    & s: X' b0 o8 f; L3 z2 g: R" V
  3.   */% d+ @0 s, Z( A# n6 j* g
  4. & m% n( }  g1 D* I3 S4 j# d
  5. /**8 {" {: z2 {) b, B# P
  6.   * @brief  DMA Configuration Structure definition
    5 h8 o( u' w# Q# C
  7.   */
    + X( w3 y& I* W6 G4 f
  8. typedef struct8 Z# H3 s  I* [; @
  9. {
    ' \7 S4 a2 L. r2 [
  10.   uint32_t Direction;                 /*!< Specifies if the data will be transferred from memory to peripheral,
    % b  p% P. @" u. I8 k
  11.                                            from memory to memory or from peripheral to memory.
    ; U# y/ W4 t8 N3 e, T4 V0 X1 M7 |
  12.                                            This parameter can be a value of @ref DMA_Data_transfer_direction */
    % k; E$ i- ], |- i6 A8 v7 y

  13. 4 u' B, p, ]! h: C/ f. ~! Y
  14.   uint32_t PeriphInc;                 /*!< Specifies whether the Peripheral address register should be incremented or not.# N0 X, W6 P7 U. j9 }+ i' d
  15.                                            This parameter can be a value of @ref DMA_Peripheral_incremented_mode */1 P1 M# ]' Y2 x( [* ~4 l) P4 e% V$ @
  16. 4 m+ X" s1 f" d$ Q; l
  17.   uint32_t MemInc;                    /*!< Specifies whether the memory address register should be incremented or not.. s9 Q/ k/ V7 C$ G; J' r: U
  18.                                            This parameter can be a value of @ref DMA_Memory_incremented_mode */
    ( I9 R4 \  h. o& a
  19. ; K8 r- m: y+ U" b. I. X3 |5 w5 S
  20.   uint32_t PeriphDataAlignment;       /*!< Specifies the Peripheral data width.
    ) o6 K/ S3 r( Z7 S) f3 {
  21.                                            This parameter can be a value of @ref DMA_Peripheral_data_size */2 \7 v- R# z6 R' ]* R$ g
  22. 0 D% [) r% V7 n1 j( d
  23.   uint32_t MemDataAlignment;          /*!< Specifies the Memory data width.& l. s, v2 d' h9 Z- @# U2 a
  24.                                            This parameter can be a value of @ref DMA_Memory_data_size */# L$ k' j- X9 ^. I  ^: T

  25. & N7 y2 _& A( p. B5 E. y1 P+ V
  26.   uint32_t Mode;                      /*!< Specifies the operation mode of the DMAy Channelx.
    ( J' |& t8 `* T5 v6 Q: K5 }( a
  27.                                            This parameter can be a value of @ref DMA_mode6 h8 h1 ?7 T8 j5 ]( @% @
  28.                                            @note The circular buffer mode cannot be used if the memory-to-memory
    9 U) \/ j0 q+ B3 ?( {
  29.                                                  data transfer is configured on the selected Channel */- X" [0 M" i: `. s! l/ p6 B
  30. ' X$ Y+ D% O9 {6 E8 c' i6 n
  31.   uint32_t Priority;                  /*!< Specifies the software priority for the DMAy Channelx.; V: B8 F* G0 Z' Z1 v5 p! \7 V: Q0 o
  32.                                            This parameter can be a value of @ref DMA_Priority_level */
    , ^* L- f9 w* [7 i+ P. ^
  33. } DMA_InitTypeDef;
复制代码

$ O) L( s: O3 p( L5 t

关于DMA的函数不多,本次用到DMA的初始化,开始发送函数

5 u! `2 ?& G1 ~3 u
微信图片_20230402181836.png 9 s" Z5 s2 q1 G4 D

/ L9 _: R3 \( Q4 s

串口中关于DMA的部分主要有这几个函数,还有一些关于中断、DMA标志等的一些宏定义,就不在一一列举了,需要用的时候大家知道去库函数中去找就可以了


$ a7 P) J& F( Y  q. w3 u- s) N

微信图片_20230402181832.png

, Q4 J9 P0 i& `' S" J7 G" N- |

串口DMA初始化部分:

  1. void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
    0 c! l# B' M# j! w: X( z
  2. {
    ) C  I# N8 a# V0 B% }
  3. # s4 t* Z: J$ d: q
  4.   GPIO_InitTypeDef GPIO_InitStruct = {0};# h% f7 D* k+ I" g% b' w9 _* r
  5.   if(uartHandle->Instance==USART1)
    / q# a" q  R* h8 P
  6.   {
    3 L  L1 G- f/ k* u% N: Q, k
  7.   /* USER CODE BEGIN USART1_MspInit 0 */
    0 ^! l$ U% s# w0 O8 {' [" e

  8. % h0 T. k# T) L: ^, |
  9.   /* USER CODE END USART1_MspInit 0 */! E1 }; J7 B: }
  10.     /* USART1 clock enable */
    / W5 V$ L: P) b# X$ K
  11.     __HAL_RCC_USART1_CLK_ENABLE();
    ; p6 i1 o4 g7 ~; m2 a1 G
  12. 7 }, ]+ }' g, s' y7 l, Z
  13.     __HAL_RCC_GPIOA_CLK_ENABLE();3 k9 X7 o; h" n
  14.     /**USART1 GPIO Configuration3 `" l7 U- U) y/ K: z
  15.     PA9     ------> USART1_TX* q/ u+ Z8 J& R) i. b9 r
  16.     PA10     ------> USART1_RX
    ) D$ K: ?# n4 m, {
  17.     */
    8 |% K& |" K4 @; j' u/ I: ]3 t
  18.     GPIO_InitStruct.Pin = User_UART_TX_Pin;
      z, U2 I+ T7 }/ w/ T4 h
  19.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    1 Y& z& O- s) c* _7 |* r, q
  20.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;* {7 r& k- d, I- @7 F% a
  21.     HAL_GPIO_Init(User_UART_TX_GPIO_Port, &GPIO_InitStruct);- d) C% {, P( p# H# r0 x# t3 f4 B9 {
  22. # e) P' T; v8 M" P* O% K
  23.     GPIO_InitStruct.Pin = User_UART_RX_Pin;1 S5 B5 T' n$ }: D! W0 n$ g: k, g
  24.     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;( X7 H: }- _$ y2 k6 \. v5 F1 e* J
  25.     GPIO_InitStruct.Pull = GPIO_NOPULL;+ B) Y( K1 u2 \/ q, w# n% F5 I
  26.     HAL_GPIO_Init(User_UART_RX_GPIO_Port, &GPIO_InitStruct);
    . I2 }; m1 w, {5 K
  27. 0 O) b- `6 E6 e4 D! J+ i
  28.     /* USART1 DMA Init */9 Q& z3 ?- W/ d  a5 N0 z
  29.     /* USART1_TX Init */( y( S7 L, X6 |$ _, }, D
  30.     hdma_usart1_tx.Instance = DMA1_Channel4;
    3 Y, z/ n2 f/ r# D4 M5 w4 J( o) W
  31.     hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    % v3 ~) Z' R7 S7 w
  32.     hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    * _+ m5 O9 e, O, k2 i$ s
  33.     hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    0 [3 |8 O* z' P/ m5 z
  34.     hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;& n' V4 D: n& z, I: C
  35.     hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;4 X- Q6 q! Z2 C: K
  36.     hdma_usart1_tx.Init.Mode = DMA_CIRCULAR;' V. `# t- g5 \) V0 P5 F
  37.     hdma_usart1_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
    7 V: P; h; J* [' b5 n5 F# |: G
  38.     if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)4 X# F( W" X( D1 O4 `5 \3 A$ q6 M9 s
  39.     {0 o* j3 ?/ r) P
  40.       Error_Handler();
    & p* }/ k' v- a1 P6 P" P+ V. n
  41.     }
    + b2 a. X7 H: H% |! N8 J

  42. 5 W5 l5 x5 C. ^6 \3 P1 {3 P, n
  43.     __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);" l# g& _4 ]% [/ K( G7 w" H' j
  44. 8 M# e" T! l) t7 r( h! d
  45.     /* USART1_RX Init */
    ) B5 w: v- M2 l  Y
  46.     hdma_usart1_rx.Instance = DMA1_Channel5;
    : b  m* f8 G& E* b7 h5 h, [
  47.     hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    ( U2 Q0 o/ d7 f. A/ p, P
  48.     hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    1 F; a9 Q- \) L& F
  49.     hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    + [" K) B" f8 J" H( S* q
  50.     hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;5 Z9 ?( ~8 ^8 H* G9 @
  51.     hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;0 W7 ~; T4 D. U6 y; a( I
  52.     hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;# Y$ s7 O3 ]2 n( C
  53.     hdma_usart1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;! ?' o' ]4 |4 e/ @5 ~
  54.     if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)! J  N3 M! @( Z, ?+ v/ _& h, c
  55.     {+ X6 l% m9 C# e4 G- t. k' l5 \
  56.       Error_Handler();) d+ s! q6 u* {1 N& ~8 H' Y6 X
  57.     }2 ^8 P7 c9 T- N8 n- G* ]& i+ {
  58. ' R# M7 ]& L# a2 p) s1 }- e
  59.     __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);
    , T& W( L$ u4 Q* _4 U( l! ^) r3 l8 S
  60. & w9 Q2 {$ [; ]$ T/ S& U7 `
  61.     /* USART1 interrupt Init */
    5 M. y+ {. f. R# y' q
  62.     HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    ' \5 H8 H- M3 \( f
  63.     HAL_NVIC_EnableIRQ(USART1_IRQn);0 X7 m8 i* E: T% s3 p- l( }/ U
  64.   /* USER CODE BEGIN USART1_MspInit 1 */
    % h) D0 s$ ?/ J! |
  65. * _3 O6 _  \; O% V
  66.   /* USER CODE END USART1_MspInit 1 */) W* b- H3 ^+ n, D1 V; Z6 x
  67.   }# I% N7 t' l" T6 h" S, v
  68. }
复制代码
: \" |9 r5 {. |' d) {
DMA发送设计

发送非常简单,都不知道该怎么介绍...发送对应DMA的方向是内存到外设,我们只需要把数据装入相应的内存中,调用发送的API即可:

  1. /******************************************************
    3 x1 [- q# B% S" @
  2. * Brief     : DMA传输函数
    * f7 F1 }6 k1 K$ ^9 `7 B' `
  3. * Parameter :
    ' {* ^& w" ~. X$ o3 {
  4. *           *pData: 要传输的数据
    $ t2 ^) N4 c8 Y9 I8 C3 o
  5. * Return    : None.
    . P+ U: o* ~$ [- B+ V, \
  6. *******************************************************/8 H/ g9 k9 n7 |3 f; q- S
  7. void User_uartdma_Transmit(const char *pData)' x8 K9 u5 T8 L+ J+ K. p4 `2 R
  8. { # G! T+ A( S0 `' k( @  r
  9. HAL_UART_Transmit_DMA(&huart1,(uint8_t *)pData,strlen(pData));
    9 D% t* l4 ^$ \. D
  10. }
复制代码

9 L9 P* b- }' G5 H  B& }4 m

根据DMA的原理,我们发送的时候是不影响CPU的正常工作的,效果应该类似于操作系统的多任务执行,现在我们只需要在初始化时候打开DMA发送数据,串口助手监控,主函数什么都不干,数据不断在发送

此时如果添加两个LED流水灯,是完全不受发送数据影响的,效果就不放了,相信小飞哥...


) I9 B+ y$ i  X0 ~* a, | 微信图片_20230402181828.png
5 ~0 u. \5 ]# n& n% A$ k/ O# L% n4 }1 v- `

不信你看~

$ O/ Z* f+ d0 t% G5 D

微信图片_20230402181823.png


4 @2 J$ V- _8 R4 l% C) D

发送的是非常简单的,好像这里也没体现出来,使用DMA发送有什么好处,其实在LCD驱动的时候,当有图片等大数据量的数据需要传输的时候,使用DMA是种非常好的方式

& A) `: V) E5 x9 l0 k7 l1 m  h

DMA接收设计

聊起串口数据接收,我们最先接触的可能是,中断接收,来一字节进一次中断,通过定时器超时判断一帧数据结束。

但是小伙伴们有没有考虑过一个事情,数据量很大,串口一直进中断,对MCU带来的负荷是非常大的,这种方式就显得不那么美好了。

哲学上讲,矛盾是推动社会进步的源泉,没错,鉴于此种情况,我们换一种方式来处理,DMA+串口空闲中断的方式,我相信,这种方式你一用就会喜欢上~

具体的设计思路是:

1、开启串口1中断

2、开启串口1空闲中断

3、打开串口DMA接收

4、判断空闲中断标志是否置位

5、数据接收完成,主函数打印接收到的数据

先来封装几个函数:

  1. /******************************************************
    ' V% h. E8 q; X8 k  \* @2 |1 B& w
  2. * Brief     : 串口DMA 初始化,初始化除了cubemx配置之外的部分
    3 k- D; v+ F2 W) z; k8 H! ?
  3. * Parameter :
    ( W$ G2 |: X, c  A# J
  4. *           :
    3 A7 R& ^' u7 E, y$ ?
  5. * Return    : None.
    : A) \! A9 r$ o$ z
  6. *******************************************************/; n5 C* ^! [* P% [2 ^1 M( ]( O/ _8 `9 e
  7. void User_uartdma_Init(void)
    4 y, k- D0 _) v: g5 p. H8 j
  8. {
    * W3 q# r  h" {! f# ]
  9. //失能串口DMA传输
    ; h& L) ^& `" t  L, L8 P
  10. HAL_UART_DMAStop(&huart1);8 W( `  I5 k* H! Q, t' v  B
  11. //使能串口1接收中断3 U" W5 l* o5 V1 [5 ?4 K
  12. __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);
    2 @; m, i' m4 ~$ A5 n
  13. //使能串口1空闲中断& x/ H% B+ A* ]4 g* c7 N) S/ J
  14. __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);) B. P; E$ h, y. Y' Y. N, _. g
  15. //使能串口DMA接收
    6 n1 @: m- z1 C& J1 q
  16. HAL_UART_Receive_DMA(&huart1,UserUartDma.RxBuffer,Max_RecLen);
    4 U2 z6 I0 G3 C1 G! P
  17. }
复制代码
  1. /**
    " K+ j) |( }. h4 o2 X
  2.   * @brief  DMA接收函数- O: p, L- A7 |4 e! ^! ]% s5 _" a- U
  3.   * @param  htim TIM Base handle
    2 V- U6 i" h5 z3 a/ |, ]
  4.   * @retval HAL status
    - n+ Z1 g: J( u
  5.   */% g) d) x6 E% X7 A6 O5 K
  6. void User_uartdma_Receive(uint8_t *recData,uint16_t rec_len)
    2 Z7 n/ u, Y0 K& K
  7. {9 l' ]$ Z: o3 `7 G0 v) i8 x/ i
  8. HAL_UART_Receive_DMA(&huart1,recData,rec_len);
    : g* G$ n) i* @  H
  9. }2 r' K7 w: L3 I0 K7 R' @4 D$ C  s1 Q3 t

  10. % j6 i7 K& V0 s3 j
复制代码
+ R9 I) J9 z# B1 t% f

主函数:

  1. /**0 S  E1 e9 w9 x/ j% O
  2.   * @brief This function handles USART1 global interrupt.
    0 W. A9 B2 o8 H* A4 i* U
  3.   */
    3 F1 e' }/ h+ N
  4. void USART1_IRQHandler(void)7 x3 q3 A# n8 J1 f1 k8 N
  5. {
    : _8 k9 m0 h' u8 c5 y5 w" }
  6.   /* USER CODE BEGIN USART1_IRQn 0 */
    ' T' q/ V# ^' V2 f2 e) G$ z
  7. uint32_t idle_flag_temp = 0;
    . ^' f9 J  U: ]3 z) D, h
  8. uint16_t len_temp = 0;
    ) n. p, D8 c0 Z* ]& G; [/ n! E7 ~$ m* C
  9.   /* USER CODE END USART1_IRQn 0 */% f# V4 E1 x; G: y
  10.   HAL_UART_IRQHandler(&huart1);. B5 w% S# J/ S: V9 m( c1 f
  11.   /* USER CODE BEGIN USART1_IRQn 1 */
    7 D, y% o/ V& X' q  g
  12. idle_flag_temp = __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);
    2 ~% Q- i; e1 J1 `' ?9 e+ b9 [

  13. $ a! W0 C8 T1 H* H! b
  14. if(idle_flag_temp)6 n- E. l0 \' a* R4 H% D% M0 l% i2 X
  15. {
    . P5 A# _& k# I/ E2 w
  16.   __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE);
    . l8 v" `# ]1 ~9 u  W7 ], _
  17.   HAL_UART_DMAStop(&huart1);3 D1 ]# D) R( C' N% d0 V
  18.   0 z+ m, L5 x! {# s( r8 q) ~
  19.   len_temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
    " N' o- @# ]; U$ ?, {0 c4 X( g( i
  20.   ; R, C7 ^4 {5 \" T* S" h: G  o
  21.   UserUartDma.RecDat_len = Max_RecLen - len_temp;  
    + w' y1 \) ]- J4 g
  22.   UserUartDma.rec_endFlag = 1;6 U1 A6 @6 K- J! `8 c$ F7 c: x
  23.   
    ! M( p# y4 ]5 f4 p7 N
  24. }( F- P0 A% |* O
  25.   __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);9 G4 m# h* h1 H- U9 L- _: H6 h- o
  26.   HAL_UART_Receive_DMA(&huart1,UserUartDma.RxBuffer,Max_RecLen);  
    ; M9 e' L! p/ E# Y
  27.   /* USER CODE END USART1_IRQn 1 */. \# U& }3 G; r* O% T2 K, h
  28. }
复制代码
7 I" M. g5 A: n6 a( K, d

演示效果:


4 H9 d) c3 i) J" h$ J9 _! L" H

0 |9 K! r8 P4 N: E 微信图片_20230402181811.png , S! t2 f1 r8 p6 F1 ~  o* [1 I

7 y0 h4 `7 a% s  u- \/ [% g/ |转载自: Embedded小飞哥: i% g6 c- C+ n3 V" K" b, i
如有侵权请联系删除: ^) ^( ~( u% ^
0 a: H" `5 q) b% u- S
$ u) X% E0 O+ F. Y, m; l4 ]4 m; \% ^
1 y, X0 V3 J& f- \# s. U
收藏 评论0 发布时间:2023-4-2 18:19

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版