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

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

[复制链接]
STMCU小助手 发布时间:2021-12-25 10:14
中断接收方式,最大的缺点就是中断过于频繁,为了解决这个问题那就把DMA搬过来,它不就是专门搬用数据的嘛,不用多可惜。
3 d% a8 l. H" T5 [' s+ G' G  b4 q6 J
. N2 `! d4 f! n# S. a" ^首先我们需要大致了解,DMA和外设传送数据,例如串口,我们希望,当一帧数据接收完毕了,有个东西告诉主程序,串口接收到了一帧n个字节的数据存在某个地方,接收过程中你丫别打搅我。
$ G5 y: \7 z$ p0 |
3 v6 P% k+ O9 \+ Q" zDMA就能胜任这个工作,他可以以中断的形式告诉你这些信息。相比中断接收方式,是不是省了很多中断,主程序被打断的次数也就少了。; b. S) [- _( e

0 S; @: c9 c3 R( G% n9 d7 ~2 {0 r还是按照上一篇形式大概看一下,HAL库中DMA是怎么和串口配合的。
+ M" F- k( d/ t9 @( Z8 \: \8 ?  R- o' j- |
  1. /**
    & J7 q0 z6 {. ^8 G
  2.   * @brief Receive an amount of data in DMA mode.
    8 c0 P( {* q* N/ k! m7 O' I
  3.   * @note   When the UART parity is enabled (PCE = 1), the received data contain4 `+ @& S4 a: D1 g" F# O
  4.   *         the parity bit (MSB position).
    , a, c+ u8 _( b. q; D6 l: ]6 i- O! N
  5.   * @param huart UART handle.
    ' I. _7 J1 T/ r0 v( }/ h) c9 L! F
  6.   * @param pData Pointer to data buffer./ b+ F$ T. R' L
  7.   * @param Size  Amount of data to be received.
    % o, {1 z; _  l3 K3 f$ i; t
  8.   * @retval HAL status0 D5 x7 M, u5 i( }& ]
  9.   */
    & d; S, ^7 |6 T9 J4 W
  10. HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)4 e/ D) w0 j; ]
  11. {
    3 O! r) }5 q% I" i* A' \
  12.   /* 其他关系不大的代码省略 有兴趣可以自己看 下同 */
    2 G* \6 I7 a1 i( `3 A1 y, |
  13.   //1.检查参数 判断串口接收状态为就绪 把缓存区参数传递到串口句柄  修改某些状态
    # g. x5 Z' c& I, |1 B0 Q, \4 X
  14.   //2.判断和串口句柄关联的DMA句柄地址不为空  然后给DMA句柄注册一些回调函数
      z! |% t0 I; w4 [4 |$ n
  15.       /* Enable the DMA channel */
    & M: w6 G% J- s6 U  t
  16.       if (HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->RDR, (uint32_t)huart->pRxBuffPtr, Size) != HAL_OK)
    $ E# e# U$ Z5 ]- N2 Z3 w
  17.     {
    , B" l6 A. Y0 m5 \" `6 ?0 L* d
  18.       ......% |# _4 B5 C5 r# O$ w  @  o- \
  19.     }! i. A7 P+ Y, T3 r+ L
  20. }
复制代码
; t3 V9 [4 H! Z  x
HAL_UART_Receive_DMA这个函数里最主要的就是调用了HAL_DMA_Start_IT这个函数,你看他连参数都没怎么变,就把句柄换了,其他三个原封不动的传递过去了。所以函数内其他内容几乎不用考虑了。直接往下看这个函数。  n4 `  A9 @% d
. ^5 ?& W  H% h9 P, y. z! F, X# E7 @
  1. /**
    & g5 I! M' G! V1 J5 U; f( t
  2.   * @brief  Start the DMA Transfer with interrupt enabled.1 y( H0 D  k! ?0 E% |
  3.   * @param  hdma:       pointer to a DMA_HandleTypeDef structure that contains
    ' v% ~* ^1 Z! R, m# q
  4.   *                     the configuration information for the specified DMA Stream.
    . H6 a" N% x1 m: I
  5.   * @param  SrcAddress: The source memory Buffer address
    2 x& e% h( ?0 q- w5 B4 `0 p
  6.   * @param  DstAddress: The destination memory Buffer address
    7 ?5 Z  d4 K. h0 a
  7.   * @param  DataLength: The length of data to be transferred from source to destination
    9 a" \: B. `2 q! ^# ~6 I
  8.   * @retval HAL status
    0 x7 g9 ]$ |/ n6 @+ W# G6 A% c! v
  9.   */
    # K! {, h( S0 K. r3 I4 a
  10. HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
    - z9 n8 k2 v% B; l4 V' k4 {( \
  11. {
    6 p6 x2 y! w; n, T
  12.   //1.检查参数 给句柄上锁 判断状态 只有在就绪状态下才允许配置1 t8 d3 V* \+ q  {, d
  13.   //2.判断就绪状态4 B1 ~/ ^# k: R2 z+ k1 K. W( v" a
  14.   {
    6 |9 Q9 e4 Z/ H
  15.     ......: m& l2 q* a+ h+ ~' _! V
  16.     /* Configure the source, destination address and the data length */% H, X. a" y- @1 L0 O4 H
  17.     DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);6 X, j5 Y4 A; t" X
  18.     ......8 D# f. U  J3 a9 F; d
  19.     //这里会开启一堆中断  完事要用  暂时可以不关心
    9 D) f' D: M0 o- J4 x. T
  20.   }  g9 _9 ^; x6 n6 M& }6 ~" h
  21. }
