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

基于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 至少可以得到一半的系统总线带宽。


  j) z3 C7 b8 [/ w$ C7 ~

微信图片_20230402181850.png


% Z5 z3 a8 ?5 r" `

  • DMA 处理
    8 Z6 p+ ]7 V+ ?7 k! V

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


. k3 S# m2 C  }0 q) d

  • 仲裁器# w& k3 r1 q0 _! t  P  Q% a- D/ i

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

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

; [7 q5 s4 N+ q) p1 M

  • DMA 通道
    7 N! E; t9 ~& ^' y  r4 e2 [

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

8 p+ j7 a! Z# ~0 U
微信图片_20230402182102.png % ]) n& B+ B9 S& z

9 [7 ^. b6 v  i7 P

STM32 的 DMA 有以下一些特性:

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

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

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

● 支持循环的缓冲器管理

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

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

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

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

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

$ m1 u. B' l) {1 B$ [7 }0 B& {% C$ }

STM32串口DMA使用详解

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


4 v) g& t: p4 F3 R, W$ p  E: v

cubemx配置

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

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

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

# O6 d& ~; \' e( }, M( o+ n. M; N
微信图片_20230402181846.png
2 f! W' r7 @: X5 t' C. @6 q3 t; u) V" u& K8 O

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

4 a. J# |2 u8 L2 m
微信图片_20230402181843.png 5 q# k! j1 g7 @" ~: f, G$ ?
6 `  }. \/ U) P' D  w. j6 v

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


% \& _& A0 Q& \& a 微信图片_20230402181839.png
9 e* V( x  c4 M! \$ S
- P. r( v; U+ t

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

3 n& l, ?) ^8 C

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

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

  1. /** @defgroup DMA_Exported_Types DMA Exported Types6 b# W$ ^/ H' }9 T! Q$ v0 Z
  2.   * @{
    5 _' t# E& ]  R% r% _& K
  3.   */8 d) e! G6 ?4 z! ?# d

  4. ) R6 [3 C+ v* ?
  5. /**
    , H5 ]9 g# t6 e1 L+ k9 U
  6.   * @brief  DMA Configuration Structure definition+ U# M( x+ D; D% a
  7.   */8 F& A  {$ ~; i7 ]2 a& p! o$ u
  8. typedef struct
    8 @6 r& L0 f/ _
  9. {7 Z! z7 [+ N8 N* R# ^: h4 ^
  10.   uint32_t Direction;                 /*!< Specifies if the data will be transferred from memory to peripheral,
    / W$ K/ {; Z" j( T: s
  11.                                            from memory to memory or from peripheral to memory.
    % g# v: B: Q% @' @1 M) X" {' C) ~
  12.                                            This parameter can be a value of @ref DMA_Data_transfer_direction */
    - V9 G: ~' _, G$ W
  13. $ |) }! r' L2 m7 W# r. {0 {
  14.   uint32_t PeriphInc;                 /*!< Specifies whether the Peripheral address register should be incremented or not.
    / p, Q% C9 _4 V2 E8 R1 r+ z) [
  15.                                            This parameter can be a value of @ref DMA_Peripheral_incremented_mode */
    , c4 X: K6 G3 V2 N+ w, a3 T

  16. % Y1 m) j) k& ?& n1 X3 a
  17.   uint32_t MemInc;                    /*!< Specifies whether the memory address register should be incremented or not.5 ~4 u( h( j+ ?% {5 V: M
  18.                                            This parameter can be a value of @ref DMA_Memory_incremented_mode */& Q7 u+ T( ~* ]6 d
  19. . a  s+ ^4 f. W
  20.   uint32_t PeriphDataAlignment;       /*!< Specifies the Peripheral data width.8 }) c, ~" a( u
  21.                                            This parameter can be a value of @ref DMA_Peripheral_data_size */
    ! \# w3 X7 N2 s3 U8 n

  22. 4 [) i) u! l: b0 b% @
  23.   uint32_t MemDataAlignment;          /*!< Specifies the Memory data width.0 G/ \* |+ x# I' D$ u) ~3 v7 h& f
  24.                                            This parameter can be a value of @ref DMA_Memory_data_size */: {: h" e2 q3 A$ x3 V8 h4 U
  25. - V' g8 Q; d5 K
  26.   uint32_t Mode;                      /*!< Specifies the operation mode of the DMAy Channelx.5 e* M$ I0 e4 D6 z6 L0 W* f+ d, `( q3 ~
  27.                                            This parameter can be a value of @ref DMA_mode" L" |* Q$ x' e  Y( a+ j/ ]
  28.                                            @note The circular buffer mode cannot be used if the memory-to-memory
    ! X3 Q) _0 V  ?  p0 B9 f5 g
  29.                                                  data transfer is configured on the selected Channel *// A2 E) i* r/ k- h$ S
  30. 5 E$ m! D, c- o7 }  {  O5 _
  31.   uint32_t Priority;                  /*!< Specifies the software priority for the DMAy Channelx.
    3 Y: h3 L, }, K
  32.                                            This parameter can be a value of @ref DMA_Priority_level */
    2 M" R2 q0 T5 ^6 ^7 L# m) C9 R) K( u" I$ A
  33. } DMA_InitTypeDef;
