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

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

[复制链接]
STMCU小助手 发布时间:2021-12-25 10:14
中断接收方式,最大的缺点就是中断过于频繁,为了解决这个问题那就把DMA搬过来,它不就是专门搬用数据的嘛,不用多可惜。
6 p* e0 H" T% O% v6 g+ p+ G: p7 I/ `; m7 A
首先我们需要大致了解,DMA和外设传送数据,例如串口,我们希望,当一帧数据接收完毕了,有个东西告诉主程序,串口接收到了一帧n个字节的数据存在某个地方,接收过程中你丫别打搅我。
# u) E- ~0 a( ?/ v* U9 w. q5 W" \; X  C+ x7 T% t! d6 ^
DMA就能胜任这个工作,他可以以中断的形式告诉你这些信息。相比中断接收方式,是不是省了很多中断,主程序被打断的次数也就少了。
9 j: p3 i( j2 `6 \& {. O
. _, ]& c+ p' R! O( `8 B  W' ?( m还是按照上一篇形式大概看一下,HAL库中DMA是怎么和串口配合的。1 f9 O$ a9 S4 L7 u: r

" D3 N- w' F2 X6 G0 y6 s
  1. /**! _) Y: h, K% N" _3 P# ?* |
  2.   * @brief Receive an amount of data in DMA mode.
    . o$ b/ b% N6 A2 q+ E$ |
  3.   * @note   When the UART parity is enabled (PCE = 1), the received data contain5 x5 d; d# x' [% Q9 R3 ?
  4.   *         the parity bit (MSB position).! }3 R8 e5 |% b/ W
  5.   * @param huart UART handle.6 c! R2 w# W5 q9 ]" P  F; L4 O* ]
  6.   * @param pData Pointer to data buffer.3 D% v- [2 m/ Z0 ~4 Q9 D9 y
  7.   * @param Size  Amount of data to be received.
    9 H) S, X* c7 S8 a3 K
  8.   * @retval HAL status
    4 [6 Y6 g" ^. E/ Q# W
  9.   */
    8 `3 ~3 d% ?. g6 U! q5 R0 t
  10. HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
    / W8 m% Y. c+ d+ J
  11. {( f- p% `9 u* r# w' Q' f
  12.   /* 其他关系不大的代码省略 有兴趣可以自己看 下同 */
    / S0 h, l( q# K* _# \5 v8 ~
  13.   //1.检查参数 判断串口接收状态为就绪 把缓存区参数传递到串口句柄  修改某些状态
    2 p1 ?+ l  p1 R
  14.   //2.判断和串口句柄关联的DMA句柄地址不为空  然后给DMA句柄注册一些回调函数
    + ?7 k/ l0 G8 F2 g5 z8 |; Z/ X
  15.       /* Enable the DMA channel */
    : B1 A2 Y  ?  \+ ~! x: k
  16.       if (HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->RDR, (uint32_t)huart->pRxBuffPtr, Size) != HAL_OK). W, w1 W9 g# q! @8 _4 r
  17.     {7 \7 @  H% W7 r0 @1 p; _9 T) A, F+ T9 H. N
  18.       ......
    ) t- I0 @. F  R. ^8 J5 r8 V# T7 a; z
  19.     }
    + Z- Y1 C4 l) b" k
  20. }
复制代码
+ A* T7 n, g! j2 H
HAL_UART_Receive_DMA这个函数里最主要的就是调用了HAL_DMA_Start_IT这个函数,你看他连参数都没怎么变,就把句柄换了,其他三个原封不动的传递过去了。所以函数内其他内容几乎不用考虑了。直接往下看这个函数。; R. F. [* ]( O4 K
! ~/ x# W9 u* m
  1. /**# v. e* e# R! }/ ]( P; V+ ~
  2.   * @brief  Start the DMA Transfer with interrupt enabled.# q+ ^; O, W8 S, j- x
  3.   * @param  hdma:       pointer to a DMA_HandleTypeDef structure that contains
    / h3 M' D# E  a1 O3 Y( t# R
  4.   *                     the configuration information for the specified DMA Stream./ I, g% S; B& y% U
  5.   * @param  SrcAddress: The source memory Buffer address4 U# ]/ W( p/ Z& H+ U
  6.   * @param  DstAddress: The destination memory Buffer address  P9 j0 _3 G' _7 j" b1 w) n
  7.   * @param  DataLength: The length of data to be transferred from source to destination- d5 ?+ D" f  F" q8 X' h% f
  8.   * @retval HAL status
    9 P6 W6 l- A) `* A
  9.   */
    . q! D8 b; x; ^; x  I! t/ j( H2 J
  10. HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)' x7 k. Y6 p* X$ `. Y+ D
  11. {
    4 S# |* H8 x9 y* i9 L9 n* f
  12.   //1.检查参数 给句柄上锁 判断状态 只有在就绪状态下才允许配置$ L. E: G% X. y5 Y: S3 N
  13.   //2.判断就绪状态
    * P8 U. I0 ]1 P2 x/ ?
  14.   {
    # p4 G! e% P+ u) {) k' e' {  e
  15.     ......
    & e6 j1 W/ s; j9 D
  16.     /* Configure the source, destination address and the data length */
    4 A1 o9 j* Y+ h
  17.     DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);
    - m) U. n) m2 V5 x5 f
  18.     ......) V. S# r' }9 [
  19.     //这里会开启一堆中断  完事要用  暂时可以不关心
    % l- O1 H. X/ U" c  Z
  20.   }5 r' \( r) h% O; D( T& e8 R5 ~
  21. }
