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

STM32使用DMA发送串口数据

[复制链接]
STMCU小助手 发布时间:2021-7-20 13:45
01概述! o5 F: {9 n4 Q
1 U% k( |9 f( m3 w8 w7 k

; ~9 }; B/ i2 K$ i7 c上一篇文章《STM32使用DMA接收串口数据》讲解了如何使用DMA接收数据,使用DMA外设和串口外设,使用的中断是串口空闲中断。本篇文章主要讲解使用DMA发送数据,不会讲解基础的串口和DMA知识,直接上代码,如果有同学对DMA和串口都不熟悉,建议看一下上篇文章《STM32使用DMA接收串口数据》
' v! q5 u  |7 ]8 S2 _5 G使用DMA发送数据,首先我们要确认使用的串口有没有DMA。
" Q& ^: U4 D% M& r  ]我们使用USART1串口外设,从数据手册中可以查到,USART1的发送和接收都是支持DMA的,使用的是DMA2.+ q! m* x5 Z) K% \; ~9 X5 n3 T
1.jpg 4 Q+ \/ w  h& z
接下来就是撸代码的时刻了% D, K3 \! G( k# R
) U2 |" O" h8 f$ x; B2 r
' V- z- p3 D( _4 G9 u2 F& M3 p
+ S$ b: F$ ?( f
+ e2 s$ J- d5 I& V! u
02代码5 O5 o5 ?  p) e' q. ]6 U

+ [0 @; A& O- k  Q8 s& Q$ `% a

0 B5 T5 b% F, r) C$ m8 qDMA串口发送的代码是在上一篇文章DMA串口接收的基础上修改的。
7 C6 d5 Z5 ^' j* l! R' L2 B
  1. <font face="微软雅黑" size="3">void UART_Init(void)
    9 y: ^( C5 E/ U2 E6 z3 T; |
  2. {! i' `/ ?- A# e$ Y
  3.   USART_InitTypeDef USART_InitStructure;, A% Q$ r, k2 }4 }6 K
  4.   GPIO_InitTypeDef GPIO_InitStructure;
    9 b) h" ?" {& l  H6 i
  5.   NVIC_InitTypeDef NVIC_InitStructure;
    & I, I/ u/ P6 M( a! c& L+ Z% }) \# _
  6. / Z( ^4 G' N2 N3 K) f
  7.   /* Enable GPIO clock */7 R' h/ B' G8 q3 N" w  _0 ^
  8.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    + D  k: R; W0 H5 p
  9.   /* Enable UART1 clock */6 {* _2 l7 R0 E( ]5 M7 c9 M1 s
  10.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    ; I9 B' E5 B# i& H9 |2 B
  11.   /* Connect PXx to USARTx_Tx*/1 k# l: c$ d9 y0 Y; U1 W
  12.   GPIO_PinAFConfig(GPIOA, 9, GPIO_AF_USART1);" n/ H! }; V& N! G2 C7 j% S
  13. , S* U: J1 ^" u5 N6 k
  14.   /* Connect PXx to USARTx_Rx*/
    9 y" K" W% F5 d. t# u" J" B5 P2 d
  15.   GPIO_PinAFConfig(GPIOA, 10, GPIO_AF_USART1);
    " C5 n4 N) c. G; n$ w" I1 e( x

  16. * F% S* T/ C8 o0 c
  17.   /* Configure USART Tx as alternate function  */
    1 K' s1 r6 z- I- J1 Q
  18.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;# C0 O& L) v7 h$ N5 A1 }( b' A
  19.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;, `1 N: J! Q% `1 C1 \
  20.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;$ y8 S: ^- Z) z' x
  21. # I+ Y: V0 b+ }6 t
  22.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    2 X7 Q) \3 ^% y8 Q) j2 L
  23.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    2 V. _  P3 p( S, C
  24.   GPIO_Init(GPIOA, &GPIO_InitStructure);8 ]+ T- H$ A8 k- {

  25. 3 J: F( L- `4 D4 Q- ?) ?+ @! H) M
  26.   /* Configure USART Rx as alternate function  */
    8 E, k! g+ F. s: Q$ J, h
  27.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    * G" b/ K+ T* G8 P2 j: K0 H2 ^7 D
  28.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    ) a7 Q3 G( m3 b! }# _" w
  29.   GPIO_Init(GPIOA, &GPIO_InitStructure);
    * J8 F) a7 t/ H: u4 D, ]( i

  30.   e& O; f" j" k+ T* z
  31.   USART_InitStructure.USART_BaudRate = 115200;) z3 O4 l! Q/ X% g7 B+ v: g1 b6 L
  32.   USART_InitStructure.USART_WordLength = USART_WordLength_8b;0 U) r+ `# W/ T0 x4 J5 D" p
  33.   USART_InitStructure.USART_StopBits = USART_StopBits_1;
    " Q! b% g/ ~( A0 x4 Z! x8 R
  34.   USART_InitStructure.USART_Parity = USART_Parity_No;
    . h: \$ W. E7 u! S! A" ^
  35.   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;! Z) n/ E! y5 V5 _+ u) U0 s% c
  36.   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    & @4 Z( P6 C! y. C3 G# v3 J3 ?
  37. 5 @8 m) y: R: K+ S. Y
  38.   /* USART configuration */
    9 `/ P8 K) d. }' f
  39.   USART_Init(USART1, &USART_InitStructure);; e! k. o) u% \8 Y; i

  40. . l& ~8 c+ i* O5 R- g& S% Z* n* a
  41.   USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);. D8 {; w2 v7 l* E9 p/ j5 N) k

  42. 9 i/ |4 j% F9 R% \: }1 x* H9 w8 P: S
  43.   /* Enable the USARTx Interrupt */
    # L* r& F: U/ n, z& _- o
  44.   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    4 M* q+ h+ O: ?
  45.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;5 D- V! L# h* H8 w& S& j4 A, h! H
  46.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;2 ^& ]6 }! g" b2 ^4 E
  47.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    0 f8 A; P$ A! P! ?6 j
  48.   NVIC_Init(&NVIC_InitStructure);' E* e+ }" x$ x$ V  \
  49. 5 W* `6 m! J1 J, ]2 _9 _
  50.   /*使能串口DMA接收*/2 E5 x$ z$ @* }) j/ m' }4 S' A% n/ F
  51.   USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);4 T$ r* _9 l: Z. o: |
  52.   /*使能串口DMA发送*/
    2 X+ g+ w( \* J5 }4 `5 a0 V8 W
  53.   USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
    " c; o# a* M: S( i1 k0 E

  54. ( P0 `% L. E: U2 @) o
  55.   /* Enable USART */
    6 |+ t/ J$ c$ W2 F: R) i
  56.   USART_Cmd(USART1, ENABLE);6 b5 [3 X, ?# z3 x0 Q0 ~- s9 b
  57. }</font>