复制代码

1 G1 D, G; G- [4 q9 [

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

7 l5 q& O% i! H+ }$ ?' j. c7 E
微信图片_20230402181836.png . _1 Y  G. b: F4 a6 A) \
0 A8 S2 _5 m) W. d

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


6 A, {. K+ V5 R$ }0 c

微信图片_20230402181832.png

, K- u9 u6 R7 j1 D2 I6 l; X

串口DMA初始化部分:

  1. void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)2 i/ j2 m# n2 Q. d9 g
  2. {
    / K& ^8 d# ?# i5 v" y

  3. ! b" d( t  E' H
  4.   GPIO_InitTypeDef GPIO_InitStruct = {0};
    6 N* f" h0 e8 H) B& B% H" a/ M9 t
  5.   if(uartHandle->Instance==USART1)
    " y6 r- X0 Y' s/ J6 Q
  6.   {3 ?4 P. }: D6 z# s' W! q
  7.   /* USER CODE BEGIN USART1_MspInit 0 */
    # C2 f2 M) @3 a# ]' S/ e3 `/ v: \

  8. 7 \% q+ y; A5 t! I  Z/ e. @2 \
  9.   /* USER CODE END USART1_MspInit 0 */$ y# H: C) s4 A6 Y- P1 u4 T+ P% w! O
  10.     /* USART1 clock enable */
    , ^! e$ U9 G% O  |& Q7 [) r
  11.     __HAL_RCC_USART1_CLK_ENABLE();
    / H6 \8 S2 K% a  |0 B& ]) z

  12. 9 v' b* T% i1 I' T3 {7 x' i
  13.     __HAL_RCC_GPIOA_CLK_ENABLE();4 G& m* P4 X" k4 }6 I' f+ y8 ^
  14.     /**USART1 GPIO Configuration8 T7 G: j" h( ^) P* C) v" T
  15.     PA9     ------> USART1_TX
    9 T* {4 ]* I" A( X' `5 o- M
  16.     PA10     ------> USART1_RX: g" f9 h! \* H1 R- q3 ^
  17.     */
    " l0 q! i7 O% D: ]* {- Y
  18.     GPIO_InitStruct.Pin = User_UART_TX_Pin;! I. {* l, R9 ?. a( L4 a
  19.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;' q2 R: V# V7 f5 J( _' |( z# ^2 H: [, a9 R
  20.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    ( S! u8 b9 T1 c1 v
  21.     HAL_GPIO_Init(User_UART_TX_GPIO_Port, &GPIO_InitStruct);* N% b6 m9 |9 e8 u

  22. 9 L2 n  |. a2 w7 q
  23.     GPIO_InitStruct.Pin = User_UART_RX_Pin;9 u/ A. d3 x, A8 }% X. r! D; E6 O
  24.     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;7 S# y( |% {% U) S# Z, U
  25.     GPIO_InitStruct.Pull = GPIO_NOPULL;) j" C" Y  ~& ?# a" @4 c8 a. o2 _
  26.     HAL_GPIO_Init(User_UART_RX_GPIO_Port, &GPIO_InitStruct);
    / r, {; f3 ^0 ~) j: ]

  27. * [) {9 y6 _4 k
  28.     /* USART1 DMA Init */: F; k0 q& E$ N& d+ ]
  29.     /* USART1_TX Init */, R) Z# _' ]; d7 ^4 b# K# K) G/ Q
  30.     hdma_usart1_tx.Instance = DMA1_Channel4;
    " ?9 K! B; A* M/ |5 R8 x
  31.     hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    3 B& y6 i/ T3 i. x6 z" Z6 `
  32.     hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;4 u  v9 X) f9 K( c2 {( E) u
  33.     hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;9 M! G  F6 f8 Y8 ~" w/ Y
  34.     hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;! ?9 o4 U$ F- F1 C
  35.     hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    " S+ G# o- b1 x* o8 q1 t
  36.     hdma_usart1_tx.Init.Mode = DMA_CIRCULAR;  R: ?0 |0 f% Q3 B4 J  U$ v) O
  37.     hdma_usart1_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
    - S/ n5 [1 [6 c3 l" t
  38.     if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK), B( ^& u- X! ?! Y* j
  39.     {
    4 ~) b/ n9 t- t  g( U' C* x
  40.       Error_Handler();
    ; \/ Z1 ]' X% S
  41.     }
    4 ?0 B- s! n6 d( Z
  42. 9 u+ E0 y6 l: A6 Y( \8 Q7 I6 X
  43.     __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);
    9 w5 f) t* z; K

  44. $ P' `% L+ i. {/ S* `* l8 W# n& d( M
  45.     /* USART1_RX Init */
    7 l3 H, V$ {8 S7 g1 h5 I) G
  46.     hdma_usart1_rx.Instance = DMA1_Channel5;
    " u' c/ t1 z, _9 o
  47.     hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;. u) e! y: d0 `; u. y
  48.     hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;" s. V9 a6 {$ @! s" M3 K
  49.     hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    * i7 }% J+ I6 R$ O; v3 V! K, x
  50.     hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    " i( U* H; x3 c- D3 f" {7 f
  51.     hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    * Z  A  @; u; D" I% l5 L2 C: `
  52.     hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;; @* N7 t" E5 p9 N
  53.     hdma_usart1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
    / ]/ L9 ], `; [
  54.     if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)  Q4 B2 [8 |4 Z' e$ j- H0 h
  55.     {! u2 r/ a% W& Y( P( ~$ Q8 b" h
  56.       Error_Handler();
    ( C0 B2 T6 P* U0 p" q' ]
  57.     }8 }, m4 a, P5 o( K1 k
  58. 6 [& S! I4 E: `3 c) _. N
  59.     __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);
    5 K) ~% u( z' D) b: e& N

  60. 4 x' D  c. y, w. }1 |
  61.     /* USART1 interrupt Init */
    . h1 i9 s' j* S8 W
  62.     HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    9 X$ D' |$ ]% [: l1 M
  63.     HAL_NVIC_EnableIRQ(USART1_IRQn);
    ! _& |! ~2 m3 F$ N7 @4 K( s7 a/ Y
  64.   /* USER CODE BEGIN USART1_MspInit 1 */& p# Z" i8 t2 z9 c
  65. & S, M. B* \* o5 r9 d( D
  66.   /* USER CODE END USART1_MspInit 1 */
    0 m, H$ _9 n6 e
  67.   }
    9 G& g* g% V8 _) C9 z. u, @8 g
  68. }
