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

【经验分享】STM32 DMA程序示例

[复制链接]
STMCU小助手 发布时间:2022-3-28 22:00
01. DMA简介
9 n) y  q( G& J. ]  lDMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。# y) |5 @# }5 R8 v' N  ?9 Q* E
/ _$ z6 P1 Q" Q) r5 y! b7 p
STM32F4 最多有 2 个 DMA 控制器(DMA1 和 DMA2),共 16 个数据流(每个控制器 8 个),每一个 DMA 控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共可以有多达 8个通道(或称请求)。每个数据流通道都有一个仲裁器,用于处理 DMA 请求间的优先级。
4 |# N9 ?9 T! e9 H- [! {8 j0 P1 O$ |4 {# M2 d- H2 d+ j
02. 功能描述
8 p; g- T* f- m* u2 d8 r4 u$ V% C利用 STM32F4 的 DMA 来实现串口数据传送,并在 TFTLCD 模块上显示当前的传送进度。! F! _2 I, D2 s$ n

5 E' ]# y) ]  v- q# @4 Q* H03. 硬件设计
- |( g: X6 i& r硬件资源有:7 q$ m3 Z2 @' w2 A. s1 x$ A
% G6 _8 Q! f5 P
1) 指示灯 DS02 E) h! F& U: r1 |2 {5 G: U6 Z# f

! S3 [% k# c$ Z2 e4 A* h2) KEY0 按键
' L+ X$ ]+ e) b8 c# k6 _: N$ R' m; m4 O' r# o
3) 串口6 l: y1 j( w  L7 Z! O! ]  t. p- B/ K

( Z' d% c. j6 p4 N$ T4) TFTLCD 模块
5 B6 H/ y. a! B7 o4 G( }; C( c$ p8 E4 Y. ?: K8 d9 Y
5) DMA
, g5 h7 Z; K/ S+ j
* w* v6 Z( L* h9 v! Y5 h0 p04. 程序设计
3 [2 M+ Z: Y6 e& h2 {0 _$ [% ydma.h7 o3 Z- n& G; `3 c! {0 k
/ [2 c5 `) D2 }5 t7 X# A- P$ _6 u
  1. #ifndef __DMA_H__
    , q4 `9 [+ [+ m4 Q6 ~0 P! R& s9 g
  2. #define __DMA_H__
    * z" t" g5 y# y1 y% f( a

  3. / U7 P, _0 Z, Y/ P
  4. #include "sys.h"& j* m" P5 x0 w

  5. " w" ^! X5 R4 _( E
  6. //DMA初始化
    + @* M; p1 V' O5 C
  7. void MYDMA_Init(DMA_Stream_TypeDef* DMA_Streamx, u32 chx, u32 par, u32 mar, u16 ndtr);
    % K* l$ |: j; `$ l* Z* i' n5 K
  8. , g. U* T( D' y" e' {  X
  9. //DMA使能# L& R8 y+ Y6 w
  10. void MYDMA_Enable(DMA_Stream_TypeDef* DMA_Streamx, u16 ndtr);
    9 B0 ^: e% h; M, A" ^: ?4 h. h

  11. 8 ]& ]' _* @" I+ t1 K
  12. " G4 D  ~) o7 k* M: i2 y! h' e
  13. #endif /*__DMA_H__*/% n( j5 i' D/ a8 A; P% U, \# m% D- G
复制代码

3 D% R3 q) I% w5 q0 q: @+ mdma.c
' y9 M$ \: \0 E$ @2 x' _  w6 l( n6 `
  1. #include "dma.h"  M/ L* }" O7 \7 f
  2. : K6 J' T2 q  M2 G6 I4 b) g

  3. / \4 P: M1 a9 P4 X" j
  4. //DMA初始化# m/ }( W9 m# a* A
  5. void MYDMA_Init(DMA_Stream_TypeDef* DMA_Streamx, u32 chx, u32 par, u32 mar, u16 ndtr)" |/ u  c0 H  {5 I
  6. {' I1 Q+ S! ^' p1 ]2 |/ w# h
  7.         DMA_InitTypeDef DMA_InitStructure;
    $ p* O6 G) `+ K- g5 ]
  8.         9 }5 Z1 E( F# \- N2 D" L* d, _0 Q
  9.         //判断是否为DMA1或者DMA25 L& j7 `# M' T* `
  10.         if ((u32)DMA_Streamx > (u32)DMA2)
    . J+ |2 F3 q& L8 H/ |
  11.         {, Q* N0 c/ K* j+ R5 X2 u0 B8 g5 i3 c
  12.                 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);) e. f& L- T# X1 t# D& Z, P: U
  13.         }) A) \( {8 F2 Q8 H1 H
  14.         else
    ( p8 M9 R+ ^; `
  15.         {' c: t+ ~- S; b* B0 w% F0 U
  16.                 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
    2 p& Y( m+ N! c& h6 A7 A
  17.         }" W' b0 m+ L1 V
  18.         
    + g+ i4 a; h+ R
  19.         //反初始化* d2 o# k9 U; n! u' Y; t  c* j) M
  20.         DMA_DeInit(DMA_Streamx);+ \. v4 ]  |! s! x1 X  a9 I
  21.         9 g7 J: f  a( K1 o$ J+ N
  22.         //等待DMA可以配置+ T8 g+ V% U& J1 P
  23.         while(DMA_GetCmdStatus(DMA_Streamx) != DISABLE)! F, y0 {# P8 I% C  \+ g
  24.         {
    5 Z# R* `- U# `" @
  25.         }6 W# D' P- D! V5 o" u5 m
  26.         
    ; A) Z7 p* u( t1 @* a
  27.         //配置DMA Stream  c5 U% G5 f" o, f
  28.         
      }9 k. q9 i1 f, j
  29.         + b, b9 Y7 V& l, F2 Q  U$ v  d
  30.         //通道选择
    8 L6 d1 v! P! H4 U3 t* s
  31.         DMA_InitStructure.DMA_Channel = chx;
    * t, p' t4 e. ]; w  d) K
  32.         //DMA外设地址' J. \6 w, D$ x5 z; n6 `. r1 j' m" J
  33.         DMA_InitStructure.DMA_PeripheralBaseAddr = par;- _/ w1 t- |* M6 v: h+ d4 ^9 R
  34.         //DMA存储器0地址
    / C0 v* P0 Q# N) R5 d4 c, ~
  35.         DMA_InitStructure.DMA_Memory0BaseAddr = mar;. ~- @8 t4 {! r0 \4 E, o' @
  36.         //存储器到外设模式7 A) n" w. b3 g+ e2 E: t# D" }1 z
  37.         DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;- l' e, V6 f, W4 o: Z/ v
  38.         //数据传输量& D; l2 l) K. |; K
  39.         DMA_InitStructure.DMA_BufferSize = ndtr;8 x" x8 |- a( X$ p2 J( D# e
  40.         //外设非增量模式) |& t& |2 h( H4 B+ g% Z; g! e
  41.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;4 g: w+ [& S& ~* o- e
  42.         //存储器增量模式
    ( ~7 V6 G8 g; B+ q; N( V, G5 o
  43.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;1 M+ u/ Q. j) o4 o# K
  44.         //外设数据长度8位* `- \- Y4 k* o& z; u8 b! i" Y0 n* q7 _
  45.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    * s+ W8 I8 F9 y- g
  46.         //存储器数据长度8位
    $ W" i% Y' U* z# n# L! V. ^
  47.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    : @/ J7 O4 `8 i3 |/ j# e% |
  48.         //使用普通模式
    4 g6 i) T$ t1 B9 s
  49.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;5 U1 t3 G6 F: V9 S% o& h
  50.         //中等优先级: G) C" Z  j8 b0 d
  51.         DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    6 E& z* L) L! T1 T, ^1 j9 k
  52.         //关闭FIFO模式
    0 M* C! N( f1 l1 d, R* z
  53.         DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;) D' d. W. R* R
  54.         //选择FIFO阈值 没有启动FIFO 随便选择
    ! d1 i! s9 h& e. c
  55.         DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;; n4 \% s3 x% h, Q! r- ~$ s
  56.         //存储器突发单次传输
    & V* C! W$ r: H% ~) s3 A+ J
  57.         DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    7 A* r5 Y' P& |  R# U/ N0 |
  58.         //外设突发单次传输4 P( e8 u! y# g5 A- u7 {
  59.         DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    . |" Y4 M7 A* m1 x& a, C" Y
  60.         //初始化( T' X8 z) J# R# W8 ]4 d3 R
  61.         DMA_Init(DMA_Streamx, &DMA_InitStructure);
    ! W) W3 [- G* T5 o
  62. }1 V5 {  A5 n# H
  63. 2 j. @# N9 _6 i) v* k( v3 c' Z
  64. //DMA使能6 V7 `$ J$ T' w& Q. I
  65. void MYDMA_Enable(DMA_Stream_TypeDef* DMA_Streamx, u16 ndtr)& @$ c. X8 [; P
  66. {
    # s4 o: u' V5 g7 S" \6 N1 o* D
  67.         //关闭DMA传输( s5 w$ K' t( d) _3 l1 B" F
  68.         DMA_Cmd(DMA_Streamx, DISABLE);
    8 t0 T: F4 F# q6 }
  69.         
    * @$ ^$ G% X' B9 c% d& o
  70.         //保证DMA可以被设置
    3 d& k% L* S5 t% G: E6 T- \% k
  71.         while(DMA_GetCmdStatus(DMA_Streamx) != DISABLE)
    $ {- B. d4 Z- ?- R1 i6 W$ j4 `
  72.         {+ z& d$ ^9 {4 f8 A
  73.         }
    ) L9 w4 I' m6 @( h8 `; q

  74. ! l/ ~. X* R) j2 b) M- L& U
  75.         //设置数据传输量3 p9 j. w1 j  u4 U4 _
  76.         DMA_SetCurrDataCounter(DMA_Streamx, ndtr);
    ) t- d# @5 d& D6 F. m3 A! N0 q' n
  77.         
    6 @, {. k3 y4 q8 v
  78.         //开启DMA传输+ K% V, I3 w( u
  79.         DMA_Cmd(DMA_Streamx, ENABLE);+ W( ~' |" |9 @, R7 K. F
  80. }
    & Z8 D! o: t, e: F( n
复制代码
4 W# c8 M$ I2 l+ o0 h" t  x
main.c
. X  a! k' ~3 r9 A; j! v  l) U! f$ W0 o5 I: o
  1. #include "sys.h"+ e9 I, \( S, M, B
  2. #include "delay.h"
    ! {. O$ S3 f2 Y2 K' `& ]
  3. #include "usart.h"/ e1 t( Y5 U% o- \: U! a* R; Y
  4. #include "led.h"" a2 o' v# Z5 M  \
  5. #include "beep.h"1 d1 Y" Q1 q' g6 u
  6. #include "key.h"& {' K) r! z* h
  7. #include "usmart.h"  I& ?& e: b/ F# s; _
  8. #include "lcd.h"
    5 x) I4 i+ s: `
  9. #include "rtc.h"
    + R* q) H2 B  z7 D
  10. #include "rng.h"
    & A1 n* H7 s# m8 i' S
  11. #include "key.h"
    , }% i# y: k1 m- T2 T! R9 c# F
  12. #include "wkup.h"5 F3 s" r3 I% ^! a. }; l* S+ }7 o6 u" r
  13. #include "adc.h"3 i* V7 Q" e* g
  14. #include "dma.h"
    - b( {3 O9 Y" d/ L9 h# \, Y5 ]

  15. 5 O/ b- x1 a( W$ [
  16. 9 e, z. p( R; I. `) S
  17. #define SEND_BUF_SIZE 8200        //发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.
    : }0 @7 I0 H9 A' I- A
  18. 6 X8 t% D, r* p9 V4 [
  19. u8 SendBuff[SEND_BUF_SIZE];        //发送数据缓冲区% q; d3 V0 H( U# Y/ \$ n3 u5 j
  20. const u8 TEXT_TO_SEND[]={"ALIENTEK Explorer STM32F4 DMA 串口实验"};         3 O% n8 V* q. m
  21. 1 K  V5 e* ^& D$ p2 w

  22. 2 [4 l( u% O+ b; n
  23. * J9 N" `, `8 z9 z
  24. int main(void)
    ! \; A6 s" w( J1 H: g
  25. { 8 X$ l4 s; n5 t( \) Q6 M
  26.         u16 i = 0;% ]* i9 a" H+ i# }9 n$ F
  27.         u8 t = 0;9 |' ?5 p- v) x5 K) [, D
  28.         u8 j, mask = 0;1 F& p% ^6 ~4 h& G5 H
  29.         //进度
    + ^) u0 y2 N5 k# v2 D2 V( H, D
  30.         float pro = 0;
    $ g1 f0 {0 I9 n5 o/ r

  31. # K  B  e: d% h7 q% j( b. @

  32. ! O. i, H% K/ z$ O+ K$ |
  33.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2% h% U+ X6 v1 e3 ?) G, b
  34.         
    0 y7 i. g6 B3 \, `
  35.         delay_init(168);
    " W7 H* o, P* b3 d8 V
  36.         5 C' s) ~% `) B8 x$ o
  37.         uart_init(115200);
    ' s" z' ]3 r) ?+ r
  38.         - E4 s$ O: `' D( P6 U
  39.         LED_Init();
    " s+ F7 M, c) D2 s% q
  40.         KEY_Init();
    1 }; n1 l+ e8 O! @0 U! }
  41.         LCD_Init();
    2 \! g+ m: {( g0 _$ H: Z
  42. 0 g5 W7 Z+ |- r, H' G, i# Q# m
  43.         MYDMA_Init(DMA2_Stream7, DMA_Channel_4,(u32)&USART1->DR, (u32)SendBuff, SEND_BUF_SIZE);, F6 {9 t# C! v8 B) _' ?/ O: H

  44. - x; f6 T& }; q( Y* G5 ~& Q2 d+ ]1 q
  45.                 * s$ l! v6 E  K- D$ \
  46.         POINT_COLOR = RED;
    9 Z4 B" D2 D/ U+ A% c; }) K
  47.         # ~) C$ a- o7 Q; x& c
  48.         LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");        . ]/ _( W# @3 s" {8 c
  49.         LCD_ShowString(30,70,200,16,16,"DMA TEST");        
    : T4 V8 Z! @& M; V7 P
  50.         LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");/ ]2 t1 V/ w' l; @+ m, o
  51.         LCD_ShowString(30,110,200,16,16,"2014/5/6");         
    $ [0 Y: ^( }( ?, A: u' v; U
  52.         LCD_ShowString(30,130,200,16,16,"KEY0:Start");         
    6 Y3 c! |% I3 [5 S% d. y
  53.         POINT_COLOR=BLUE;//设置字体为蓝色
    , ]$ d' _8 D* ~, z1 x
  54. ; ^; @" ]9 r( i! j- e
  55.         6 ^0 K) Y  [9 N: c
  56.          //显示提示信息        0 Z6 V3 e5 i8 w# L
  57.         j = sizeof(TEXT_TO_SEND);           
    8 Q& J4 O0 A4 W7 T  z/ ^3 d  S
  58.         for(i = 0;i < SEND_BUF_SIZE; i++)//填充ASCII字符集数据& _; h6 S5 X) P+ K# [
  59.     {1 a; h  B' ]; @2 Q/ Y5 J
  60.                 if(t >= j)//加入换行符  p0 C2 l2 m. O; u( r0 v6 r
  61.                 {
    ( o& h" N" x! w7 s  G' m
  62.                         if(mask)
    / W3 x+ o8 h/ v/ k& l& v
  63.                         {
    8 t. n+ \5 y3 Z8 O% T
  64.                                 SendBuff = 0x0a;
    7 Y2 G9 T: O, s1 n
  65.                                 t = 0;8 u: n1 K/ y! J& h: _" j
  66.                         }else
    4 Z' C1 _3 m+ b( c% i# ^
  67.                         {
    # y3 s# W% N1 @$ [, h' o( K
  68. SendBuff = 0x0d;" C& D: x$ ?2 z
  69.                                 mask++;' O: v* q+ ^! h4 @' U2 V* L" B- T* q
  70.                         }        8 T! Q6 w9 j# [5 h" N
  71.                 }2 q6 {' C. ^' C1 U, V7 T4 r
  72.                 else//复制TEXT_TO_SEND语句
    ) ^" E/ q6 ?- P3 F( ~
  73.                 {+ v! o, P5 z% f* i& R. a
  74.                         mask = 0;/ R4 q. Z, s7 |8 N  l$ a; P
  75.                         SendBuff = TEXT_TO_SEND[t];
    ( j7 I* l  H1 L& b7 U
  76.                         t++;
    + w3 F4 @  ?$ w) {- v  c" W
  77.                 }              
    % `$ T. `  r# y8 ?0 h6 U
  78.     }                4 P' \( r1 D' J' F) G# I/ p* @
  79.         6 t- G* r8 k! q8 H0 X
  80.         POINT_COLOR = BLUE;//设置字体为蓝色        , J, G! B7 h3 M8 u& E
  81.         
    3 @% d) m% H5 d% ]- k* w+ m* i
  82.         i=0;
    0 I9 X* u- l2 i' d
  83.         
    ( |; g. H. ]  u& D: _3 W2 ~3 P- O
  84.         while(1)
    1 Q' V8 ^! @7 f0 }  a# d- v
  85.         {) i/ w! z7 k5 W& J% ^' l, D
  86.                 t=Key_Scan();
    / D. Y6 g( `- Y. S0 T9 d# m# ], z
  87.                 if(t==KEY0_PRESS)  //KEY0按下  T  P- W+ U0 R2 ]& }7 s
  88.                 {
    ! Z; W1 e& \& w: {3 O/ m6 K! g, v
  89.                         printf("\r\nDMA DATA:\r\n");            
    * f; h7 C. i4 q" `
  90.                         LCD_ShowString(30,150,200,16,16,"Start Transimit....");
    , L6 {2 i- B! H6 D! m
  91.                         LCD_ShowString(30,170,200,16,16,"   %") ;     //显示百分号      
    8 X# i6 X% |. h4 p) N
  92.                         USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  //使能串口1的DMA发送     
    : g; p6 v, U. d/ T* @& k
  93.                         MYDMA_Enable(DMA2_Stream7,SEND_BUF_SIZE);     //开始一次DMA传输!         
    $ f, a; j8 z5 V. m& _% c; U
  94.                         
    . y2 K& ^8 h/ C" }" ]+ X; X
  95.                     //等待DMA传输完成,此时我们来做另外一些事,点灯6 A" B" l8 K1 _- G2 v
  96.                     //实际应用中,传输数据期间,可以执行另外的任务
    - {6 g  @" z/ D  ]- K
  97.                     while(1)* [  u; A- f. ^' \4 g
  98.                     {
    2 F* D' z# f5 Q# u
  99.                                 if(DMA_GetFlagStatus(DMA2_Stream7,DMA_FLAG_TCIF7)!=RESET)//等待DMA2_Steam7传输完成
    9 l% U! k3 h8 n; ]
  100.                                 {
    $ w7 b; g& ^' ~5 z- b' h2 J9 x) J
  101.                                         DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7);//清除DMA2_Steam7传输完成标志
    2 t/ q7 ^) q; ^5 y# Y6 B1 m
  102.                                         break;
    - W5 R, }) N7 l2 l' s: U
  103.                         }7 N! y; I- v) S# c) D
  104.                                 pro=DMA_GetCurrDataCounter(DMA2_Stream7);//得到当前还剩余多少个数据
    9 v7 l5 J. ~% }$ f/ O3 a! ]
  105.                                 pro=1-pro/SEND_BUF_SIZE;//得到百分比         
    6 j  F: L5 ?5 w+ p7 n! q( G
  106.                                 pro*=100;                                  //扩大100倍4 T. t. d4 S& u; o
  107.                                 LCD_ShowNum(30,170,pro,3,16);         
    % N7 c8 W$ C. i5 i
  108.                     }                           
    & R8 z6 e3 u6 y& \) U6 z, w
  109.                         LCD_ShowNum(30,170,100,3,16);//显示100%          0 ^0 H! w8 b8 U- U. y
  110.                         LCD_ShowString(30,150,200,16,16,"Transimit Finished!");//提示传送完成
    6 w" e, U% J1 g5 b& _$ r% c
  111.                 }
    9 o- U, C$ b* d4 |' Z. E
  112.                 i++;. I- v6 Q  r- T. K8 F; @
  113.                 delay_ms(10);2 J' w+ h( k/ v* ]* _
  114.                 if(i==20)
      a4 [) O1 A! h( i2 o
  115.                 {. f" X6 N7 c# Y$ R3 Z
  116.                         LED1=!LED1;//提示系统正在运行        
      w6 S# X; J! n0 P( M
  117.                         i=0;
    + @  t. B$ ~; O# |
  118.                 }                   2 @4 _% B+ Z' E; d
  119.         }                & ~0 i8 [+ d' L! B: U( w
  120. }' r; z0 V5 f/ [; K+ u
复制代码
" {7 ~/ j6 d$ [. A8 j& e: `
05. 结果验证

4 h* S: G2 I- w1 k3 @* K0 V0 YDS0 的不停闪烁,提示程序在运行。我们打开串口调试助手,然后按 KEY0,可以看到串口显示的数据。
. f2 P9 v9 _2 j1 Z7 Z, T7 @. t$ J* }
& O- e- [5 {( ^) F  r
赞 收藏 评论0 发布时间:2022-3-28 22:00

举报

0个回答

所属标签

相似技术帖

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