复制代码
, K& u9 ~" L  C9 I& t6 }& {7 j
上面这个函数也差不多还是那个意思,都懒的看了,主要是调用了DMA_SetConfig这个函数,追踪过去,它才是真正配置寄存器的函数,HAL库就是这么繁琐。$ @/ i) O) U8 x3 N* o6 D
1 F& \& p+ X- _/ n2 b# g) `. k
  1. /**2 t" y. g* M) B
  2.   * @brief  Sets the DMA Transfer parameter.3 V# y2 i4 z5 Y( p) ~% J
  3.   * @param  hdma:       pointer to a DMA_HandleTypeDef structure that contains+ D6 i  f& F; e/ Q
  4.   *                     the configuration information for the specified DMA Stream.* z- ?7 P& M2 u" Q6 x7 P
  5.   * @param  SrcAddress: The source memory Buffer address6 Z; z4 R2 E+ {" c1 S
  6.   * @param  DstAddress: The destination memory Buffer address3 n9 T! V- X9 V) m4 D
  7.   * @param  DataLength: The length of data to be transferred from source to destination5 Y/ v' u  ^8 Y$ k8 O
  8.   * @retval None
    : T. j0 }2 l+ ~/ N/ h1 ~
  9.   */
    " d8 @: a# [8 x
  10. static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
    4 k- o* ?: l5 ^6 k1 F1 U, `& ]
  11. {
    # I1 m3 G( h2 o* E  F) C& N0 w
  12.   /* calculate DMA base and stream number */
    4 T* z8 j9 T0 T/ g) r/ Q# ^4 `
  13.   //获取DMA控制器对应流的基地址( m2 P: }" U$ h' e+ }4 [
  14.   DMA_Base_Registers  *regs_dma  = (DMA_Base_Registers *)hdma->StreamBaseAddress;6 R4 [& ?$ s6 r$ R! n2 t' q
  15.   BDMA_Base_Registers *regs_bdma = (BDMA_Base_Registers *)hdma->StreamBaseAddress;
    ; M& K. f0 b! k( w% G6 a& Y; q
  16. 2 d7 c5 t7 s3 ~" G) h# _9 j
  17.   /* Clear the DMAMUX synchro overrun flag */! |: D7 X, z6 s9 T. ?3 D- H
  18.   hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask;  M" [5 r. _1 J% B; z
  19. + f" v) A  Y3 M
  20.   if(hdma->DMAmuxRequestGen != 0U); q# W/ I/ b3 \" Q
  21.   {# }/ l' |; }: z9 q/ r" D
  22.     /* Clear the DMAMUX request generator overrun flag */0 F! v: r3 |0 C+ A$ e% E5 J+ y
  23.     hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask;: I* g4 q* H5 V! X; P0 P: |* {
  24.   }
    0 Q) p7 _) |  b9 W  @; }4 p" U

  25. ! w! n" U* r4 h
  26.   if(IS_DMA_STREAM_INSTANCE(hdma->Instance) != 0U) /* DMA1 or DMA2 instance */+ @. C4 G' S$ B& V- I1 M* d
  27.   {+ I) M* Y+ Y* \7 S: K
  28.     /* Clear all interrupt flags at correct offset within the register */
    - X- d# l4 l: `! ?% S
  29.     regs_dma->IFCR = 0x3FUL << (hdma->StreamIndex & 0x1FU);' `' J6 l3 t! Z

  30. ; t; D! v1 t" h+ Q! n
  31.     /* Clear DBM bit */2 n) M$ Z) K2 v' `
  32.     ((DMA_Stream_TypeDef *)hdma->Instance)->CR &= (uint32_t)(~DMA_SxCR_DBM);
    1 Q7 I7 R/ u9 r$ E6 U% k

  33. & ^. X. g1 f3 i, \' U+ o$ C3 C4 h
  34.     /* Configure DMA Stream data length */
    ; R5 v" {2 q( h/ E6 a
  35.     //这里设置搬用的目标数据长度" ^1 i+ f- \7 K/ }7 \0 ]7 b9 w& K
  36.     ((DMA_Stream_TypeDef *)hdma->Instance)->NDTR = DataLength;
    5 h6 k, R$ i+ j* j: w2 x- Y, d. M
  37. 5 a7 j* X" x1 U
  38.     /* Peripheral to Memory */
    ! J! N& u) D- A  e( [
  39.     //整个这个if判断是在设置DMA搬运数据的目标地址和源地址: w- x' I5 i3 E. @
  40.     if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
    - K: ^0 q5 O: `4 x1 c- _$ O
  41.     {6 M& w- e6 }& w" h
  42.       /* Configure DMA Stream destination address */* [# c, w' C; p5 Z) a; [/ N1 h6 G( d
  43.       ((DMA_Stream_TypeDef *)hdma->Instance)->PAR = DstAddress;# Z9 o5 Y' D5 H1 [9 s" ]

  44. - v/ W9 ^" ?; K6 T/ c+ L  n
  45.       /* Configure DMA Stream source address */( }3 |- `: C  I
  46.       ((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = SrcAddress;
    ' ]* h$ k1 t# A) s" `* R
  47.     }) x/ }+ {. l1 `# _/ H& m6 S
  48.     /* Memory to Peripheral */# _9 Q. z3 u% O2 `0 x+ J  N/ i
  49.     else: n7 d3 \, f9 @2 C: n
  50.     {- ]* Y9 `: Y7 [" H) @! {1 c8 x
  51.       /* Configure DMA Stream source address */
    * \! y7 W6 ~. u: C3 ~/ }& G
  52.       ((DMA_Stream_TypeDef *)hdma->Instance)->PAR = SrcAddress;# d7 _- O8 S/ H' a( k
  53. , k. _5 Z* _  F4 ^
  54.       /* Configure DMA Stream destination address */6 R; @+ E( Z) s' n9 O. X
  55.       ((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = DstAddress;
    & O3 v: F3 a0 o8 t, |  J; @* U6 J
  56.     }1 b" A5 P9 g2 v# J' t/ U3 P
  57.   }+ \& \) ^2 F. e8 }+ T# |: m) |
  58.   else if(IS_BDMA_CHANNEL_INSTANCE(hdma->Instance) != 0U) /* BDMA instance(s) */" U- J0 q; M' u) J
  59.   {1 K3 ?8 n, _0 X- |: ~
  60.     /* Clear all flags */
    5 n) t4 [7 T$ O2 ?
  61.     regs_bdma->IFCR = (BDMA_ISR_GIF0) << (hdma->StreamIndex & 0x1FU);
      Q" _/ o2 S2 H( T
  62. 6 f' n# X# _+ j, h
  63.     /* Configure DMA Channel data length */
    7 _- {$ n% I9 r+ x9 n0 g
  64.     ((BDMA_Channel_TypeDef *)hdma->Instance)->CNDTR = DataLength;
    2 g" Y9 t. j# \. S/ Y+ L) p

  65. ! }0 h  e: s& ~9 F" }
  66.     /* Peripheral to Memory */
    ; s0 M" e$ F) a
  67.     if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)" z/ u! r* a7 A# F% h
  68.     {
    2 {& _3 y, |- L
  69.       /* Configure DMA Channel destination address */
    & L9 J6 W4 V3 i! K( @% Y+ l
  70.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = DstAddress;
    $ e: e, ]8 j1 a# Y/ d" Q

  71. * [! S+ C- f+ s, ^$ \9 S3 u
  72.       /* Configure DMA Channel source address */
    9 c2 i8 Q3 G: @: @- |
  73.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = SrcAddress;6 p' K& H3 D  c1 i; f' v# E
  74.     }7 n' r: t* e4 p% _
  75.     /* Memory to Peripheral */
    # y+ L6 a# S6 J/ Z! _  J
  76.     else' Q6 \& U* l4 e: x" R
  77.     {: t3 V" P1 V, |+ A! ]  Y$ h
  78.       /* Configure DMA Channel source address */% G- H5 r# l" Q% U
  79.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = SrcAddress;
    1 \4 {9 P- O& G6 G

  80. ( d+ }" X2 d! o( a& u6 j1 ]" U: X7 p  d
  81.       /* Configure DMA Channel destination address */
    + o6 a3 Z8 L7 q# g0 ^/ d
  82.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = DstAddress;
    9 `/ a2 |# ~3 g$ n/ d
  83.     }+ e# _& ^4 a0 p
  84.   }
    5 C" b" c' O( B3 X' @
  85.   else9 @; T; V/ C  E+ k
  86.   {; |4 k4 m' k! N* t
  87.     /* Nothing To Do */
    - w0 ~  \/ D* O4 U
  88.   }  # M8 y" Y5 W4 v* F$ E  K
  89. }
