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

STM32使用DMA发送串口数据

[复制链接]
STMCU小助手 发布时间:2021-7-20 13:45
01概述
* O' [; d( d) O, c1 s& H5 Y' J( ~, c0 m
$ [9 j8 T5 h; ?3 W
上一篇文章《STM32使用DMA接收串口数据》讲解了如何使用DMA接收数据,使用DMA外设和串口外设,使用的中断是串口空闲中断。本篇文章主要讲解使用DMA发送数据,不会讲解基础的串口和DMA知识,直接上代码,如果有同学对DMA和串口都不熟悉,建议看一下上篇文章《STM32使用DMA接收串口数据》。& s) I% N' m. G# M/ ~0 N7 Z
使用DMA发送数据,首先我们要确认使用的串口有没有DMA。
' p1 R3 Q4 F. S2 b我们使用USART1串口外设,从数据手册中可以查到,USART1的发送和接收都是支持DMA的,使用的是DMA2.
( R: N5 |( o* s 1.jpg
) b" }. y4 Q' g5 n; I接下来就是撸代码的时刻了
$ O# U% I' B" X5 s6 ~" C, P. N
8 m5 J" p% v2 J- w) A
* Q0 T2 t( P' I- r# T' G

0 @8 E/ a& p1 H2 x' |, p, m+ k2 W6 m
9 [* C. Q! h+ d  z' f
02代码
% R8 F% F7 m" K- U$ W5 q; R/ m# y# o* N9 w& I: b

' A& J9 u1 I* _- gDMA串口发送的代码是在上一篇文章DMA串口接收的基础上修改的。, k7 Y6 y- j7 B0 R- `+ c" j0 B6 ^
  1. <font face="微软雅黑" size="3">void UART_Init(void)2 K& B: z- N/ V) z) Q
  2. {& {0 C9 q& W, l) O. f
  3.   USART_InitTypeDef USART_InitStructure;
    * F3 D0 D( [( m9 V5 x7 }
  4.   GPIO_InitTypeDef GPIO_InitStructure;
    , d1 Q2 e  m/ `1 e# I/ I% i
  5.   NVIC_InitTypeDef NVIC_InitStructure;" M( C! r" @9 p" L

  6. , N4 a. F0 a* q
  7.   /* Enable GPIO clock */. x9 O5 _/ @9 j- u, p
  8.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    % N- n+ ?! U0 I- v5 x( O0 i
  9.   /* Enable UART1 clock */3 F6 \$ y; E5 t
  10.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    9 m/ L4 f$ ?, N1 o7 E& V2 {8 X
  11.   /* Connect PXx to USARTx_Tx*/+ T* W* b4 a" Y# D  j+ Z
  12.   GPIO_PinAFConfig(GPIOA, 9, GPIO_AF_USART1);
    ; I- m* |* p! u) I: N. C
  13. , ~! y- [, g: m" M
  14.   /* Connect PXx to USARTx_Rx*/
    8 r1 C8 S' K( N7 o, Z6 N
  15.   GPIO_PinAFConfig(GPIOA, 10, GPIO_AF_USART1);, C! U$ @# D( B1 M1 @2 o
  16. , q9 |& D/ p; `3 W
  17.   /* Configure USART Tx as alternate function  */2 n- G) g; i* W1 G5 q( R/ T
  18.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    + Y% h9 S) p7 O" Y: c
  19.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;8 n9 @& @) Y/ ]- \" H2 M7 ^
  20.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;7 F% O1 g7 i* q8 n/ Y& i2 l
  21. 2 K0 ~$ ]2 o, r8 A2 l3 C
  22.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    9 A8 |% S$ f" @, u; ]+ _
  23.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    ( M; B+ ^1 h1 P
  24.   GPIO_Init(GPIOA, &GPIO_InitStructure);- b4 m1 O6 L4 q# J5 b; S. s
  25.   T4 @, a2 e8 f: l4 P1 q
  26.   /* Configure USART Rx as alternate function  */. T' t: e9 E1 z* f* L) x
  27.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;3 _3 |& ~% E" ~  P+ q, X' Z
  28.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;/ R8 d  _+ @$ ~- d6 W& ^
  29.   GPIO_Init(GPIOA, &GPIO_InitStructure);
    ! n2 t$ Z& ~9 @6 x

  30. $ u% f! \; Z5 W5 e- [
  31.   USART_InitStructure.USART_BaudRate = 115200;4 R( x% w& v6 i, ]- }' W& {
  32.   USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    ; I) G4 M! l( X- k0 m8 n' s; `
  33.   USART_InitStructure.USART_StopBits = USART_StopBits_1;# d; m! ?- [- ~2 U9 {& Z
  34.   USART_InitStructure.USART_Parity = USART_Parity_No;
    6 g4 z! Q3 N, R7 H9 n! s
  35.   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    2 S; R5 u; \& i% c2 p# a
  36.   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    $ u" m+ k2 G6 q9 J8 |

  37. / ~' L, J2 B- g+ s& o1 W' ^) C
  38.   /* USART configuration */
    ; H$ a9 t- ~7 }, D! m5 n
  39.   USART_Init(USART1, &USART_InitStructure);
      H% m0 l+ h' x; ]6 M! L, h
  40. , N" c0 `+ H# l( q( G
  41.   USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
    % g/ C) M+ E- q" b1 f1 m
  42. 1 L6 Q& I0 H$ j! F6 T7 y! a7 H+ o
  43.   /* Enable the USARTx Interrupt */
    6 Q* K" H8 @" L% V3 y0 [5 ^
  44.   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;7 W3 _/ E1 J/ y; B
  45.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
    4 M  W4 ~1 p: x9 u
  46.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;/ w9 Y5 ]' w: E$ H
  47.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;5 y: c$ |- m# ^5 F7 K" V
  48.   NVIC_Init(&NVIC_InitStructure);
    ) Y% A4 U6 `3 l( N
  49. - i2 B; y, O, K# }& Y1 S2 A7 O% g8 X
  50.   /*使能串口DMA接收*/7 r4 M& D, t+ l! y; |$ q$ J" m
  51.   USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);2 _. Z9 [  `/ B. D7 K$ a/ c: M
  52.   /*使能串口DMA发送*/
      K* M7 F6 w5 k( y: I4 c+ D
  53.   USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);6 U: t0 P$ V, @- X
  54. ; P) c4 S2 p, h) J& [
  55.   /* Enable USART */
    2 Q" h. i- D  L0 [! J3 z0 s* E
  56.   USART_Cmd(USART1, ENABLE);
    3 Z' c, c' z1 b# U) t
  57. }</font>