复制代码

+ k+ r) ]1 f3 T* G$ m$ j8 O上面这个函数也差不多还是那个意思,都懒的看了,主要是调用了DMA_SetConfig这个函数,追踪过去,它才是真正配置寄存器的函数,HAL库就是这么繁琐。4 ~6 O. U9 P+ ]

! Y, S: Y; g+ i/ x
  1. /**
    & ?3 \* k8 r! }8 `- s5 ]9 A2 `. u
  2.   * @brief  Sets the DMA Transfer parameter.8 j! `8 m- }; g: |7 B; k
  3.   * @param  hdma:       pointer to a DMA_HandleTypeDef structure that contains
    2 s6 Q& t/ [' E
  4.   *                     the configuration information for the specified DMA Stream.
    7 P- K7 \4 j9 O  T
  5.   * @param  SrcAddress: The source memory Buffer address
    / J; v% J0 `0 [; m' `) l- w
  6.   * @param  DstAddress: The destination memory Buffer address
    + X; W' S( _3 g% j8 w
  7.   * @param  DataLength: The length of data to be transferred from source to destination! A# e1 k; v. |
  8.   * @retval None
    2 e0 ]" t$ i: X+ C9 s2 z3 D
  9.   */2 E+ L4 Q, R! x
  10. static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)6 _# i$ }* F% s  {0 z8 q8 h) E
  11. {4 B/ X) U$ d/ }( J6 W! x- }  {) D
  12.   /* calculate DMA base and stream number */
    4 Z) k! ~8 U6 F" [. i7 i. h
  13.   //获取DMA控制器对应流的基地址7 D2 @" q3 A4 r0 M; T2 o( b# c: _
  14.   DMA_Base_Registers  *regs_dma  = (DMA_Base_Registers *)hdma->StreamBaseAddress;6 i3 _* ~7 g$ m) {. D  }$ F& m
  15.   BDMA_Base_Registers *regs_bdma = (BDMA_Base_Registers *)hdma->StreamBaseAddress;
    - C8 E5 i2 _8 p
  16. ' g+ [* U" J" ~; }
  17.   /* Clear the DMAMUX synchro overrun flag */
    : ^3 I; V* Z5 K+ A7 {
  18.   hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask;
    . @2 y. L1 i$ {$ G
  19. 7 o( b1 j4 q- N$ V
  20.   if(hdma->DMAmuxRequestGen != 0U)+ Y1 g8 Z' Q/ d3 W1 }
  21.   {
    & A) R2 M- |% G
  22.     /* Clear the DMAMUX request generator overrun flag */+ u. P8 y, l: L$ N1 v
  23.     hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask;
    ' E0 d0 U+ Q. @/ v4 H5 ~0 s
  24.   }/ W5 C/ H% g3 e! H* r
  25. / J, {# O& G1 x
  26.   if(IS_DMA_STREAM_INSTANCE(hdma->Instance) != 0U) /* DMA1 or DMA2 instance */9 H4 C" r* D3 I( `$ o& i
  27.   {: ?9 b1 E- i; J6 C3 w
  28.     /* Clear all interrupt flags at correct offset within the register */3 R; Q# R& W8 g- m
  29.     regs_dma->IFCR = 0x3FUL << (hdma->StreamIndex & 0x1FU);) e4 m: s9 G8 B6 u
  30. 9 \' N8 J8 K9 w  f" J& C4 M! P
  31.     /* Clear DBM bit */) s3 ?* J$ k& M7 l. d
  32.     ((DMA_Stream_TypeDef *)hdma->Instance)->CR &= (uint32_t)(~DMA_SxCR_DBM);' e" C% K- K  p. N/ {

  33. ! N0 Z: u7 D' }  `6 X
  34.     /* Configure DMA Stream data length */' }% h% i  f4 `6 U: [4 i
  35.     //这里设置搬用的目标数据长度
    # g$ L4 S$ S. [3 D2 Q
  36.     ((DMA_Stream_TypeDef *)hdma->Instance)->NDTR = DataLength;7 q" {& }: {, a, D% k
  37. / g7 A$ @2 B- `- y: |. R( J7 M
  38.     /* Peripheral to Memory */# G: g. _/ w) ?* u) P
  39.     //整个这个if判断是在设置DMA搬运数据的目标地址和源地址4 @9 K1 X. G- ^6 M8 u
  40.     if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
    + i& o6 B/ [. L! U6 J0 j
  41.     {+ x% W: D* r5 E+ b! J' \6 T( t! {% G
  42.       /* Configure DMA Stream destination address */
    4 [5 a. i, D; O9 w1 L- p
  43.       ((DMA_Stream_TypeDef *)hdma->Instance)->PAR = DstAddress;% e. @6 c3 S! K* z6 t  _
  44. - g: o9 X5 n  g$ p. Q# P
  45.       /* Configure DMA Stream source address */
    7 A9 i9 B% b' b7 H  S
  46.       ((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = SrcAddress;
    7 I- m& }+ a3 t$ Y
  47.     }! ~- r9 M* C% [9 {7 U3 N) q' Q1 o
  48.     /* Memory to Peripheral */& Z/ C0 }1 V& [
  49.     else
    5 U+ U, h1 l* [% B+ X- y) v( q  P" _
  50.     {/ I8 D, A' p, _" c
  51.       /* Configure DMA Stream source address */
    / \2 u6 {4 g+ b0 e2 _' f4 j
  52.       ((DMA_Stream_TypeDef *)hdma->Instance)->PAR = SrcAddress;
    7 P0 e" r) {8 D  n. F2 j0 [2 x" U

  53. & u+ q7 ^/ e1 [
  54.       /* Configure DMA Stream destination address */
    ' L+ i. y0 k- x$ O! L4 ?/ Y
  55.       ((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = DstAddress;" Y4 J& h7 v- H( j
  56.     }
    + w* M2 A1 @6 t) P* W. E5 v
  57.   }
    ) T* v, C2 S/ {$ ~3 p* o0 @% f
  58.   else if(IS_BDMA_CHANNEL_INSTANCE(hdma->Instance) != 0U) /* BDMA instance(s) */" e. t3 P4 q6 X) i7 G2 i
  59.   {
    ! z' H' |+ }; k4 l5 c( Y
  60.     /* Clear all flags */
    ' R$ i, M3 F4 Z9 D3 t  L: M
  61.     regs_bdma->IFCR = (BDMA_ISR_GIF0) << (hdma->StreamIndex & 0x1FU);
    / u5 `4 |$ S% z' C

  62. % q3 V6 H) L9 W# w0 m3 g6 \
  63.     /* Configure DMA Channel data length */& Y$ ?- K+ B3 G8 t
  64.     ((BDMA_Channel_TypeDef *)hdma->Instance)->CNDTR = DataLength;  {8 V' l, Y, L- K8 D- A8 K: l

  65. ! u, b  U* J- B; v
  66.     /* Peripheral to Memory */
    , Y- @: ]7 e/ K1 e' |
  67.     if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
    2 n8 y) c' g# o* a0 U8 u- o6 t" c
  68.     {
    % m! s4 c$ E$ {8 Q
  69.       /* Configure DMA Channel destination address */
    + V% l* G  ~% y, F0 {  h/ u" `' y
  70.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = DstAddress;
    5 q: d! T$ O) Z- n8 ]

  71. + I9 _2 y/ ~+ |! M
  72.       /* Configure DMA Channel source address */1 {+ W! g8 ~4 A+ l+ R3 p# H- Z
  73.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = SrcAddress;
      P: u. b/ u$ M( m! g% k
  74.     }
    - f* x/ E" t' [
  75.     /* Memory to Peripheral */# ?6 P/ ?& ~; L9 l- H
  76.     else8 t  g4 T  t9 G$ ]5 E! v
  77.     {
    ; J" V" U/ C% q, ~5 b6 Z
  78.       /* Configure DMA Channel source address */
    9 A) X; ?0 B1 i) K5 l6 Y
  79.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = SrcAddress;7 t- h& s* O8 I* x* a

  80. ( Q5 |8 d# J( A! j. A5 h
  81.       /* Configure DMA Channel destination address */$ s: e) y) _0 T+ s" i' B0 S# t& ~
  82.       ((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = DstAddress;
    ( {' H" z+ x, {7 t& G0 M& T! W
  83.     }
    3 p/ a4 o6 n$ ]6 L
  84.   }
    6 m% M$ D. R- R
  85.   else/ j6 [7 n* ~/ C. B
  86.   {
    ' Y4 I$ h. `( U% S- [$ D0 t: n+ s' `
  87.     /* Nothing To Do */8 L% Q' k/ q7 H8 ]6 }
  88.   }  5 X$ y( R- ]# X7 O
  89. }
复制代码

& h3 a8 _, c/ E/ M' e各位同志你们自己看吧这个函数最主要的目的就是配置DMA寄存器。以上就是串口DMA接收函数中最重要的部分。好像没什么意义一样,因为我要用到其中的一点点东西,所以必须要分析源码。9 T$ \0 m; y8 S
" ~$ C- v) b1 |9 J' `9 `
我们只是说了调用接收函数,参数里边指定了接收缓存,也指定了大小,似乎和我们的目标不符合,假设我们的DMA和串口之间的配置已经配置好了,那现在能做到的就是把数据收集到这个缓冲区里,可是并不能告诉主程序接收到了数据,和接收了多少,想要知道这个,有两种方法,一种是CPU定时去问DMA接收了多少数据,然后自己定义一个记录变化的变量,配合,另一种是中断方式,我们通过查询得知,DMA只有接收完成和接收半完成两个中断。
* ^: ~2 z! g0 g/ v- s, \' h2 T1 j2 i! |4 G% h& S
最最主要的串口的空闲中断不要忘了呀,这个可以告诉你,一帧数据接收完了,你可以根据这个中断去搞,接收了多少,在什么地方。
) {4 e0 a2 y/ V0 m6 G# P* G3 v) C& z& n8 X9 \4 t& C
因为这个编辑器不知道咋回事,贴代码总是挂,上边那个函数就贴了我很长时间,很生气,所以我就无耻的把源码整到这里了,整个工程哦(暂时还没有上传)。' g2 g$ g/ I0 }6 ^# q& I2 M
9 S' m5 X& v. ^
再试试贴代码吧,方便你我他,要积分的都无耻。改天
; ~  `# P6 [' p+ F( n) Y7 ]! F- y. b  S1 M6 d
uart.c文件就这么多代码,8 C6 q8 G6 u3 u: @) O9 p

+ m) Y5 _# I7 ?; k4 y
  1. #include "Uart.h"
    9 G: d" W9 _9 p1 {
  2. #include "stm32h7xx_hal.h"
    $ w9 G% E4 ?- j9 ~! l8 }

  3. ! V3 h3 U9 J  {
  4. #define RxBufSize   10242 d/ T, c9 X7 X; u" t" o" D( h

  5. $ O6 h1 H+ p0 {6 Y
  6. UART_HandleTypeDef hUart1 = {0};/ F& O8 e% \9 E. b, g( Z$ S
  7. DMA_HandleTypeDef hDmaUart1Tx = {0};8 \* `" H. o3 v9 @  W; l/ Y
  8. DMA_HandleTypeDef hDmaUart1Rx = {0};, m( \4 D0 |; }! P- C# }
  9. ' H  T! y6 I% n4 d( J1 i( h
  10. //数组后边的那个限定跟你的内存分配有关 如果你的主RAM在512K的那个片内存就可以不加 这是AC6编译器用法
    1 n- G5 }/ A( K3 D
  11. uint8_t RxBuf[2][RxBufSize] __attribute__((section (".RAM_D1")));
    ! A5 [" [. Q$ c' s7 E
  12. void (*Uart1RxCompleteCallback)(uint8_t *pData,uint16_t *Count);
    + y4 t# n  H, ~1 K& @& ^& s
  13. * {- w$ \0 @6 t4 V( N
  14. void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count))
    % T6 T7 I( K  }+ Q. e/ u+ |
  15. {0 ?3 C0 r% ]( T# J
  16. hUart1.Instance = USART1;
    + S' h7 Z# [. E5 R' U; Y/ R
  17. hUart1.Init.BaudRate = BaudRate;
      E/ Z* o+ w) U. o% G& S7 c" j1 W9 k  N
  18. hUart1.Init.ClockPrescaler = UART_PRESCALER_DIV2;
    4 `  t3 \$ w; k1 G4 v) f3 L
  19. hUart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    1 [6 I0 P$ B" [0 h
  20. hUart1.Init.Mode = UART_MODE_TX_RX;
    % f5 j- S; m! w6 Q
  21. hUart1.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;
    5 h& y3 `, E# j
  22. hUart1.Init.OverSampling = UART_OVERSAMPLING_8;
    1 f: P# ^3 w) Y' s
  23. hUart1.Init.Parity = UART_PARITY_NONE;
    % K) h$ v- R5 g3 f5 d4 |
  24. hUart1.Init.StopBits = UART_STOPBITS_1;
    " Y( \( R$ m3 v! C2 f# Y
  25. hUart1.Init.WordLength = UART_WORDLENGTH_8B;
    : U# L  g1 c7 D# {0 i
  26. hUart1.FifoMode = UART_FIFOMODE_DISABLE;3 ]0 @! a' h5 V

  27. * t# d' `  O  {" x3 `3 Q* O3 q% H
  28. HAL_UART_Init(&hUart1);
    / M7 {5 H0 O% s) L; V

  29. 4 _9 u5 z6 P- L
  30. __HAL_RCC_DMA1_CLK_ENABLE();
    , f; F- Z4 i/ e- i

  31. : k" K- ?  ]3 y3 X7 t
  32. hDmaUart1Tx.Instance = DMA1_Stream0;. F6 a  R8 P$ Y  C/ x. {
  33. hDmaUart1Tx.Init.Request = DMA_REQUEST_USART1_TX;
    # \0 H1 [4 L. A
  34. hDmaUart1Tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    5 |- v  ]: M2 n
  35. hDmaUart1Tx.Init.PeriphInc = DMA_PINC_DISABLE;& W- n6 ^! B! ?
  36. hDmaUart1Tx.Init.MemInc = DMA_MINC_ENABLE;# j. G' V! a) W+ \: t8 |
  37. hDmaUart1Tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    ! {8 v' w8 q* ]# x/ [0 W
  38. hDmaUart1Tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    1 y, s' u6 I0 A/ Q7 ^* ^
  39. hDmaUart1Tx.Init.Mode = DMA_NORMAL;
    " c2 Z/ S$ K" f9 q% j6 b
  40. hDmaUart1Tx.Init.Priority = DMA_PRIORITY_MEDIUM;, e1 c% }4 g" k8 x/ _" i
  41. 1 s2 p8 ]9 \" K/ \4 t
  42. HAL_DMA_Init(&hDmaUart1Tx);( N! D# R: V8 H# _( G
  43. __HAL_LINKDMA(&hUart1,hdmatx,hDmaUart1Tx);
    3 s" ]# E- _& U
  44. $ X% l5 @" w2 o8 c
  45. hDmaUart1Rx.Instance = DMA1_Stream1;  V% d1 \: q' Q, G
  46. hDmaUart1Rx.Init.Request = DMA_REQUEST_USART1_RX;+ K+ G; \, a  T" S
  47. hDmaUart1Rx.Init.Direction = DMA_PERIPH_TO_MEMORY;: M, t  I. z& R$ |  S- }0 D! X& t
  48. hDmaUart1Rx.Init.PeriphInc = DMA_PINC_DISABLE;" X. q3 t7 x) k
  49. hDmaUart1Rx.Init.MemInc = DMA_MINC_ENABLE;- N0 S3 {, M% P
  50. hDmaUart1Rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;: g1 I# N0 _# ?% _7 i' N
  51. hDmaUart1Rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    2 T9 s) }3 X% h4 P, h! r& C
  52. hDmaUart1Rx.Init.Mode = DMA_NORMAL;: ?% j) ]% s: H; Y
  53. hDmaUart1Rx.Init.Priority = DMA_PRIORITY_MEDIUM;/ P# V: f. o2 |0 N5 _

  54. # ?' e/ r. s  D
  55. HAL_DMA_Init(&hDmaUart1Rx);
    1 L0 P9 S. S) e0 O/ G, E
  56. __HAL_LINKDMA(&hUart1,hdmarx,hDmaUart1Rx);
    ( W+ s  d0 T( a
  57. * H- M1 n$ S4 ]+ C8 n
  58. HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
    . E" |8 `2 y9 \: {" N0 [! h: d8 y

  59. . K; @; @; J& }0 E* d
  60. __HAL_UART_ENABLE_IT(&hUart1,UART_IT_IDLE);
    ! a; k. `$ W. f9 I3 Y! l) c# ~
  61. HAL_NVIC_EnableIRQ(USART1_IRQn);8 v8 g, A# |+ E* w1 U8 g
  62. HAL_NVIC_SetPriority(USART1_IRQn,14,0);6 D! y4 @* S# _6 m2 u/ _
  63. 9 D$ u4 h+ F- O7 h% W% N$ Z
  64. HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);//Tx
    ! ?/ m( e8 M' _9 q2 f& |
  65. HAL_NVIC_SetPriority(DMA1_Stream0_IRQn,14,0);
    6 ?* V3 y2 d$ J. ~' \
  66. 7 v; a0 _# n3 A6 i0 X1 }9 q' S
  67. HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);//Rx' o7 y7 V: L. A
  68. HAL_NVIC_SetPriority(DMA1_Stream1_IRQn,14,0);
    & x- }/ B9 Y# m2 \' B8 \
  69. & ^) P; M" p" \6 ^1 _
  70. Uart1RxCompleteCallback = RxCompleteCallback;
      f8 y% ~9 {3 S4 _: q+ ?# O
  71. }3 L9 n; [: J3 @! Q

  72. ) W/ e( v/ T, X; c2 d" d8 P
  73. void HAL_UART_MspInit(UART_HandleTypeDef *huart)' Y% a. U, l- N
  74. {
    * n. V! x+ j* r2 F: e
  75. if(huart == &hUart1)//串口14 f- }1 e: j, V
  76. {
    2 J$ L1 h' V* f2 N' K+ r; g: b& y
  77.   GPIO_InitTypeDef GPIO_InitStruct;$ i, y5 `5 {' e# |+ K- J& f4 i/ o

  78. % p* q- G6 p* @8 M# G2 H# m! `8 e
  79.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;: P! A( F% M  }4 B+ U; R
  80.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    + z& K" u# @& H+ k
  81.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
    2 _9 C( D" z9 ?' p  S* |
  82.   GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    6 f" r' P0 m/ H, ]7 [$ c
  83.   GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_9;  W" C* v8 Z0 @! H
  84. * h/ d/ ^  T# U
  85.   __HAL_RCC_GPIOA_CLK_ENABLE();
    ( C9 Q( d, H  e9 z* l; G
  86.   __HAL_RCC_USART1_CLK_ENABLE();
    ) V. P' F% C. O0 Q8 j- F
  87. ) h/ `7 t* j5 K
  88.   HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
    * x2 k2 J; _# x3 H1 z4 M5 d
  89. }, W9 l  c* _5 n. \7 D1 Q
  90. }, y# n9 T  ~8 Y3 R, c0 J

  91. $ e! [2 N! m; N1 x% c
  92. void Uart1TxData(uint8_t *pData,uint16_t Count)8 O5 A% D- J, {$ `( y/ C/ h
  93. {
    % h9 ^/ k4 j& t" o
  94. if(Count)
    9 E. I. v+ E; s) n
  95.   HAL_UART_Transmit_DMA(&hUart1,pData,Count);" w3 p- q1 f& u5 D# ^
  96. }0 d1 p- ]# V# @0 X$ o2 `
  97. - ]3 s2 t$ `2 h2 m
  98. void USART1_IRQHandler(void)
      l% H3 I3 K& `( J4 B; N
  99. {( s1 N7 h/ b2 n% @+ u( r7 c/ z" z
  100. if(__HAL_UART_GET_FLAG(&hUart1,UART_FLAG_IDLE))
    $ p* j9 J3 q! O  m! Y1 O. |' a
  101. {  G( X$ \6 ]0 a, p
  102.   static uint16_t count;
    : z1 z5 Z! X( U$ R. S- t. F7 D
  103.   __HAL_UART_CLEAR_IDLEFLAG(&hUart1);( R6 [9 _1 }; I
  104.   if(Uart1RxCompleteCallback)
    0 \& H; _- `, U
  105.   {
    9 M% e" c" K3 B
  106.    hUart1.RxState = HAL_UART_STATE_READY;% t3 a0 u$ t2 V" j9 _0 P$ a
  107.    hDmaUart1Rx.State = HAL_DMA_STATE_READY;) F3 ?9 f2 {, B" z9 T% I
  108.    HAL_UART_RxCpltCallback(&hUart1);
    8 {4 d: f3 ~" t% p% m; R; S
  109.   }
    # z1 z$ g. [; K- y0 m, n
  110. }
    ; H  t0 O5 k" k; {  N
  111. else
    ' C* }4 C4 |- V+ Z$ P* r) x  s) P
  112.   HAL_UART_IRQHandler(&hUart1);
    : I, X; s' b# d+ Z4 v
  113. }
    ' i& j2 h  ]3 g' h) V( d, |

  114. - m( h* c/ I: i& h2 I
  115. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    / q- |9 \$ J- M3 ^9 i: e
  116. {
    ) A6 Q  b; A: \. a; b
  117. if(huart == &hUart1)
    $ E5 I3 o# |8 Q( `! @" E6 k
  118. {
    ; w0 t" u1 U3 ?' y3 B: q. p1 w
  119.   static uint16_t count;
    ( ?& ]- i+ Y3 M7 I5 c
  120.   count = RxBufSize - __HAL_DMA_GET_COUNTER(&hDmaUart1Rx);
    # M* m; ]* x3 _0 e7 @# l* g  U4 O7 L
  121.   if(count == 0)return;
    & ^+ J$ G( R& `
  122.   hDmaUart1Rx.Lock = HAL_UNLOCKED;! O' m# y" V& L) j, F
  123.   if(huart->pRxBuffPtr < RxBuf[1])% o* a5 w; g$ `
  124.   {' T$ ?$ j  U* y/ o
  125.    Uart1RxCompleteCallback(RxBuf[0],&count);; j* s4 E% G7 z- t6 G1 S
  126.    HAL_UART_Receive_DMA(&hUart1,RxBuf[1],RxBufSize);
    3 H5 A& C* m( R% j- E* q& r2 @; v
  127.   }
    8 t7 f  a3 j0 Z/ M
  128.   else1 K3 q1 R) k$ r& ]# k0 Y- E) I
  129.   {
    + s  ]# h; Z6 s- H3 M
  130.    Uart1RxCompleteCallback(RxBuf[1],&count);6 T4 z: m# E  l: P
  131.    HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
    / c& E+ h* b- Y8 z. Q: o
  132.   }7 ^3 T9 T/ m8 F/ y5 ?) v7 ?
  133.   hDmaUart1Rx.Lock = HAL_LOCKED;' L" v9 z7 q) ?( I, b- S4 ^! S
  134. }- \4 v7 _' d, x, Y
  135. }/ i9 B1 T# m: P  S  c1 `

  136. ' v: K2 x6 q8 j7 N2 }. m; T
  137. void DMA1_Stream0_IRQHandler(void)
    % y3 Q' G; h! k  Y. t
  138. {% \2 r8 k" N5 J) z3 r$ F: y
  139. HAL_DMA_IRQHandler(&hDmaUart1Tx);
    5 U& z8 ~, k* H1 k" J) L
  140. }
    " A5 K, D, n4 z, _
  141. 2 |$ u0 W8 w# @0 {' v+ p8 z
  142. void DMA1_Stream1_IRQHandler(void): Y; ]% P$ v" m8 Y
  143. {
    . H) H" T; P+ Y8 o3 d: s+ m% D$ s
  144. HAL_DMA_IRQHandler(&hDmaUart1Rx);% a7 i5 m% _8 ?5 O( _' U2 D' C" I
  145. }
复制代码
* m% t; |4 D$ p, ~. g# F" q* @
这个是Uart.h文件
7 K& m  E7 s: Y& f4 _; k* G' P
$ r" ?, m3 S6 D! w
  1. #ifndef __Uart_H_
    0 Q* Q7 [( N  g' g
  2. #define __Uart_H_
    ( v* f2 r$ A3 _( \
  3. 6 C$ M& E. b. c
  4. #include "stdint.h"
    3 u4 d6 I1 j' A: Y! D8 D

  5. 6 z( q% ~9 C+ S1 q: S# h
  6. void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count));
    3 b8 {* w2 {4 d# H# z: P, S0 u
  7. void Uart1TxData(uint8_t *pData,uint16_t Count);" V( \5 L4 B- z( u! d8 m+ E
  8. $ u6 o6 ^; [$ [
  9. #endif /* End __Uart_H_ */
复制代码
; t4 f( B- ~2 r: d
这个是应用文件,实现了把收到的数据在发回去的功能。+ b% B3 T! C" f  X9 B9 W& ^
5 ^) Q; @/ q+ X$ Y# C: ]
  1. #include "Uart1Task.h"
    + V. M" @$ R+ b4 h0 u
  2. #include "limits.h"//ULONG_MAX
    5 A  j0 V) A, |
  3. #include "Uart.h"8 s& ~, E/ w/ c$ a5 T" T5 y
  4. #include "string.h": E( ~( e! W  X$ f3 M3 b# ?' z  R
  5. #include "SystemConfTask.h"
    9 w* b: J' m* l8 N) r( B
  6. 8 r) _5 O- o# u' s
  7. #define Uart1RxCompleteFlag  0x01
    0 z& F8 \, Q/ s8 U" v

  8. 9 ]4 A" _% J' @: W
  9. static uint8_t *Uart1RxData;2 {5 [# b4 J3 Z- A" m4 F% R1 r
  10. static uint16_t Uart1RxCount;
    $ v* B/ p7 }" m2 m
  11. TaskHandle_t Uart1TaskHandle;
      G1 i& T% O) i! b5 M
  12. ( \" w" N# L4 w" C* [/ w8 R# z- ]
  13. void Uart1RxIRQ(uint8_t *pData,uint16_t *Count);& ^. ^. ]9 x- E
  14. ; G/ N# o$ y0 K1 t9 f4 l
  15. TaskHandle_t *GetUart1TaskHandle(void)
    & g. s3 y: C4 L5 ~
  16. {" p4 m5 |9 h( Y: P9 A- \; [
  17. return &Uart1TaskHandle;
    ' ~2 X8 ^; A" o+ q1 j& O
  18. }7 ?. A# s: W4 e9 w! C/ u
  19. * f! B& @! [' b* F1 f( P' j* ]
  20. void Uart1Task(void *pvParameter)0 U) Q! j0 A( `3 O1 O# d) r
  21. {$ W5 R4 a. `1 l, L
  22. Uart1Init(115200,Uart1RxIRQ);" }0 L! W8 Q9 q" o- Z
  23. while(1)
    " I+ o' \" @2 W+ j" i* Y- [( ~2 M
  24. {3 B. b  _$ S& u+ F
  25.   uint32_t NotifyValue = 0;
      ^; i/ N/ z7 j2 O
  26.   xTaskNotifyWait(pdFALSE,ULONG_MAX,&NotifyValue,portMAX_DELAY);
    1 z( {* D3 R2 [  i+ N$ P/ s
  27.   Uart1TxData(Uart1RxData,Uart1RxCount);
    & d7 {5 G+ b- ^7 f
  28. }& W2 |( O: B+ g& |7 {
  29. }
    4 K, d2 j( Q* S: t
  30. 3 `3 ^$ z$ T6 N9 j
  31. void Uart1RxIRQ(uint8_t *pData,uint16_t *Count)
    ; t: J4 g# r1 D
  32. {5 f1 x/ f( J& a
  33. Uart1RxData = pData;$ ^" T% o$ _* q
  34. Uart1RxCount = *Count;
    , w: {/ {+ d! ]5 i5 ?
  35. BaseType_t pxHigherPriorityTaskWoken;
    4 p+ U2 _& n  z. d  I- f$ J
  36. xTaskNotifyFromISR(*GetUart1TaskHandle(),Uart1RxCompleteFlag,eSetBits,&pxHigherPriorityTaskWoken);
    / F6 U+ J+ y8 R  y' b  i  [$ c, H
  37. portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
    ' r' i: D) \" W# W! E1 L
  38. }
复制代码

! M8 @  _: ?( R2 H- ]串口驱动里做了一个双缓冲的,防止大量数据出问题1 v2 _. Y' ~7 E% p  u, L& Y7 w

& B2 A  f. D" P* }1 v$ {9 Q
- J! I1 S2 D8 D( z& e& K+ X/ P
收藏 评论0 发布时间:2021-12-25 10:14

举报

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