复制代码
在这里除了常规的串口配置,我们需要配置串口的DMA发送,和串口DMA接收一样的API函数,参数修改为USART_DMAReq_Tx即可。8 K- Y& {6 U6 j- v9 t1 q
串口DMA发送配置
8 k1 A) y; V8 v" i# l+ q2 P
  1. <font face="微软雅黑" size="3">void Uart_Send_DMA_Config(void)
    ) j' I! G, ?6 B! l
  2. {$ |- S) z1 x$ r5 a
  3.   DMA_InitTypeDef  DMA_InitStructure;9 a( D5 \# N9 ~$ R9 T5 m" q' w

  4. ! w$ @6 p' Y1 H2 @5 H
  5.   /* Enable DMA clock */2 z! v- l2 a: j
  6.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    0 r) e7 _1 C& H4 X5 \1 q7 V
  7. ) d, f) R/ i- U( \/ X' `
  8.   /* Reset DMA Stream registers (for debug purpose) */
    " i7 B# _2 s$ ^  ~
  9.   DMA_DeInit(DMA2_Stream7);  F" \* h: ?0 }* y2 h
  10. * {6 P, G  Y$ r! H% f' q( Z
  11.   /* Check if the DMA Stream is disabled before enabling it.5 a3 h  G1 T% ~7 R& L& _% H
  12.      Note that this step is useful when the same Stream is used multiple times:
      Y; n2 j8 U+ E$ p
  13.      enabled, then disabled then re-enabled... In this case, the DMA Stream disable
    & t9 Q, c$ n( K8 r# ?5 y
  14.      will be effective only at the end of the ongoing data transfer and it will 3 _& y  i3 P/ c. I9 a/ G- v3 T
  15.      not be possible to re-configure it before making sure that the Enable bit
    * R* |( u8 G- [$ e$ N" R
  16.      has been cleared by hardware. If the Stream is used only once, this step might
    7 r5 C$ \& i$ ^) g
  17.      be bypassed. */
    ! Y9 [' b4 j$ y; ]+ }6 [/ s
  18.   while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE)
    + S  B  |$ j7 k; u! y3 {0 k
  19.   {
    8 ~- }# p" H, @& u1 b; @+ O+ W
  20.   }0 x; z7 a: |6 x6 U
  21. 5 ]5 e# ?8 k* N* k7 S9 i5 B: F
  22.   /* Configure DMA Stream */
    * C  r  ?' V# ]$ x8 V
  23.   DMA_InitStructure.DMA_Channel = DMA_Channel_4;  //DMA请求发出通道1 {: |" {4 l* @9 H% \) \
  24.   DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;//配置外设地址! |! t" y. a5 B3 b+ l8 l% W, X- W! }
  25.   DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)UART_Buffer;//配置存储器地址
    ; v" Z+ {& G. N8 M& }; v
  26.   DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//传输方向配置8 {9 v1 _! b/ a* w% N7 \. X
  27.   DMA_InitStructure.DMA_BufferSize = (uint32_t)UART_RX_LEN;//传输大小$ v6 k0 y" i) n; k0 |) P0 L
  28.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不变
    7 u' Q7 R+ b: O, v) a* K% |6 \
  29.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//memory地址自增
    4 |& _+ v7 u3 U& d: k, l0 U. f4 E
  30.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设地址数据单位: V) o+ J4 d; o! l7 L& I) f
  31.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//memory地址数据单位' a% c4 W/ K; `3 |+ ]: j
  32.   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//DMA模式:正常模式$ H2 U) a5 b! f( I, ^8 b) p
  33.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;//优先级:高
    6 `- D/ o2 j$ g9 r7 _& t
  34.   DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//FIFO 模式不使能.          . E3 ]+ o: M( q9 ~
  35.   DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;// FIFO 阈值选择+ g! V2 u. v( f3 v
  36.   DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。
    ' k; @/ ~+ A* o* M$ C
  37.   DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。
    5 j; D/ |. A, w. `7 Y
  38.   DMA_Init(DMA2_Stream7, &DMA_InitStructure);
    7 @. O$ x, i7 o& ^

  39. & `. W( `0 U2 ~/ c
  40.   /* DMA Stream enable */
    % Q& x2 t* s  z
  41. //  DMA_Cmd(DMA2_Stream7, ENABLE);
    5 ~$ j9 ~6 ?- H! ~
  42. }</font>