复制代码
在这里除了常规的串口配置,我们需要配置串口的DMA发送,和串口DMA接收一样的API函数,参数修改为USART_DMAReq_Tx即可。
2 F- K. s1 G  ]% z7 Z% e串口DMA发送配置
3 W  @: y3 Q% E+ g
  1. <font face="微软雅黑" size="3">void Uart_Send_DMA_Config(void)
    / c; ~# V& x& L! z% g! O
  2. {2 \% R( y1 _& h6 X* D! p0 d% Q
  3.   DMA_InitTypeDef  DMA_InitStructure;
    ! b) Y: v4 i5 C0 F" \4 A
  4. ) z- _, _0 @9 R3 c1 [2 G
  5.   /* Enable DMA clock */
    # r  B# o7 i% r' `' m1 l
  6.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    . i4 ?* Y/ U8 ?) p! L

  7. ; z4 ]$ @- x$ m" U
  8.   /* Reset DMA Stream registers (for debug purpose) */
    " d+ [, v8 v1 [3 J4 x$ n
  9.   DMA_DeInit(DMA2_Stream7);% S  Z1 r1 \- V( q9 n, G

  10. . S6 p+ i; P& w5 q
  11.   /* Check if the DMA Stream is disabled before enabling it.9 a5 `5 J( h( @& U
  12.      Note that this step is useful when the same Stream is used multiple times:; N6 s# C& v2 f# d7 k  E2 E
  13.      enabled, then disabled then re-enabled... In this case, the DMA Stream disable
    2 ]) `0 W7 o* I' _3 P# U) K
  14.      will be effective only at the end of the ongoing data transfer and it will
    $ F$ W5 H9 ]9 e0 S( p) ?$ ?
  15.      not be possible to re-configure it before making sure that the Enable bit
    % b! G7 |" D: O; W9 l7 {
  16.      has been cleared by hardware. If the Stream is used only once, this step might
    - G" P& l$ j1 {5 z
  17.      be bypassed. */
    6 W# l- b* X" Q, |
  18.   while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE)
    0 z3 T2 m! o7 c
  19.   {
    3 ], Z. a# J+ M  }. m; J9 I4 S. |
  20.   }
    6 b2 _5 _: C& G& ?
  21. $ k+ R$ ]% _# s0 \
  22.   /* Configure DMA Stream */
    8 W1 d# l' ^: t5 m4 T
  23.   DMA_InitStructure.DMA_Channel = DMA_Channel_4;  //DMA请求发出通道( x3 C" m, A; O0 b5 Z
  24.   DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;//配置外设地址  z1 |! `5 v% ]6 A6 g( g& ?
  25.   DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)UART_Buffer;//配置存储器地址/ M: C' P* h, B$ O
  26.   DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//传输方向配置! e4 X  x' g! k# b7 `# ?' M
  27.   DMA_InitStructure.DMA_BufferSize = (uint32_t)UART_RX_LEN;//传输大小; {2 l6 ^- X) o9 C) `
  28.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不变& N% z! ?$ |$ n& R9 H3 U
  29.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//memory地址自增' x/ ]4 ]; T$ B" z8 i' H0 z% l  p
  30.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设地址数据单位6 v1 B: V; o- U" ~9 }
  31.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//memory地址数据单位
    $ i, y1 Z' e/ O2 o, ^7 ?
  32.   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//DMA模式:正常模式! v& v$ ?; T" s6 V
  33.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;//优先级:高
    ) o% z. T4 ?+ @% z# E( T' E
  34.   DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//FIFO 模式不使能.         
    6 y7 ^+ Q' Q% l8 g" s* v; u5 c
  35.   DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;// FIFO 阈值选择
    & I. Q2 R+ p9 h
  36.   DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。3 p" f' v5 Z" x) o, }; e, b
  37.   DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。
    " {: s2 S  [' |( P9 D
  38.   DMA_Init(DMA2_Stream7, &DMA_InitStructure);
    5 D4 P( o  V* R) T6 S# N
  39. # ~, u3 k# }; t6 [# }
  40.   /* DMA Stream enable */
    + J: q* Y4 d7 O% I9 j
  41. //  DMA_Cmd(DMA2_Stream7, ENABLE);
    : Q7 Y1 N8 k" v2 A
  42. }</font>