复制代码

6 y! c9 m% \8 y; H. y; pDMA发送设计

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

  1. /******************************************************
    ( Z1 [+ F6 b3 q1 ?) G- H1 M+ g) v
  2. * Brief     : DMA传输函数
    - r* ]) F5 n1 Z; ^1 L
  3. * Parameter :
    $ n$ B  s3 y9 K% p
  4. *           *pData: 要传输的数据" ]2 l4 s- A/ t4 O9 G
  5. * Return    : None.
    0 h* n; J; S! l
  6. *******************************************************/
    3 Z7 r% c1 [5 F
  7. void User_uartdma_Transmit(const char *pData)' u$ A3 {! ~, ^! U
  8. {
    9 E9 L9 `$ B/ ^/ z* I. Q# U
  9. HAL_UART_Transmit_DMA(&huart1,(uint8_t *)pData,strlen(pData));0 l0 {+ A. y  E8 t  X1 D$ S; t
  10. }
复制代码
# A9 p2 w& |3 k+ c6 I0 }8 Q: b

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

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

& m! q: M, i  o. Z' T* W: O
微信图片_20230402181828.png 2 A( j" V" b7 `6 C5 d$ ]7 Q" B% j4 z

! n5 i  R7 Q/ p  G$ O$ ?$ z' y9 }' y

不信你看~


9 ~7 Y; Y8 O' g! t! P# n

微信图片_20230402181823.png


4 E9 n0 V5 K! ]2 D4 ?/ k

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

