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

【经验分享】STM32H7 串口 空闲中断 DMA 任意长接收 Hal库 IDLE

[复制链接]
STMCU小助手 发布时间:2021-12-25 10:14
中断接收方式,最大的缺点就是中断过于频繁,为了解决这个问题那就把DMA搬过来,它不就是专门搬用数据的嘛,不用多可惜。( T0 D9 v5 v9 V# Y% V
8 D5 d3 h( z4 N% P
首先我们需要大致了解,DMA和外设传送数据,例如串口,我们希望,当一帧数据接收完毕了,有个东西告诉主程序,串口接收到了一帧n个字节的数据存在某个地方,接收过程中你丫别打搅我。
( a& z4 B' e* t# e0 W( n! t$ f5 q. r% r
DMA就能胜任这个工作,他可以以中断的形式告诉你这些信息。相比中断接收方式,是不是省了很多中断,主程序被打断的次数也就少了。
- x5 u5 P3 `6 d* V3 X/ ]2 N% J: W7 ~6 r
还是按照上一篇形式大概看一下,HAL库中DMA是怎么和串口配合的。; a4 g6 A$ P4 s$ U$ ?
0 E2 O' ]7 }0 d, @1 P5 Y
  1. /**- R. p( B) h4 N$ }8 Q! }3 `! D
  2.   * @brief Receive an amount of data in DMA mode.
    , Q6 Z: o6 D: \8 t
  3.   * @note   When the UART parity is enabled (PCE = 1), the received data contain
    ! O3 d& q5 u: ^/ G
  4.   *         the parity bit (MSB position).9 K( G" \* u4 Q" }) Q
  5.   * @param huart UART handle.% @* j0 r3 F# W3 A4 P
  6.   * @param pData Pointer to data buffer.
    $ r" D% b1 X; ?
  7.   * @param Size  Amount of data to be received.6 O% s% E7 L" e5 t" p
  8.   * @retval HAL status
    & V; |" O* o) B- _; r3 j
  9.   */1 O# r( r4 h, X* h) w
  10. HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
    2 O9 O1 e% I' J1 |
  11. {
    8 l& v, P* W0 ~  d
  12.   /* 其他关系不大的代码省略 有兴趣可以自己看 下同 */
    6 R6 A9 `' W; E3 D6 [% W( `3 v* m4 e
  13.   //1.检查参数 判断串口接收状态为就绪 把缓存区参数传递到串口句柄  修改某些状态* I6 W: c* z# @+ h* n+ q" E
  14.   //2.判断和串口句柄关联的DMA句柄地址不为空  然后给DMA句柄注册一些回调函数5 [2 |9 p4 w+ v& R
  15.       /* Enable the DMA channel */* i7 f$ q! X( r" n6 e) s
  16.       if (HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->RDR, (uint32_t)huart->pRxBuffPtr, Size) != HAL_OK)! S+ G# v& R3 U
  17.     {% g/ c2 l& T' `0 W
  18.       ......* A1 s; V5 w* @, r+ x/ [; B1 \% q! ?
  19.     }" x* D2 Q9 @2 x9 T
  20. }
复制代码
  b" S( S% U# m. x$ r& R: |1 l, x
HAL_UART_Receive_DMA这个函数里最主要的就是调用了HAL_DMA_Start_IT这个函数,你看他连参数都没怎么变,就把句柄换了,其他三个原封不动的传递过去了。所以函数内其他内容几乎不用考虑了。直接往下看这个函数。3 V/ U3 [0 |+ P

* D6 }0 O9 ?" S: k
  1. /**
    0 v# H0 K1 C4 W* V4 u
  2.   * @brief  Start the DMA Transfer with interrupt enabled.$ m8 {5 `# z" N# `, u
  3.   * @param  hdma:       pointer to a DMA_HandleTypeDef structure that contains, T: }. e# H1 x, E
  4.   *                     the configuration information for the specified DMA Stream.
    / ]5 {: F; K& k7 l! K$ ~
  5.   * @param  SrcAddress: The source memory Buffer address
    ( O2 ]$ B/ |1 Q/ n
  6.   * @param  DstAddress: The destination memory Buffer address. x- u7 D" x3 _# D, }$ a: [5 y
  7.   * @param  DataLength: The length of data to be transferred from source to destination
    * b6 Y5 U/ o4 J
  8.   * @retval HAL status9 F  O% M3 P. V
  9.   */, }7 g& I- h/ n# w
  10. HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)5 E, E; [- s* X8 l. o
  11. {8 h  M+ i4 U, S2 O( U) G7 B/ |  E
  12.   //1.检查参数 给句柄上锁 判断状态 只有在就绪状态下才允许配置
    " Q$ O) t( x2 j& p) \
  13.   //2.判断就绪状态
    * h' P, Y2 ]* l) N5 P
  14.   {* c) d* A- C/ u9 v; F( x  I0 Y
  15.     ......
    # A  F- x+ S; [/ k
  16.     /* Configure the source, destination address and the data length */
      x+ J5 ~/ x( k& W
  17.     DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);9 K4 q8 q+ }7 r5 N
  18.     ......2 N  j* ~2 W, s
  19.     //这里会开启一堆中断  完事要用  暂时可以不关心1 [' x: e. p0 J3 o
  20.   }$ a! B* \1 K4 _' s8 _
  21. }
复制代码
8 _8 H; A  Z* z1 n+ D8 K
上面这个函数也差不多还是那个意思,都懒的看了,主要是调用了DMA_SetConfig这个函数,追踪过去,它才是真正配置寄存器的函数,HAL库就是这么繁琐。
. v6 l3 l; `9 \* \; |6 W
- u% D5 p! Z" D  c  K8 K9 n
  1. /**3 H  W/ J/ f# N% ?6 k* Y' l2 k
  2.   * @brief  Sets the DMA Transfer parameter.
    % T5 b+ l: g4 i, j  C4 E
  3.   * @param  hdma:       pointer to a DMA_HandleTypeDef structure that contains
    : d6 b+ }% Z5 \& o
  4.   *                     the configuration information for the specified DMA Stream.
    - d$ H' h: Q6 q6 y4 I4 N* W; P
  5.   * @param  SrcAddress: The source memory Buffer address
    & V6 L% O; W1 D' \+ f, F$ `
  6.   * @param  DstAddress: The destination memory Buffer address& {+ |; ~/ ]3 |) R+ ]8 V  F- y
  7.   * @param  DataLength: The length of data to be transferred from source to destination" ^' N) Y& S! @& C1 E! e( s" p
  8.   * @retval None
    ; X$ [- u8 q% t0 L
  9.   */3 D' d/ O! o& P. {# \* l
  10. static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)% z0 t3 }/ F) _. i. L% S
  11. {
    - T- \* w9 `* x: w, t" w
  12.   /* calculate DMA base and stream number */
    0 |. v& R; D  K9 c3 e5 ]" D* W4 k: b
  13.   //获取DMA控制器对应流的基地址. D! r' `' o. g8 V+ D0 ]' h
  14.   DMA_Base_Registers  *regs_dma  = (DMA_Base_Registers *)hdma->StreamBaseAddress;
    " v, F5 m' E7 V
  15.   BDMA_Base_Registers *regs_bdma = (BDMA_Base_Registers *)hdma->StreamBaseAddress;
    $ F/ P4 y9 i; U& P9 S* v, z& W

  16. ( F9 Y4 f' ~, f0 {# _) V6 a
  17.   /* Clear the DMAMUX synchro overrun flag */
    6 j2 H" w* v' ]6 K9 s
  18.   hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask;; y9 I: r0 y$ R7 A8 z$ _1 E

  19. 1 w0 f% i) k( r4 A! Y# U+ |+ v" a
  20.   if(hdma->DMAmuxRequestGen != 0U)
    ; L3 S+ @1 C0 p* m% ^
  21.   {, J8 B' w6 }0 k- N( F
  22.     /* Clear the DMAMUX request generator overrun flag */, @8 v  y& ?, u
  23.     hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask;
    * p1 m  K: A' h: G: o8 H( k
  24.   }2 T8 D+ a1 v2 O6 e

  25. , e9 a# z+ _( `( I
  26.   if(IS_DMA_STREAM_INSTANCE(hdma->Instance) != 0U) /* DMA1 or DMA2 instance */
    ( e* j- B& y/ Y& Y
  27.   {6 m; f* t: C9 v. D2 J# i: \
  28.     /* Clear all interrupt flags at correct offset within the register */
    . H; w& {( [. w: z0 X# s- m
  29.     regs_dma->IFCR = 0x3FUL << (hdma->StreamIndex & 0x1FU);
    4 D! v; [% v" M+ v

  30. + y3 j8 S6 T0 W& M& f- l& F& @
  31.     /* Clear DBM bit */1 }3 q) k/ U+ c7 q- g' }
  32.     ((DMA_Stream_TypeDef *)hdma->Instance)->CR &= (uint32_t)(~DMA_SxCR_DBM);
    ; p" |- ^, x: N5 _( Z; u7 o5 S; I
  33. 3 G: n6 i. c6 |% @3 U# [( i* n) q
  34.     /* Configure DMA Stream data length */6 t; p$ o5 A- [) f6 M" t: ~+ l0 ~- ?
  35.     //这里设置搬用的目标数据长度' h8 r, F- L( k3 l( }, \
  36.     ((DMA_Stream_TypeDef *)hdma->Instance)->NDTR = DataLength;
    3 I+ Q& q8 H# w. r8 Q
  37. # Y! n6 u5 i1 @& B# @
  38.     /* Peripheral to Memory */
    ! Z  s1 }: s1 R. Q
  39.     //整个这个if判断是在设置DMA搬运数据的目标地址和源地址# @" M" Q/ ]. K; _
  40.     if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH), d6 N) V- p* s4 j2 Y4 D6 v1 m
  41.     {# |) U. {' \. L/ X* @
  42.       /* Configure DMA Stream destination address */: x& G6 `4 u; l9 f' {
  43.       ((DMA_Stream_TypeDef *)hdma->Instance)->PAR = DstAddress;
    $ t8 y9 R9 f- D& \2 ^' r+ w9 n8 x1 A% j

  44. & ?7 Z4 t" M' T9 m( v. c3 s7 T5 Y
  45.       /* Configure DMA Stream source address */$ ^" y: J7 v' l- N) j6 D1 h
  46.       ((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = SrcAddress;, Q. c( \( G/ s+ m
  47.     }/ E* G/ }8 S2 p  Q7 l8 p
  48.     /* Memory to Peripheral */
    ! h0 }2 ~8 Y/ U% O/ Z+ O# I( E; J
  49.     else9 p- F* r* P+ G% q  t6 b! p  L
  50.     {
    % r6 p- d2 g5 ~$ \7 }
  51.       /* Configure DMA Stream source address */
    ) ]4 q; T3 ]4 t' }0 v
  52.       ((DMA_Stream_TypeDef *)hdma->Instance)->PAR = SrcAddress;9 ^$ P$ i7 d+ t0 @0 a

  53. 3 s# r8 R- {, T% k
  54.       /* Configure DMA Stream destination address */, L& p" W" R3 |7 K( o
  55.       ((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = DstAddress;
    + b; P1 X. V  }% H( e
  56.     }( V( ~; e& C7 J
  57.   }
    4 f6 W2 k1 H4 b
  58.   else if(IS_BDMA_CHANNEL_INSTANCE(hdma->Instance) != 0U) /* BDMA instance(s) */
    & D! o4 G( b; v0 g" N9 M& c
  59.   {
    + ]& h: O" T4 U9 A& n: M
  60.     /* Clear all flags */
    $ G2 ?* c" h' v" \! Y: Q" B4 Y
  61.     regs_bdma->IFCR = (BDMA_ISR_GIF0) << (hdma->StreamIndex & 0x1FU);* \8 T: Q' K; Z6 N" }2 @
  62. ' @& d' d" K+ l" ?  H
  63.     /* Configure DMA Channel data length */
    : E4 j) I# {% y! H
  64.     ((BDMA_Channel_TypeDef *)hdma->Instance)->CNDTR = DataLength;! l4 o/ O( v$ |! c- Z, ]+ M

  65. & d4 g* t. G# M0 \  J7 g; U* W
  66.     /* Peripheral to Memory */
    - a6 x" x! ^* c4 a$ G
  67.     if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)* H" B" E( s1 e  A1 ?- W; T7 |
  68.     {0 {' {" e. h! N" n
  69.       /* Configure DMA Channel destination address */
    1 f2 G; P7 z, M& ~, }: f' ]
  70.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = DstAddress;
    " H5 C. b! Z7 h5 [7 [. t# ?2 r

  71. " [  ~1 L: }1 w# ~1 _0 a; N
  72.       /* Configure DMA Channel source address */  h: A. `( R8 m8 v
  73.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = SrcAddress;
    . K) D  j- T0 g6 ~! ?$ L1 f: Q; S
  74.     }9 U" h7 r9 K6 w# b) D' t$ g
  75.     /* Memory to Peripheral */
    1 v/ q* U0 d  m; P. U2 G
  76.     else
    7 k% @, N% M0 M" M( g* `8 I4 \/ v# H# e
  77.     {5 [/ I) e9 ]0 n( |4 u4 P
  78.       /* Configure DMA Channel source address */
    1 s, b& M3 E9 `- X5 r$ i1 X+ j
  79.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = SrcAddress;
    ( q6 u8 `$ O( W4 o, w' A
  80. 5 b8 T) t& C( q3 X6 R5 \% K3 F
  81.       /* Configure DMA Channel destination address */
    9 H% m6 D$ k; @+ j( d1 Z1 v
  82.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = DstAddress;2 f& E( P7 ?7 A5 `
  83.     }+ j$ k) ?1 z  J7 Y! }/ T# |* m
  84.   }1 \7 i! k6 o7 y5 i$ n/ Q9 {" z
  85.   else: L/ n1 M4 ]1 |' l/ c/ ?6 \& l6 f
  86.   {1 Z) E/ t9 b- v/ h6 K# v
  87.     /* Nothing To Do */% X. l4 E5 O# m/ b6 B" @0 A
  88.   }  
    : f# S5 z) p8 I7 _' E
  89. }
复制代码

: b: b; @1 {/ x0 t7 a各位同志你们自己看吧这个函数最主要的目的就是配置DMA寄存器。以上就是串口DMA接收函数中最重要的部分。好像没什么意义一样,因为我要用到其中的一点点东西,所以必须要分析源码。
8 L( T  e1 B- v7 H5 C9 Z/ {6 g/ D& t9 d# j' r
我们只是说了调用接收函数,参数里边指定了接收缓存,也指定了大小,似乎和我们的目标不符合,假设我们的DMA和串口之间的配置已经配置好了,那现在能做到的就是把数据收集到这个缓冲区里,可是并不能告诉主程序接收到了数据,和接收了多少,想要知道这个,有两种方法,一种是CPU定时去问DMA接收了多少数据,然后自己定义一个记录变化的变量,配合,另一种是中断方式,我们通过查询得知,DMA只有接收完成和接收半完成两个中断。& b1 U! @  L8 n5 e) c
- ^7 O* p+ F5 N' o; j, v' f
最最主要的串口的空闲中断不要忘了呀,这个可以告诉你,一帧数据接收完了,你可以根据这个中断去搞,接收了多少,在什么地方。
9 x: ]" U. E5 r5 Y
9 q, {# E3 e9 Q" o因为这个编辑器不知道咋回事,贴代码总是挂,上边那个函数就贴了我很长时间,很生气,所以我就无耻的把源码整到这里了,整个工程哦(暂时还没有上传)。
, p+ t5 x( T, `- F" P/ `$ D( n: t8 @
再试试贴代码吧,方便你我他,要积分的都无耻。改天
, g, V4 j8 h, g6 [& U& g" U* v3 R7 G
, q3 H6 v' k: t# {+ nuart.c文件就这么多代码,
# l0 r' o+ A. O6 _
" g3 T9 ?; f1 b$ i
  1. #include "Uart.h"8 h# S' S$ p# e
  2. #include "stm32h7xx_hal.h"  J& V  Q' [9 ~( e6 p6 G, Q& ~
  3. - F3 _0 E) ?2 `) I. X: Z
  4. #define RxBufSize   1024
    6 c+ ]& p/ F- L: Y. ]

  5. 8 `+ b# e3 u" k1 l: {% W5 r
  6. UART_HandleTypeDef hUart1 = {0};7 f4 ?! Y: q5 x2 d+ S3 T1 i
  7. DMA_HandleTypeDef hDmaUart1Tx = {0};
    $ H, p8 b$ x$ R- a! Y& _- K- Z4 T
  8. DMA_HandleTypeDef hDmaUart1Rx = {0};
    ; p: J- h' p4 M5 c& [

  9. " G' d* J# t( l1 j$ U5 U1 P
  10. //数组后边的那个限定跟你的内存分配有关 如果你的主RAM在512K的那个片内存就可以不加 这是AC6编译器用法8 \5 X; y! c; T. C0 H3 g/ _2 r
  11. uint8_t RxBuf[2][RxBufSize] __attribute__((section (".RAM_D1")));
    % \+ U* l) ?$ k% J3 }( \
  12. void (*Uart1RxCompleteCallback)(uint8_t *pData,uint16_t *Count);6 `3 F+ x0 [$ z$ m

  13. + c' b. X  z0 Z2 r, e& n% ~0 Z: B
  14. void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count)): k" Q. I% p3 M& w, T4 g
  15. {7 c: l: w5 J5 j" d" |7 B# K
  16. hUart1.Instance = USART1;
    ; n; \* `4 C# G9 l) R7 n
  17. hUart1.Init.BaudRate = BaudRate;4 I( D4 M* i6 k4 m
  18. hUart1.Init.ClockPrescaler = UART_PRESCALER_DIV2;
    " |+ }2 V$ a* Y% _& |
  19. hUart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    1 F& L8 a! s: e9 h
  20. hUart1.Init.Mode = UART_MODE_TX_RX;
    6 s: R; I; U; S% c
  21. hUart1.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;- @: z/ ~( J, P% W- \8 J/ ^5 p
  22. hUart1.Init.OverSampling = UART_OVERSAMPLING_8;
    3 Y4 P( O; z- e" F7 q
  23. hUart1.Init.Parity = UART_PARITY_NONE;
    % r  X- R$ R" i, C& R
  24. hUart1.Init.StopBits = UART_STOPBITS_1;
    - ]4 G9 T2 f* f) D0 E9 S( e# f
  25. hUart1.Init.WordLength = UART_WORDLENGTH_8B;
    ; ^- p3 g  J/ {+ ]) P
  26. hUart1.FifoMode = UART_FIFOMODE_DISABLE;& ?1 v8 m7 X9 T, k8 E
  27. 8 _% T' y+ s% q$ ^3 H( g; U
  28. HAL_UART_Init(&hUart1);
    2 _/ Z* m/ X, k( Q9 T7 n1 i

  29. 5 D1 t/ ]# y& ]6 \
  30. __HAL_RCC_DMA1_CLK_ENABLE();
    + B* }9 o8 H0 L5 {0 E3 U: a4 l) x
  31. 0 A- }# v- u* N- P
  32. hDmaUart1Tx.Instance = DMA1_Stream0;
      c& ^; J# S! j. [  \
  33. hDmaUart1Tx.Init.Request = DMA_REQUEST_USART1_TX;" d* q$ `4 u. m6 ?( U5 B! c
  34. hDmaUart1Tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    % J6 b1 q! N5 K1 r9 s) l
  35. hDmaUart1Tx.Init.PeriphInc = DMA_PINC_DISABLE;
    ) n- y/ e) y, U" m, Y- ]0 L0 e$ Z
  36. hDmaUart1Tx.Init.MemInc = DMA_MINC_ENABLE;; d8 q( K) t- j( W- H! I
  37. hDmaUart1Tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
      D% m" O$ y4 k1 {5 b7 B3 c" c
  38. hDmaUart1Tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    2 m% c# q' L$ Z. o( I' {3 }
  39. hDmaUart1Tx.Init.Mode = DMA_NORMAL;
    ' h8 o6 q' S- y
  40. hDmaUart1Tx.Init.Priority = DMA_PRIORITY_MEDIUM;
    & r- G0 B- t9 s8 q

  41. ; h$ Y+ N- [: S' t% F
  42. HAL_DMA_Init(&hDmaUart1Tx);0 i! \9 D  P9 L& l; R
  43. __HAL_LINKDMA(&hUart1,hdmatx,hDmaUart1Tx);6 C5 L# M5 O+ D2 M' I( ]) ^

  44. % W. V: T/ A/ c! M
  45. hDmaUart1Rx.Instance = DMA1_Stream1;
    ) r: T4 `/ j0 x7 r* K! G$ W
  46. hDmaUart1Rx.Init.Request = DMA_REQUEST_USART1_RX;% m4 G% K3 b! T- d6 e
  47. hDmaUart1Rx.Init.Direction = DMA_PERIPH_TO_MEMORY;) O8 o+ g. W3 V, `
  48. hDmaUart1Rx.Init.PeriphInc = DMA_PINC_DISABLE;
    , u# c. y9 A7 J- u$ G4 \
  49. hDmaUart1Rx.Init.MemInc = DMA_MINC_ENABLE;
    ) _  v; b& D3 p& g/ J- G' _
  50. hDmaUart1Rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    7 T' |) ?7 {9 H* h" {- t. `) W' |
  51. hDmaUart1Rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    & I) ]5 E( H6 O+ k, U( v; D
  52. hDmaUart1Rx.Init.Mode = DMA_NORMAL;; f5 U9 J/ f! M4 ]% F3 X' t- E
  53. hDmaUart1Rx.Init.Priority = DMA_PRIORITY_MEDIUM;
    4 u$ ^4 z- m0 @! `

  54. 2 ^- H0 m2 _5 c7 Q  K9 z8 p
  55. HAL_DMA_Init(&hDmaUart1Rx);9 V. V3 r. m+ b4 H& A- Z- e: r% h, f
  56. __HAL_LINKDMA(&hUart1,hdmarx,hDmaUart1Rx);
    ! ^; x' p' H5 B+ ~+ K0 o$ X

  57. 9 W7 R. C$ O& L  K
  58. HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);, n1 \5 k8 x( U4 m" X
  59. 9 g% e( n0 M+ f; j. O2 {
  60. __HAL_UART_ENABLE_IT(&hUart1,UART_IT_IDLE);
    ; d# o  Y  o5 S, C5 ^
  61. HAL_NVIC_EnableIRQ(USART1_IRQn);% V' ]8 b& o/ V: Q9 J
  62. HAL_NVIC_SetPriority(USART1_IRQn,14,0);
    . ^3 Y$ `" s  c3 ~/ E

  63. , [5 m3 i* n8 e6 ^3 U. ~8 Y( c* Z
  64. HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);//Tx! b: d! s* v9 r4 U
  65. HAL_NVIC_SetPriority(DMA1_Stream0_IRQn,14,0);
    1 ~$ }7 Z! |4 v
  66. & j. }. C6 f" N; L' c: C& ^8 |
  67. HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);//Rx; n* N; H  U3 p( \7 [( p; W
  68. HAL_NVIC_SetPriority(DMA1_Stream1_IRQn,14,0);
    3 Q& z5 N8 w# c
  69. 9 _2 b3 a# a' W; j+ {# L0 _
  70. Uart1RxCompleteCallback = RxCompleteCallback;4 b' y( Y/ |  ^8 S: ]
  71. }
    ) k: }* g4 m' k0 m, j, r: a. ?
  72. $ D5 _- i! v+ a" l
  73. void HAL_UART_MspInit(UART_HandleTypeDef *huart), N0 b! L$ H  L$ j
  74. {
    7 l! X1 h4 z, H; f& m/ {& o6 v
  75. if(huart == &hUart1)//串口1+ {/ u# x; \$ O' K$ o) m+ O
  76. {
    7 g. f8 e* N" d2 [; Z' e/ t; D
  77.   GPIO_InitTypeDef GPIO_InitStruct;  ?. \7 W% d1 U

  78. 3 _5 m; |: Q7 h& a; S; m. v
  79.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;3 a0 |6 G, @6 X1 m3 U* a5 f9 `
  80.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    * {) q8 w; [/ `+ B- }
  81.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
    , o5 P7 r! _3 j1 X" @7 s4 `
  82.   GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    : f: u6 I& v  q
  83.   GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_9;5 f$ ^: z  W, T& f6 Q' F3 [
  84. * e' J, T# _1 C8 V/ c
  85.   __HAL_RCC_GPIOA_CLK_ENABLE();+ b# Y# P& [; A! _& b0 Q  K
  86.   __HAL_RCC_USART1_CLK_ENABLE();
    5 g  j# U9 j9 ?* G

  87.   p2 T. S, @/ N" ?! Y+ ?
  88.   HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
    & Z+ t. R2 n) U
  89. }( A3 R' N* h1 {; A' p
  90. }
    ! f% w/ C* u: g- Z& U

  91.   h2 |0 v: ?/ U: l
  92. void Uart1TxData(uint8_t *pData,uint16_t Count)- }  |' L, R! o0 n- V; _/ U+ ]0 c8 R) I
  93. {6 ^: e2 }% P, E8 \: {
  94. if(Count)
    " F, b: l2 `" I. Q/ H$ j
  95.   HAL_UART_Transmit_DMA(&hUart1,pData,Count);% I. b( y% u5 d$ C; Z& B( {
  96. }" g2 t0 m0 A0 l! F. ?% ^; y( H

  97. 0 e" Y' ]- b& M+ s3 {0 p
  98. void USART1_IRQHandler(void)/ ?" F, D5 R' |& D5 q- h. M2 p* l" U
  99. {
    0 I& F, J# {. M
  100. if(__HAL_UART_GET_FLAG(&hUart1,UART_FLAG_IDLE)), e+ }3 C% G+ G
  101. {
    ' w: v+ J& W. R9 ?/ V$ c
  102.   static uint16_t count;
    1 X) U' L" D. P* ~7 P
  103.   __HAL_UART_CLEAR_IDLEFLAG(&hUart1);+ f( [  g4 w8 r- s
  104.   if(Uart1RxCompleteCallback)# d; V( T2 b+ V# `0 _  [; t: j
  105.   {! m% @* ~% a4 J1 V
  106.    hUart1.RxState = HAL_UART_STATE_READY;4 [. h3 v" L$ H0 Y  o+ a+ N6 g2 s
  107.    hDmaUart1Rx.State = HAL_DMA_STATE_READY;
    ! g6 X, Y( Y5 L7 V; O- R( H
  108.    HAL_UART_RxCpltCallback(&hUart1);: g& S* ~- i; J& y5 o! C. [# M
  109.   }
    % I/ x, d* {: ^; K
  110. }
    8 z5 k* P+ ~& @! t7 y
  111. else3 m* D* w# Y5 u
  112.   HAL_UART_IRQHandler(&hUart1);
    2 U# }  ?' F9 z
  113. }$ G$ n( _, z( `

  114. 6 a- H9 i, ?4 k: b7 R+ t6 y$ ]
  115. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)( I2 D% A/ l3 f
  116. {
    ) R) m& ]$ K- Y
  117. if(huart == &hUart1)  d. N0 D8 e5 h* z5 _6 j6 ?- q
  118. {
    2 [0 o% n/ Z# Q  |' }2 o1 |" E
  119.   static uint16_t count;! q; E7 p, ]; @4 `6 y' E
  120.   count = RxBufSize - __HAL_DMA_GET_COUNTER(&hDmaUart1Rx);) s) k1 U8 u- f3 {7 N4 P6 Z; P3 H
  121.   if(count == 0)return;) n. t5 L4 q, w# e6 _
  122.   hDmaUart1Rx.Lock = HAL_UNLOCKED;
    8 K' q( S- U) \9 ?' [, Y4 m
  123.   if(huart->pRxBuffPtr < RxBuf[1])# U$ D, n( W# J
  124.   {
    ; \4 v  K) W$ V# Y, _+ C! u9 X
  125.    Uart1RxCompleteCallback(RxBuf[0],&count);1 |+ Q- Y9 l2 G7 S4 N
  126.    HAL_UART_Receive_DMA(&hUart1,RxBuf[1],RxBufSize);$ q+ e* F8 W6 p( `
  127.   }
    ' _; z6 `% E/ g+ Z' f( W+ b. j
  128.   else8 N) J4 c+ z1 o, ?# O7 U! |2 {* w
  129.   {# P" p8 V, B4 [) B
  130.    Uart1RxCompleteCallback(RxBuf[1],&count);
    0 U: {6 F! T6 ?" n- E5 s2 r
  131.    HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
    & @+ U" b3 J" ]7 f; P$ _
  132.   }
    . i& G: _- k4 c$ s9 s
  133.   hDmaUart1Rx.Lock = HAL_LOCKED;+ t, n1 g' ^: e2 \
  134. }5 ~& S- T/ c5 l3 {; t' l
  135. }
    - _7 O8 H0 E+ A% ]+ p# \
  136. ( ?" ^- Q* _) `* O- R
  137. void DMA1_Stream0_IRQHandler(void)
    # ?$ }* q6 X6 O" b2 h2 C
  138. {. r% s) a8 l) e6 u# T4 ?
  139. HAL_DMA_IRQHandler(&hDmaUart1Tx);
    ( L  l1 A% o) |! T" c2 B' C
  140. }
    8 [  F7 Q6 @( J" c
  141. % H2 H9 P4 c& F( c; E4 N
  142. void DMA1_Stream1_IRQHandler(void)
    / ^8 h$ r2 u' O' s$ Z  E* @
  143. {. \( B) S3 ]0 b4 S( J! a
  144. HAL_DMA_IRQHandler(&hDmaUart1Rx);
    ' F: {6 E- _  r; K
  145. }
复制代码
( T0 Y- Y8 c; d4 R  q
这个是Uart.h文件
, C7 t, h( r0 r* T9 g4 h/ Y1 ?! r, t+ ?* L( @
  1. #ifndef __Uart_H_" f$ b* s# d, c) _" n
  2. #define __Uart_H_" t2 K, {: q" C2 z$ G+ ]5 B

  3. - |$ d; n5 m3 v; l/ U7 ^+ |" q8 b3 X3 K6 g
  4. #include "stdint.h"
    1 c) F4 \* V' k1 i# H1 B

  5. & |8 L. C% w' v' [' s5 @/ M/ C
  6. void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count));: {8 z" ^  g  I8 y
  7. void Uart1TxData(uint8_t *pData,uint16_t Count);
    6 x/ r+ q# r# w) Y

  8. " D3 p. p% k8 I
  9. #endif /* End __Uart_H_ */
复制代码
( S" f" c6 f$ l% s% n: p
这个是应用文件,实现了把收到的数据在发回去的功能。4 w' }: `9 f1 {- }6 M" u7 K+ d8 E( f
- k) n/ R9 A+ y9 @4 k6 N. L
  1. #include "Uart1Task.h"3 b& A# P2 ]$ J6 H' P# ]. x
  2. #include "limits.h"//ULONG_MAX
    / x( a5 b( t& N* M1 q4 J
  3. #include "Uart.h"8 `4 o! m+ P- H+ x" }# `
  4. #include "string.h"
    0 c4 P0 V6 J7 F( f8 F: o0 G  P
  5. #include "SystemConfTask.h"
    , D: E" |0 Z" U7 Z- {/ P6 F5 ?6 `1 j
  6. ) @' k5 L2 {! x, ~
  7. #define Uart1RxCompleteFlag  0x01
    1 u3 b9 u( w7 h6 R+ z) H

  8. 8 I' a* V$ B) T2 Y
  9. static uint8_t *Uart1RxData;
    " G0 _! f) i  G8 w, D+ d
  10. static uint16_t Uart1RxCount;
    0 D2 G. H/ z& R$ T* W
  11. TaskHandle_t Uart1TaskHandle;' ^3 N0 [: D5 N+ D! g5 ?. L* p% @
  12. ; l. l% }0 X9 K* e2 l
  13. void Uart1RxIRQ(uint8_t *pData,uint16_t *Count);
    1 @, J* h. F2 s' j4 G. b+ v/ a
  14. + c9 a$ B0 u6 p' y* R  P# n, }
  15. TaskHandle_t *GetUart1TaskHandle(void)
    2 w  c% g1 G, S1 I
  16. {' b' O1 o0 O9 q2 s
  17. return &Uart1TaskHandle;
    % V* |1 Z4 }/ ]
  18. }
    & c  P8 s8 D3 `1 U
  19. ) W7 N- H2 u% {: C% \/ g
  20. void Uart1Task(void *pvParameter)+ s" t) A# U5 i5 p$ O
  21. {0 H" e4 V* |; E
  22. Uart1Init(115200,Uart1RxIRQ);, V* g: H/ [5 o+ O$ j
  23. while(1)
    9 n0 j" ^  ?& q: @: _8 H. m" m8 d
  24. {
    . w6 ?8 J) x8 X. [
  25.   uint32_t NotifyValue = 0;
      a8 h& q7 J- c/ H
  26.   xTaskNotifyWait(pdFALSE,ULONG_MAX,&NotifyValue,portMAX_DELAY);
    + l- T: c0 |' w- @
  27.   Uart1TxData(Uart1RxData,Uart1RxCount);
    7 P* d7 X  E9 U' G7 Z# v
  28. }
    ! g5 T' j+ X) @4 v
  29. }7 r& ^  Z& d6 M6 a5 M

  30. ; s+ W2 B4 f7 t
  31. void Uart1RxIRQ(uint8_t *pData,uint16_t *Count)
    . [6 r$ I3 H) X9 s/ K0 }
  32. {
    1 N* m! O3 B8 f/ q+ R
  33. Uart1RxData = pData;
    . n. c  P2 g, r* g8 C1 s0 T" n+ G, F
  34. Uart1RxCount = *Count;
    * u! [4 {; G& h5 |
  35. BaseType_t pxHigherPriorityTaskWoken;
    + o% ?% d, w4 l
  36. xTaskNotifyFromISR(*GetUart1TaskHandle(),Uart1RxCompleteFlag,eSetBits,&pxHigherPriorityTaskWoken);6 e9 O6 }4 q5 T0 l' f2 d1 l  W7 x
  37. portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
    4 [) Z6 E# H# D4 u
  38. }
复制代码
" X0 U" A; W  B6 \5 D2 W/ F
串口驱动里做了一个双缓冲的,防止大量数据出问题
+ w- ]. ?% D% d6 I' L. V' x
4 {# R. V9 Z, h$ G
5 i2 K& ?( j" `6 u" ~
收藏 评论0 发布时间:2021-12-25 10:14

举报

0个回答

所属标签

相似分享

官网相关资源

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