复制代码

# T! @9 Y" G+ h7 G各位同志你们自己看吧这个函数最主要的目的就是配置DMA寄存器。以上就是串口DMA接收函数中最重要的部分。好像没什么意义一样,因为我要用到其中的一点点东西,所以必须要分析源码。
, i' j2 E7 O* X8 L: M. r6 F
" s4 D' c, v. r+ E; `+ h我们只是说了调用接收函数,参数里边指定了接收缓存,也指定了大小,似乎和我们的目标不符合,假设我们的DMA和串口之间的配置已经配置好了,那现在能做到的就是把数据收集到这个缓冲区里,可是并不能告诉主程序接收到了数据,和接收了多少,想要知道这个,有两种方法,一种是CPU定时去问DMA接收了多少数据,然后自己定义一个记录变化的变量,配合,另一种是中断方式,我们通过查询得知,DMA只有接收完成和接收半完成两个中断。; `+ r) W, I2 V3 |# a0 G
2 D4 X" [" i1 D/ c  _. V
最最主要的串口的空闲中断不要忘了呀,这个可以告诉你,一帧数据接收完了,你可以根据这个中断去搞,接收了多少,在什么地方。1 v- h- m( y" J, |; @7 P, `+ ~

/ e) k8 L0 K9 R5 B0 ?因为这个编辑器不知道咋回事,贴代码总是挂,上边那个函数就贴了我很长时间,很生气,所以我就无耻的把源码整到这里了,整个工程哦(暂时还没有上传)。9 z1 x. y' h% Z