4 q2 K/ j& W8 D2 A- w

DMA接收设计

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

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

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

具体的设计思路是:

1、开启串口1中断

2、开启串口1空闲中断

3、打开串口DMA接收

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

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

先来封装几个函数:

  1. /******************************************************1 P+ ]" |7 ]# j6 R" J
  2. * Brief     : 串口DMA 初始化,初始化除了cubemx配置之外的部分5 t- }/ B! V, n! w
  3. * Parameter :
    1 o, d; |- r$ @, c) W
  4. *           : 9 }1 u1 s9 _- Y& b: U# J: w
  5. * Return    : None.
    3 ^8 p4 s% X+ z3 h, I  c# F  N
  6. *******************************************************/  }' S$ r# @1 w% |: |4 J
  7. void User_uartdma_Init(void)
    # C" U8 K" {2 L* n/ ^5 _( ^7 a
  8. {* C% Y7 ^3 Z& I$ n! r8 H
  9. //失能串口DMA传输
    0 T& m+ y  S; Q6 z+ R
  10. HAL_UART_DMAStop(&huart1);
    # F" ?! z5 d0 ?4 h( x4 `
  11. //使能串口1接收中断; K3 G$ ~6 Q9 E! O) ]
  12. __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);' T9 o+ r6 _' U6 M
  13. //使能串口1空闲中断( T3 S2 W8 U  P/ z/ z9 n: [
  14. __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);9 K, J! G, I, C  w
  15. //使能串口DMA接收
    2 _% z) i6 q7 V& L1 a: k
  16. HAL_UART_Receive_DMA(&huart1,UserUartDma.RxBuffer,Max_RecLen);
    ' A0 V; n3 ~2 L0 n: {+ P, j4 I+ t
  17. }