复制代码
这里也是常规的DMA配置流程,不明白的同学请看文章《STM32DMA详解》,这里值得注意的是,配置完成并没有使能DMA2_Stream7,使能了就会立即将UART_Buffer的数据发送出去。
8 Z$ ~1 y" N- X" t, b其他代码处理
7 p4 a9 d) A' ^* f# m
  1. <font face="微软雅黑" size="3">void USART1_IRQHandler(void)' F( g) G% R  Y) C2 F
  2. {
    7 r. ?& [) E) S6 a
  3.   uint8_t temp;
    ! T) G& b: H! V, P8 x& X; i$ ~5 i
  4.   if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE) == SET)7 f6 R8 ]- ~4 W2 R+ \+ B  ^
  5.   {/ U5 \) ]" a9 s' S$ k
  6.     DealWith_UartData();
    9 D3 Q2 T5 B6 f8 y% }( W9 d/ d. N% i
  7. //    USART_ClearFlag(USART1, USART_FLAG_IDLE);
    2 ]8 e" e5 i! Z% O
  8.     temp = USART1->SR;  + P$ r1 Z8 ]6 S. X% e8 \& a
  9.     temp = USART1->DR; //清USART_IT_IDLE标志  
    / g; v! ?' A8 N; ?8 G
  10.   }( K7 G/ t" y: U
  11. }; ]  d3 h* p/ p& L0 Z

  12. 4 H5 v  n! H$ R, c$ m- O
  13. void DealWith_UartData()
    # _" X) F$ O8 P0 V3 i- e
  14. {* t2 u% V' c& ]- g2 {
  15.   DMA_Cmd(DMA2_Stream2, DISABLE);  H5 h/ ]: z8 P6 g8 E6 ?
  16.   UART_Receive_flg = 1;
    ! W) @4 a! x3 B
  17.   UART_Receive_len = UART_RX_LEN - DMA_GetCurrDataCounter(DMA2_Stream2);
    6 A8 K: h# B7 l8 d4 k# s) U4 @
  18.   UART_Buffer[UART_Receive_len] = 0;
    % [9 y  k" G8 |* U  V% |: O  |
  19.   DMA_SetCurrDataCounter(DMA2_Stream2,UART_RX_LEN); + @! N6 i" s+ L; f
  20.   DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2);4 f+ u6 |1 \- h
  21.   DMA_Cmd(DMA2_Stream2, ENABLE);8 T% E6 u2 c* x% l
  22. }) Q' m$ w$ U* V! m! ~# w, h
  23. $ x/ E" Y6 a0 X
  24. int main(void)1 w3 b; L: L: s
  25. {8 _5 m0 a/ {) }# \9 V
  26.   UART_Receive_flg = 0;5 P* l2 @. E/ e! [

  27. ! P) w5 q6 Z& t+ [" H; G+ J% q2 Y. j
  28.   Uart_Reveice_DMA_Config();
    0 S& m$ f3 l8 X0 E/ \! H( V
  29.   Uart_Send_DMA_Config();
    : H5 R, F# T) w7 X: W
  30.   UART_Init();* q  N- |0 ]- c3 s

  31. ' D: j- ?) u* k1 W
  32.   while (1)! G% q, B9 E7 }8 a8 Z. x
  33.   {9 F  l0 n% d, j3 O* y% @
  34.     if(UART_Receive_flg)7 o* U9 [$ T0 c5 o! [
  35.     {
    ' X2 R' ]7 y: ^
  36.       UART_Receive_flg = 0;
    2 f  ?/ h) W/ z% y: O" Q' a" M
  37.       Uart_Send_DMA_Start();
    0 G4 ?7 P! ~" u
  38.     }
    + b+ u% y1 _* u2 ~
  39.   }
    ' [) [6 l% ^8 }: w4 X3 v
  40. }</font>
复制代码
上面3个函数,简单逻辑就是,当串口使用DMA接收了一定量的数据,就会通过串口DMA发送出去,串口DMA发送的代码如下:) p4 t- k( Q0 A+ x( b1 E
  1. <font face="微软雅黑" size="3">void Uart_Send_DMA_Start(void)
    1 m0 K. N2 `; j" {, P$ {. U
  2. {
    * o+ ?( T- {1 Q( |# y/ X4 |% @
  3.   DMA_SetCurrDataCounter(DMA2_Stream7,UART_Receive_len);
    9 b1 ^5 W8 h4 C" `9 C& ]; ~
  4.   DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7);+ U4 }) Q* g& O) p. m4 \
  5.   /* DMA Stream enable */8 f8 S7 o: y( k& K
  6.   DMA_Cmd(DMA2_Stream7, ENABLE);2 n9 k; `; K6 }
  7. }</font>
复制代码

# S: }# `: E' {# u1 P8 j" U0 ?- [( D
赞 收藏 评论0 发布时间:2021-7-20 13:45

举报

0个回答

所属标签

相似技术帖

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