. |+ s6 P8 s5 G3 e再试试贴代码吧,方便你我他,要积分的都无耻。改天7 h5 X, P! ]; T+ r: y) a2 z1 ?

' K8 o; P! I8 R# }, M+ Vuart.c文件就这么多代码,8 u9 M# ]4 Z0 |! j% |

. J! ?8 q( }1 `1 x/ t3 o8 s! Q
  1. #include "Uart.h"( `, w* Q2 @+ U
  2. #include "stm32h7xx_hal.h"
    9 T( Q- X. s9 ?. O9 o

  3. 3 c) @. k: [" j: g- Z
  4. #define RxBufSize   1024
    5 C0 d+ f+ u' ]$ ~
  5. ; d9 _. U2 G. T- E% P
  6. UART_HandleTypeDef hUart1 = {0};+ b4 v2 P' S3 }: y6 `
  7. DMA_HandleTypeDef hDmaUart1Tx = {0};
    ) W- M4 Y1 N# a$ i- D5 l3 l: i
  8. DMA_HandleTypeDef hDmaUart1Rx = {0};0 b  V/ r+ ]$ v5 A% w: t

  9. / o5 H  S* m6 i
  10. //数组后边的那个限定跟你的内存分配有关 如果你的主RAM在512K的那个片内存就可以不加 这是AC6编译器用法
    2 D  d( b# \2 d0 [2 c
  11. uint8_t RxBuf[2][RxBufSize] __attribute__((section (".RAM_D1")));- e8 C9 E" ]2 K
  12. void (*Uart1RxCompleteCallback)(uint8_t *pData,uint16_t *Count);" Q0 E& N) y" o! v# r) n
  13. 8 ^9 s% A* W* M! J5 o/ @
  14. void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count))
    4 z; R- N4 p0 r$ k: M8 h
  15. {
    ) P* ]8 U' A0 ^" B
  16. hUart1.Instance = USART1;
    ' D$ P2 @) T- X% ]# A9 i
  17. hUart1.Init.BaudRate = BaudRate;
    3 \  z3 }2 S, t3 e, z4 D- r
  18. hUart1.Init.ClockPrescaler = UART_PRESCALER_DIV2;
    3 o& [5 Q$ w; P3 k6 d. Z
  19. hUart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;3 N" Q* H3 _+ A5 K3 y, i
  20. hUart1.Init.Mode = UART_MODE_TX_RX;
    ! w! f/ k9 C7 I3 q; \
  21. hUart1.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;$ E7 d+ N  O$ U0 D8 I3 B
  22. hUart1.Init.OverSampling = UART_OVERSAMPLING_8;
    & ?+ |( f8 h: x, m8 V
  23. hUart1.Init.Parity = UART_PARITY_NONE;
    % B: l/ B( `- H% f& y
  24. hUart1.Init.StopBits = UART_STOPBITS_1;
    1 W& C; R1 h! D% |3 H0 m
  25. hUart1.Init.WordLength = UART_WORDLENGTH_8B;
    & K* v; x" i4 R8 g2 }+ Q
  26. hUart1.FifoMode = UART_FIFOMODE_DISABLE;
    / t6 Y$ {9 i; {5 I

  27. 6 k) \, n! ]" ~0 x, x2 F
  28. HAL_UART_Init(&hUart1);
    / M$ u1 [- \& D+ I' g  \

  29. . i2 ]9 |- P5 ]# R( ?" C
  30. __HAL_RCC_DMA1_CLK_ENABLE();& K( I: Z, H5 ]1 H9 i$ n- r

  31. ) G. m# F; I( Y! M0 }- s
  32. hDmaUart1Tx.Instance = DMA1_Stream0;- `6 r7 j- Y2 z$ ^1 f! r
  33. hDmaUart1Tx.Init.Request = DMA_REQUEST_USART1_TX;
    ) d, U% b. k' L/ M- H" w6 t5 g
  34. hDmaUart1Tx.Init.Direction = DMA_MEMORY_TO_PERIPH;7 C/ B/ l+ E$ R1 c6 J) O
  35. hDmaUart1Tx.Init.PeriphInc = DMA_PINC_DISABLE;7 u8 T1 k; p5 h6 v9 E
  36. hDmaUart1Tx.Init.MemInc = DMA_MINC_ENABLE;7 a2 U5 `/ ^" I$ ?4 X* f
  37. hDmaUart1Tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    5 ]+ d4 v6 f9 n* ]8 q
  38. hDmaUart1Tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;3 Z! }3 Z( x1 h9 f  x
  39. hDmaUart1Tx.Init.Mode = DMA_NORMAL;, Q% i1 {& K5 F
  40. hDmaUart1Tx.Init.Priority = DMA_PRIORITY_MEDIUM;+ Q) e/ W1 U* _) T; o
  41. * C/ H# n' \8 j3 Q/ z3 g
  42. HAL_DMA_Init(&hDmaUart1Tx);: M& B) `! C# Y* W1 }) I
  43. __HAL_LINKDMA(&hUart1,hdmatx,hDmaUart1Tx);
    1 C% P6 k4 [4 ~/ e  R
  44. $ O  Z: f! K3 P* ?
  45. hDmaUart1Rx.Instance = DMA1_Stream1;
    % q% O1 E2 j% M+ ?! Y4 h
  46. hDmaUart1Rx.Init.Request = DMA_REQUEST_USART1_RX;
    6 h8 p6 H( E  t  s3 C0 O
  47. hDmaUart1Rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    ( G" k2 s8 _7 C. [
  48. hDmaUart1Rx.Init.PeriphInc = DMA_PINC_DISABLE;4 u6 b" W+ \1 G" U6 h8 C' A) q- g
  49. hDmaUart1Rx.Init.MemInc = DMA_MINC_ENABLE;
    ( }9 l0 u- ^) e/ F
  50. hDmaUart1Rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    ; {+ c, E$ t( B2 S+ }, G
  51. hDmaUart1Rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;: {  A7 T5 }, q: n& W6 a% v
  52. hDmaUart1Rx.Init.Mode = DMA_NORMAL;
    ' D' S+ C; i1 t, |+ O) _
  53. hDmaUart1Rx.Init.Priority = DMA_PRIORITY_MEDIUM;# Z' y. H" E9 \* [( C
  54. / R8 {$ g( k& b. [9 h
  55. HAL_DMA_Init(&hDmaUart1Rx);0 b1 B/ k# D% d6 e' W
  56. __HAL_LINKDMA(&hUart1,hdmarx,hDmaUart1Rx);7 N. Q; I7 S: s# m

  57. ) y8 h5 k! ~; o8 I" c5 e6 G1 C
  58. HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
    1 f& J) X/ ^' M

  59. ; O2 B3 m! P% V( J0 K1 }. w4 D
  60. __HAL_UART_ENABLE_IT(&hUart1,UART_IT_IDLE);
    9 p! V9 c+ I; @
  61. HAL_NVIC_EnableIRQ(USART1_IRQn);2 U7 o3 [$ |' z  F% l4 j# ]' z
  62. HAL_NVIC_SetPriority(USART1_IRQn,14,0);2 o4 s* D% v- F* G* {

  63. 0 }% K: v, Z* m  ~$ h) P- p4 h7 U
  64. HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);//Tx
    3 a8 E+ g0 M5 E" p  e4 g: {' t: L
  65. HAL_NVIC_SetPriority(DMA1_Stream0_IRQn,14,0);
    / @9 h* H5 z5 w/ I, o& z5 c
  66. 2 p! x$ U& ~- Z& ~  b( E
  67. HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);//Rx
    # P6 o# t" s2 \
  68. HAL_NVIC_SetPriority(DMA1_Stream1_IRQn,14,0);2 G! C, X- n6 B0 O7 N) N. V# ?+ R) W
  69. 3 M) q* J: h/ z8 k$ p, ^9 q+ H! N: x
  70. Uart1RxCompleteCallback = RxCompleteCallback;0 b8 O5 G. M2 [" e# q/ X. Q' H
  71. }
    $ @2 {$ }3 }0 P! J

  72. & \9 n# v& J* w& a( e
  73. void HAL_UART_MspInit(UART_HandleTypeDef *huart)
    ( h- R' w; i' P8 G- D9 t. _: _
  74. {
    9 h+ A9 ~. z! n0 s
  75. if(huart == &hUart1)//串口1
    1 ^3 p) e1 Y+ T" w5 V; S
  76. {
    - Z6 |0 T# {2 |, M4 m8 ]" ~0 C" G
  77.   GPIO_InitTypeDef GPIO_InitStruct;' C, D) u- Z0 S6 D2 W$ I

  78. . G) W. Q+ f% G
  79.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;: f# M' P# Y2 a0 @0 s
  80.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    $ q6 a; r# X7 T2 X1 Y7 m5 J
  81.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
    + D! b5 T$ z/ S4 y
  82.   GPIO_InitStruct.Alternate = GPIO_AF7_USART1;) r: O) e7 t& o# V
  83.   GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_9;
    8 k; r9 O9 H5 d" r1 `& o/ q

  84. / u- J; ^. W9 a0 X: O9 w+ W
  85.   __HAL_RCC_GPIOA_CLK_ENABLE();+ ~9 o) P$ {0 P
  86.   __HAL_RCC_USART1_CLK_ENABLE();
    % T- ~. w/ k. e

  87. : o8 ~# N- {& u7 n% [9 w( d# D, b
  88.   HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);+ v' `8 }, ^+ T& P$ t: p+ h
  89. }! V/ ^* k1 a! `1 b$ u
  90. }
    8 {8 h. L8 C) |6 Y9 i7 O2 ?

  91. ) \- Z* R' P' h1 _& \
  92. void Uart1TxData(uint8_t *pData,uint16_t Count): Y+ [5 O; w! K8 t/ y$ W
  93. {
    & t9 l, g  |% G6 |6 Z1 P
  94. if(Count)
    % \- S$ m4 m, L5 H' g. S$ y7 H
  95.   HAL_UART_Transmit_DMA(&hUart1,pData,Count);/ p/ G/ h( ~# r6 O
  96. }
    4 p1 b/ \; c( _6 U" y& @
  97. 2 j, Y7 |. g$ L/ ]6 `0 p2 f, j
  98. void USART1_IRQHandler(void)
    * a" K2 ^% \2 E/ u5 I8 y1 Q
  99. {
    9 \0 j, L: P1 O& B
  100. if(__HAL_UART_GET_FLAG(&hUart1,UART_FLAG_IDLE))
    1 n% [) u/ u8 g( p1 v7 W* g( v
  101. {
    9 c% K/ g. ?3 A3 X2 y; b
  102.   static uint16_t count;+ z3 A* F. m: ], V
  103.   __HAL_UART_CLEAR_IDLEFLAG(&hUart1);
    2 _# H2 J7 |/ Q6 B$ u) h
  104.   if(Uart1RxCompleteCallback)* k" y  J1 j; p
  105.   {
    - \: K$ F2 X& U. Y6 U+ D
  106.    hUart1.RxState = HAL_UART_STATE_READY;5 Y" `( i8 h1 A5 U: O/ z
  107.    hDmaUart1Rx.State = HAL_DMA_STATE_READY;
    0 X# L- A: i( B0 V; q6 ?6 l
  108.    HAL_UART_RxCpltCallback(&hUart1);0 _0 W: x% {7 \3 ~$ `& W
  109.   }$ A- f; i8 G# w  c" n' f
  110. }! {! o4 ^/ h3 q2 k
  111. else2 R6 M+ X2 z; i
  112.   HAL_UART_IRQHandler(&hUart1);
    " B8 F: o( h1 o
  113. }
    . {1 u, Q2 Z$ j) S

  114. 8 G- B& A% A, [9 K
  115. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)3 R2 f7 ^; |9 P( p6 q
  116. {
    3 a$ ], ~- i% k9 ^6 R, l
  117. if(huart == &hUart1)4 L. I3 {, s1 ?7 {5 s8 r# o
  118. {
    # V% }/ G4 P1 e5 a- s1 O6 h0 L4 f
  119.   static uint16_t count;
    ) G9 K. ^; ^' W" }2 t! A5 F, G
  120.   count = RxBufSize - __HAL_DMA_GET_COUNTER(&hDmaUart1Rx);1 t: Y; _# A) K" z+ \: F
  121.   if(count == 0)return;
    8 m5 S+ x) B$ ?* Q+ G
  122.   hDmaUart1Rx.Lock = HAL_UNLOCKED;& V* Z* N# i( X+ b/ l0 n8 r" b8 l2 m
  123.   if(huart->pRxBuffPtr < RxBuf[1])
      [. S% ]& b) N( D* |$ _
  124.   {
    - O6 x1 q" @- R4 j5 {4 r4 ^" y5 t, N
  125.    Uart1RxCompleteCallback(RxBuf[0],&count);
    5 j5 Y/ {1 Q% c- j' |3 l" v6 A
  126.    HAL_UART_Receive_DMA(&hUart1,RxBuf[1],RxBufSize);$ P$ g4 ~+ s! k2 S- r4 \6 ]2 ~/ V7 c
  127.   }' }- q6 n. h9 `8 a  x! u) f/ u! R
  128.   else9 J3 O( k: T3 ]3 e% T+ K
  129.   {4 f* R  v. q/ m4 V0 d& \8 V
  130.    Uart1RxCompleteCallback(RxBuf[1],&count);5 ?* E/ k0 O. l' p& c5 ?; P
  131.    HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
    : w& g/ U2 V* k
  132.   }
    1 V" L4 \: H3 b/ n8 H! v- z' h
  133.   hDmaUart1Rx.Lock = HAL_LOCKED;# D  a4 ~/ v  Y# h8 h+ X
  134. }
    + ~# e0 L3 Y' w, h
  135. }8 T2 w/ n/ `+ `3 F6 u, X4 P
  136. , T7 F1 c4 q3 Z( O0 Y! K
  137. void DMA1_Stream0_IRQHandler(void)% t+ u9 P( \; S
  138. {
    9 J. q$ S( L) I/ v
  139. HAL_DMA_IRQHandler(&hDmaUart1Tx);
    $ i8 L9 n5 K! m
  140. }! W) m) a2 C7 V% W' g5 b0 G

  141. : N5 k( [0 O7 m" c! H/ O
  142. void DMA1_Stream1_IRQHandler(void)' |0 y+ ]( z3 v" H
  143. {
    ) r6 U3 O1 @( Z4 y6 }, F+ ]
  144. HAL_DMA_IRQHandler(&hDmaUart1Rx);' t9 A) c* s9 ]1 Y
  145. }
复制代码

% `" M" Y7 d4 X3 `; r这个是Uart.h文件
+ K+ n$ |0 W$ h+ T3 x
' j- F+ S& `8 b2 ^
  1. #ifndef __Uart_H_4 R7 F4 ]; C0 r- C% e" {
  2. #define __Uart_H_
    0 e# E4 |! T0 E* |! H3 u  J( ?

  3. 8 r- f7 _0 v5 J- d" w" f
  4. #include "stdint.h"
    : ~0 w3 V. C+ k1 I! t" |

  5. : l: i  ^- M: ~* |0 B8 X
  6. void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count));# Q; x" m% d8 j
  7. void Uart1TxData(uint8_t *pData,uint16_t Count);( G2 S9 m/ ~* @4 C

  8. ! r. Z+ k9 D+ i. l/ N
  9. #endif /* End __Uart_H_ */
复制代码

3 e/ [; o6 B* D) A" H; I+ D这个是应用文件,实现了把收到的数据在发回去的功能。1 V9 n- K( Z' h3 b- o
9 H4 e- E1 o$ P7 ?- q
  1. #include "Uart1Task.h"3 A! r8 }+ v% \* M* |- j
  2. #include "limits.h"//ULONG_MAX
    ' a7 J0 f2 x$ e& }% ^/ O0 L# c
  3. #include "Uart.h"
    9 N/ b" H9 k( }2 x; [: N4 ]* v
  4. #include "string.h"
    . u# Z" d9 y! l( G1 w
  5. #include "SystemConfTask.h"
    + q5 T4 Z& a& E" z  r

  6. 6 N, C+ d- f! i, M8 n, T+ ?
  7. #define Uart1RxCompleteFlag  0x01
    3 G5 G: Y7 c7 C
  8. + K9 D' }- d9 ?/ h
  9. static uint8_t *Uart1RxData;
    6 G- @' |" [8 Y1 W, A' V
  10. static uint16_t Uart1RxCount;# \. k1 k; [4 a1 B
  11. TaskHandle_t Uart1TaskHandle;
    " }; [; Y$ `1 o) q6 o
  12. 8 v& A8 d3 X) N3 q, M
  13. void Uart1RxIRQ(uint8_t *pData,uint16_t *Count);
    . S! N: j0 z9 R! f( h5 A' R

  14. 9 t- B* {+ T$ O  R
  15. TaskHandle_t *GetUart1TaskHandle(void)7 A, R6 D) C5 `) B/ {
  16. {5 z) X, N9 M: m
  17. return &Uart1TaskHandle;
    : l& h8 ]$ j# P& m) Z
  18. }4 q/ J2 f% e2 v/ R

  19. 2 W7 k4 h& G* t- h, E
  20. void Uart1Task(void *pvParameter)
      u' l: Q1 R9 Z: J9 Z
  21. {
    & C* z: q7 G1 R3 H2 y
  22. Uart1Init(115200,Uart1RxIRQ);
    8 i* T! Q( [$ _6 {
  23. while(1)+ ?, X8 E. l" l/ ^9 m; ?1 _
  24. {
    2 \: H4 J8 \: H3 u; M$ X5 N: e
  25.   uint32_t NotifyValue = 0;3 \- W" S* P: a8 J
  26.   xTaskNotifyWait(pdFALSE,ULONG_MAX,&NotifyValue,portMAX_DELAY);
    $ M6 ?! p* s8 i' k0 R
  27.   Uart1TxData(Uart1RxData,Uart1RxCount);5 U+ Z$ ?0 w1 M; y- F. I9 v4 o7 {6 `
  28. }
    $ u$ @" y/ {, O4 B  |) t, A* A  h0 {$ q5 ^
  29. }
    8 }3 a9 @( g- H# \) [
  30. * e! I8 D0 L- [2 L
  31. void Uart1RxIRQ(uint8_t *pData,uint16_t *Count)
    1 |+ {: m  J. t2 U6 o% F+ E; U% S
  32. {9 |% q" V6 h" f
  33. Uart1RxData = pData;, O1 T8 L- m; ?' I7 P
  34. Uart1RxCount = *Count;! [; ^: @/ x7 Q
  35. BaseType_t pxHigherPriorityTaskWoken;4 P0 R# ]0 S9 l+ ^4 W$ ~" R
  36. xTaskNotifyFromISR(*GetUart1TaskHandle(),Uart1RxCompleteFlag,eSetBits,&pxHigherPriorityTaskWoken);
    ! L4 f( P9 Y2 R' m8 J5 @
  37. portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);: u/ \' b% i* e6 \& G# L. |
  38. }
复制代码

, V8 B- P9 N4 O. i) u3 I6 o  A串口驱动里做了一个双缓冲的,防止大量数据出问题0 x$ k+ R9 V3 z7 _  W* r: N# F
0 Y$ T6 g  r- Y$ Z9 o7 M; f* ~

* O0 w6 ?  S  a3 p: q2 t: N
收藏 评论0 发布时间:2021-12-25 10:14

举报

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