复制代码
  1. /**7 u2 p2 J& [3 R  Y, g
  2.   * @brief  DMA接收函数
    5 _: s1 }9 D% C- c& A. ~
  3.   * @param  htim TIM Base handle
    9 u, O; f6 F; s8 n+ ~0 L0 _) K4 O4 p
  4.   * @retval HAL status
    $ M9 P) K6 F9 V: i5 u9 @, J
  5.   */8 J8 u. V4 [3 v3 S
  6. void User_uartdma_Receive(uint8_t *recData,uint16_t rec_len). v6 T: d# {+ \  ?4 H% A
  7. {; Q6 h( p8 y! h
  8. HAL_UART_Receive_DMA(&huart1,recData,rec_len);  {+ c; A2 z# `' p" V
  9. }+ i# A* e. a- r5 d+ p; ?

  10. 8 s# z# z1 R: v" ^1 C& Q1 H, V
复制代码

# h& v1 L' A7 e4 {5 P+ |

主函数:

  1. /**
    4 H& f: x% `) r9 p
  2.   * @brief This function handles USART1 global interrupt.
    : [+ R' n) `% P) Y; s! ?$ o
  3.   */; L" Z- T' Q7 o/ i6 Q# u- A
  4. void USART1_IRQHandler(void)7 X' [5 b- ~. Q0 f0 ~" j
  5. {$ R. y$ N3 X, m; E* W  b" f, O4 w$ _) N
  6.   /* USER CODE BEGIN USART1_IRQn 0 */2 b6 Z4 p+ D1 Y6 z! y
  7. uint32_t idle_flag_temp = 0;$ X. @0 F; w  x) j8 x1 z$ w4 F
  8. uint16_t len_temp = 0;) W/ W  Z6 G  ^, h4 f% ~
  9.   /* USER CODE END USART1_IRQn 0 */0 s/ M) H# c/ a& C8 I
  10.   HAL_UART_IRQHandler(&huart1);
    ( L! A7 C& Q; K) A; q
  11.   /* USER CODE BEGIN USART1_IRQn 1 */
    $ j$ b. Y9 {3 j  w, v- ]" E. d5 r4 K2 k
  12. idle_flag_temp = __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);. S% A- w* O" @! c
  13.   z$ l  Y3 S! D$ v
  14. if(idle_flag_temp)
    6 v  N- Q# ?2 l: A# J; r+ O
  15. {
    3 {8 ?" S& Q3 K$ @) t3 \- ?# U3 D
  16.   __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE);4 M5 ]: Y! ]  [% U6 t$ I
  17.   HAL_UART_DMAStop(&huart1);
    + {* E9 M" U- M# U* d* O
  18.   ( L3 V/ z7 @1 _. h2 t
  19.   len_temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
    , M2 m" D$ i& |0 t/ z1 X
  20.   # [" w  w8 \% Q! @5 w
  21.   UserUartDma.RecDat_len = Max_RecLen - len_temp;  
    $ q8 b! X) I* c: H; d0 a
  22.   UserUartDma.rec_endFlag = 1;# U& \0 b# o& u9 U# q5 h
  23.   
    % W" ?0 S* {( w. f# B5 }4 L
  24. }: M: F6 F; _- \; @. p$ u4 M
  25.   __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);! b# B0 L; ?4 I+ {$ D) I
  26.   HAL_UART_Receive_DMA(&huart1,UserUartDma.RxBuffer,Max_RecLen);  8 _; w! H3 Q( ]& P; p
  27.   /* USER CODE END USART1_IRQn 1 */* S# g/ P  k, L# F0 _( A; Y8 N6 D
  28. }
复制代码

! R6 ~$ \7 ^: Q

演示效果:


5 R: A) D) F5 j1 B
  L( R7 q' a/ J$ `2 J7 o, m1 H7 ?
微信图片_20230402181811.png   g# |' y: e# s* j) t

2 ^0 P/ w  r, S' u& K8 N! R7 q转载自: Embedded小飞哥
9 ]( \( b# S# Z* R/ t. ~% A如有侵权请联系删除! x5 U9 P3 F/ R. Y
+ v1 C, F# B$ l" [0 H( a. m2 [) F1 R

7 Z1 c1 r: @5 u
9 e  E6 g2 q/ i) t3 C% g
收藏 评论0 发布时间:2023-4-2 18:19

举报

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