复制代码
这里也是常规的DMA配置流程,不明白的同学请看文章《STM32DMA详解》,这里值得注意的是,配置完成并没有使能DMA2_Stream7,使能了就会立即将UART_Buffer的数据发送出去。1 F5 u7 e: {6 y- j
其他代码处理
! y0 @8 ^0 u. o+ S' l9 O2 ?
  1. <font face="微软雅黑" size="3">void USART1_IRQHandler(void)
    3 E$ K" T2 X# o! S" c) {
  2. {/ M% L% F2 O3 C6 Z
  3.   uint8_t temp;
    3 L  x( p5 Q8 E% ]
  4.   if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE) == SET)& t8 m- u& r8 [' M1 [
  5.   {
      ]# f; w4 c+ l5 F
  6.     DealWith_UartData();; H8 h9 q$ [& c$ n9 b: |
  7. //    USART_ClearFlag(USART1, USART_FLAG_IDLE);( ]8 e* w7 \$ O# k6 R
  8.     temp = USART1->SR;  ; Y5 u2 ^; ~/ f
  9.     temp = USART1->DR; //清USART_IT_IDLE标志  % b+ n1 s" S& \3 Q
  10.   }- D- b1 W, D  J7 z7 T4 W9 h
  11. }
    / ^- s9 U% e  K. s0 {2 `

  12. * P+ I) H4 P/ I4 @7 [3 \7 g% m
  13. void DealWith_UartData()
    5 N( z: Z8 r! Q# q* o: ?
  14. {5 F! T0 o- P3 a$ R8 H
  15.   DMA_Cmd(DMA2_Stream2, DISABLE);. Q* D) c9 |. X8 \
  16.   UART_Receive_flg = 1;; g- I/ R+ K1 I0 D0 Z
  17.   UART_Receive_len = UART_RX_LEN - DMA_GetCurrDataCounter(DMA2_Stream2);' J! P7 L8 Q$ t, i. b
  18.   UART_Buffer[UART_Receive_len] = 0;# F7 A8 x0 w) i
  19.   DMA_SetCurrDataCounter(DMA2_Stream2,UART_RX_LEN);
    1 v. Z0 Y+ D& \7 Z1 K
  20.   DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2);
    ; k3 H: z3 ]/ a, d
  21.   DMA_Cmd(DMA2_Stream2, ENABLE);: D' v9 \) |9 V. I; u' @
  22. }
    ! h/ H9 G* K2 n' P9 q7 p
  23. ! \* [) V" O6 i7 |6 a+ a. b/ X- o
  24. int main(void)
    1 P+ Q( P7 V- x
  25. {3 Z# f" x8 R  ]7 k: f
  26.   UART_Receive_flg = 0;& k0 v$ Z  X4 P& C8 w
  27. : A5 \( Y6 I! d0 E/ {7 h3 O6 v
  28.   Uart_Reveice_DMA_Config();
    $ y: g2 e. Z" u  k
  29.   Uart_Send_DMA_Config();5 ^1 E( \9 X' m% l5 z7 _: P
  30.   UART_Init();  @2 u7 E& f( N$ v; k; ~
  31. 8 Q( ~9 C5 |! J' F& `$ h% Y( d
  32.   while (1)
    , B7 W: K3 C; R  p+ w
  33.   {
    9 q* h3 u* V3 y, O" N
  34.     if(UART_Receive_flg)1 O6 x* t4 t$ M) f: |
  35.     {* t# B+ C4 R: J; T9 @) ~
  36.       UART_Receive_flg = 0;; G0 L4 L  t" f
  37.       Uart_Send_DMA_Start();# y3 h' e4 E% h& k" n  N5 g
  38.     }
    6 `: s2 K& E  f, r! M
  39.   }
    & w! ]: v  w, h0 C5 n( [2 B
  40. }</font>
复制代码
上面3个函数,简单逻辑就是,当串口使用DMA接收了一定量的数据,就会通过串口DMA发送出去,串口DMA发送的代码如下:
6 q; q: Q9 x# y  q
  1. <font face="微软雅黑" size="3">void Uart_Send_DMA_Start(void)+ Z/ z6 T! S; o' ~. i
  2. {7 g, R$ Q% [% A9 P0 y. a) K' M
  3.   DMA_SetCurrDataCounter(DMA2_Stream7,UART_Receive_len); 3 ^: M$ e  g, L& U
  4.   DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7);% D! ^7 ^1 d- t8 h  w% P9 R  z% D
  5.   /* DMA Stream enable */0 M: W4 {6 o  @4 z7 A& {8 i, ~, N5 n( M
  6.   DMA_Cmd(DMA2_Stream7, ENABLE);+ A; S: z5 X9 w- f
  7. }</font>
复制代码

0 i6 ^2 W6 m+ m  H
$ |8 m" j7 k! c4 ^
收藏 评论0 发布时间:2021-7-20 13:45

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版