本文通过一个小的设计来进行讲解,将STM32内部存储的一个数组中的数据,通过DMA操作复制到第二个数组里,并用USART1串口将第二个数组中的数据输出到电脑端,进行检查,看是否复制成功。
) g' U7 ]$ C8 F* T1 ?' x' F3 |4 ^+ u5 o; r% ~# z( ~
首先总结全文,,使用STM32进行DMA操作的主要过程如下:" P5 ?9 m5 i# @" i& K- O2 Y+ _3 C
1,初始化GPIO$ Z! L5 H& v8 V) E3 F1 y) o
2,初始化串口
- x; a0 F/ J% t1 j3,初始化DMA
& x, i- ?! X3 I& n1 F; h4,编写主函数1 r6 Z5 P! e! e! u
- | u6 j" e& s( Z) d下面介绍详细步骤:7 L% j- q1 l7 e3 T( F
2 v9 L, {* V; q' A5 e C1,初始化GPIO6 T) _$ e# F2 i7 b @4 e9 M) Z7 R
- void IO_Init()" p0 j- U+ G3 A( i
- {
5 F) r( m+ o7 e! `. Z3 D: l/ X - GPIO_InitTypeDef Uart_A; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
3 b9 ~7 r# [- o6 r$ J - Uart_A.GPIO_Pin = GPIO_Pin_9;2 R. w) C) r& m P
- Uart_A.GPIO_Speed = GPIO_Speed_50MHz;6 x% `* V6 g* `$ @
- Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;
5 d2 K) q1 C, R! z& J, U. n$ s: ]1 E - GPIO_Init(GPIOA,&Uart_A);) l: A! ?$ v6 z6 S0 a4 r
- 9 q3 F& r/ c9 ~. p5 E
- Uart_A.GPIO_Pin = GPIO_Pin_10;& c( G6 `0 D8 `; v+ `
- Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
z3 f) I$ e# F9 f) f% a+ @ - Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //page 1100 W1 a- F; p$ G0 p3 c! Y
- GPIO_Init(GPIOA,&Uart_A);
3 x% K' W+ _, J% g - $ F* s# t0 h Z& p5 v2 Y0 N' s
- }
复制代码
& q. u5 S0 G& f8 q; M2,初始化USART1" P) W7 Z! ^+ u [# X# m
- void Usart1_Init()
: p b1 e7 k8 E4 i2 ~0 n- o - {
( f) w' T! [8 z; r8 k/ ?2 s/ @ - USART_InitTypeDef Uart;
t6 W" K7 M+ R - 8 q3 H. _' p6 U7 V H
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
, w: N. w! |, |3 B - Uart.USART_BaudRate = 115200;0 N3 h0 G$ ^, o
- Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
$ X; j' S) @/ y; k0 l - Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
) w# D }/ _2 u! q# Y# c9 T* W - Uart.USART_Parity = USART_Parity_No;
: F. h1 t2 c* m" w - Uart.USART_StopBits = USART_StopBits_1;
9 I* c7 b0 Z4 W, L5 G - Uart.USART_WordLength = USART_WordLength_8b;
: k# R3 c1 x& i! g+ H" W) c% [ - USART_Init(USART1,&Uart);
( u; V/ f1 b! e2 K- N5 O - ( i" [' U+ ?# m- U
- USART_Cmd(USART1,ENABLE);
" I' ~8 j- G5 D1 W" B+ o - USART_ClearFlag(USART1,USART_FLAG_TC); //page 540- O5 ?# w" g F/ z3 C/ j, H
- }
复制代码 9 Y; N- L8 R4 v8 e
. V5 I+ T2 O+ Z; \2 |: R3 ~! E
3,初始化DMA& P4 m3 n) ]: Z! }+ M
库函数中DMA的结构体如下: J g7 a1 x* q- ]8 |6 X8 D! C- m
- typedef struct" ^2 X4 k% l- h3 o }
- {
2 ^- d# |% z0 E3 b6 o5 c. K& m8 ~ - uint32_t DMA_PeripheralBaseAddr; /*!< Specifies the peripheral base address for DMAy Channelx. */
$ K5 y0 O [% K9 Z0 C: @. p -
3 X' f' }4 u! O2 F - uint32_t DMA_MemoryBaseAddr; /*!< Specifies the memory base address for DMAy Channelx. */
0 L# F1 S+ _+ j/ j2 e9 @- s - 4 b; o/ p, }1 n, i' c
- uint32_t DMA_DIR; /*!< Specifies if the peripheral is the source or destination.
" O C2 o% M/ k3 T3 ~) f$ w( n7 { - This parameter can be a value of @ref DMA_data_transfer_direction */
3 C, \- I& _! H. r! s8 f+ E - / M7 P/ \( G: y9 E, X
- uint32_t DMA_BufferSize; /*!< Specifies the buffer size, in data unit, of the specified Channel. ; J0 q/ Z$ c5 E
- The data unit is equal to the configuration set in DMA_PeripheralDataSize
- h: q4 W' O( t C2 T$ B - or DMA_MemoryDataSize members depending in the transfer direction. */
1 _+ z( U+ f" ~; L5 ~ - " v. o- m9 B( ? x6 }
- uint32_t DMA_PeripheralInc; /*!< Specifies whether the Peripheral address register is incremented or not.' i' o2 J( j4 o, h5 i
- This parameter can be a value of @ref DMA_peripheral_incremented_mode */* g0 t! ^" l1 D
- * J5 M8 D# X2 U0 v# L
- uint32_t DMA_MemoryInc; /*!< Specifies whether the memory address register is incremented or not.- Y0 S. k' g9 k0 |
- This parameter can be a value of @ref DMA_memory_incremented_mode */$ M: I( M8 q# u* w+ K9 \, O: C1 w
-
6 N. p3 K7 G0 i0 n$ ?9 q - uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width.
3 Z8 [2 {* K% s - This parameter can be a value of @ref DMA_peripheral_data_size */
* C7 o @, W2 r" A! S6 J1 e& y5 ] - & B; M5 e5 ~0 H0 c/ c* }4 A9 Q
- uint32_t DMA_MemoryDataSize; /*!< Specifies the Memory data width.- C4 I6 t3 m% M3 W, y9 L: e K1 u
- This parameter can be a value of @ref DMA_memory_data_size *// |9 v2 K/ P, M+ A
- / X# a( B8 b. [4 _- r0 t$ m( q
- uint32_t DMA_Mode; /*!< Specifies the operation mode of the DMAy Channelx./ { U/ ] [' R' R4 ?. ?- o
- This parameter can be a value of @ref DMA_circular_normal_mode.
% H- K( o; Y1 ^( B s - @note: The circular buffer mode cannot be used if the memory-to-memory9 w+ |& z3 s. X5 w/ ]
- data transfer is configured on the selected Channel */- i, H6 |6 k0 z! G$ o* S% t/ U, [1 e
-
) r8 Q# s* o4 U( h+ Y1 r1 I - uint32_t DMA_Priority; /*!< Specifies the software priority for the DMAy Channelx.9 }' A& g, n: b" d
- This parameter can be a value of @ref DMA_priority_level */
* L' U# F( j% G" J0 W$ A - 4 L) v H( C! s6 ~
- uint32_t DMA_M2M; /*!< Specifies if the DMAy Channelx will be used in memory-to-memory transfer.
7 g/ @; V) X1 H+ g* A e - This parameter can be a value of @ref DMA_memory_to_memory */" o a$ G' }6 b3 \4 M
- }DMA_InitTypeDef;
复制代码 2 H- f& `' L/ [4 I# H D: G
这个是定义DMA的传输方向,DMA传输总共有三个方向,外设到内存,内存到外设,内存到内存(关于外设和内存可以这样简单理解,相当于一条路的两头); d* }3 M8 |$ b) w9 B- H
, E- I* m- B' J Z库函数中有两个定义:$ z( f0 H l% z/ r. Y
- #define DMA_DIR_PeripheralDST ((uint32_t)0x00000010)
5 B& N" [: v2 H) x; N6 x - #define DMA_DIR_PeripheralSRC ((uint32_t)0x00000000)
复制代码 3 q! m/ b! ]1 q: F+ S
以DST结尾的那个,表示,以外设为目的地,以SRC结尾的那个,表示,以外设为起始点。
9 E) p6 y0 |$ k3 U7 F4 Z) F4 U3 i uint32_t DMA_PeripheralBaseAddr;这个是用来定义外设地址的- Q3 p( q8 l1 p7 c) f- v! R
uint32_t DMA_MemoryBaseAddr;这个是用来定义内存地址的
$ C" a& g9 ^* H6 zuint32_t DMA_BufferSize;这个是指DMA通道的DMA 缓存的大小,这是为了照顾,两边的速率不一致。
, i- C8 K' c: C& l' y1 j; wuint32_t DMA_PeripheralInc;这个是用来定义外设地址是否要自增5 O' W- e+ ^5 e9 P3 N" }
uint32_t DMA_MemoryInc; 这个是用来定义内存地址是否要自增
9 E s4 o5 _! nuint32_t DMA_PeripheralDataSize;用来制定外设的数据宽度1 L' I- t, M# W' R% W5 @
uint32_t DMA_MemoryDataSize;' V$ ?7 D. R! p2 t& ?6 |7 j
) c7 z# J$ y2 V
这个是用来制定内存的数据宽度,当外设和存储器之间传数据时,两边的数据宽度应该设置为一样大小. H% m( ]# `/ i7 F9 c
; w* R5 o, Y9 l4 G" M' D
uint32_t DMA_Mode;
% j: e7 s. E+ x" Z; `, y7 @
, v# A R. r: p这个是用来指定DMA的工作模式,有一次传输和循环传输模式,两种。
. a. Z- |2 {% G5 T; S* @) A, }4 B- \" N1 D6 t8 d) P$ r4 `
uint32_t DMA_Priority;
7 S8 k; D/ o+ |! G4 b! I+ ~/ K4 J& V- y% _; r8 a6 c
这个是用来指定DMA的优先级,有非常高,高,中,低四种。1 [5 T$ c! O: V
3 d! ~ p* B1 t0 Y: y, q& w% e0 h# k3 duint32_t DMA_M2M; 这个是用来设置是否进行 内存到内存传输; k' P% m2 ^4 w
+ u2 H" G+ n7 R. I& U8 P F
初始化函数如下:
; s' X3 B- Q* Z: I7 P2 `1 Z- void Dma_Init()
1 D1 k& v$ l+ Z3 m5 | I - {
7 \: `5 }+ S6 j, C$ p - DMA_InitTypeDef dma;
8 }4 Y& q/ Y, Z! K% r! t - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//老规矩,先开心脏. e, g7 H7 I* f2 v/ g! d
- dma.DMA_MemoryBaseAddr = (u32)zimu;内存地址/ i% S' G @* x1 j& Y
- dma.DMA_PeripheralBaseAddr = (u32)zimu_1;外设地址, M5 c) I0 W+ M, f
- dma.DMA_DIR = DMA_DIR_PeripheralDST;外设为目的地,即zimu_1数组为目的地
; E# R, F! X7 x( Y) h - ( M. ^' U- I- |5 ?7 Y
- dma.DMA_BufferSize = 26;缓冲区大小$ e9 [ |* Q& ]: ~ c6 S
- dma.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;数据宽度
3 q/ v8 l( D; k7 l6 M7 A - dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;同上3 n3 v j. Q3 V; Q3 q& V
- / y* Y# j/ U/ }% r; {' Z
- dma.DMA_MemoryInc = DMA_MemoryInc_Enabl;内存地址自增
9 Y# u9 y& a9 t/ O2 J, s5 p - dma.DMA_PeripheralInc = DMA_PeripheralInc_Enable;外设地址自增; F- l6 j( X# M: Q: L
- - [' @! C* s8 s. ~/ W: g
- dma.DMA_Mode = DMA_Mode_Normal;单次模式" G( W6 G, \8 T7 S' p5 A
- dma.DMA_Priority = DMA_Priority_High;优先级为高* N/ r; W a8 }1 w5 \6 |
- dma.DMA_M2M = DMA_M2M_Enable;设置为内存到内存传输
, N; I& s8 e" A7 K+ p3 Z - 9 J9 C8 l; g& E
- DMA_Init(DMA1_Channel6,&dma);寄存器初始化) Z! M/ H3 n6 d
- DMA_Cmd(DMA1_Channel6,ENABLE);DMA使能
; o1 V2 I1 D+ J# P& y$ b3 y4 ]' ~- e - }
复制代码
0 n. G" F1 C7 G9 L$ S4,编写主函数% X- ?8 A$ m( C! P( z
- int main(): r# W& ?. `, G' ?
- {
$ }" j( L0 S9 o! _- b% k/ ` M - void printf_string(char* a);
$ P# S4 j0 u. d1 n0 s5 }0 v/ I4 \ - IO_Init();GPIO初始化0 O0 F) E, i6 S* N# D: N
- Usart1_Init();USART1初始化2 _5 C& J1 Y1 w1 \4 f" T$ }- V. p
- Dma_Init();DMA初始化0 `& `, ?* }, n. h
- while(DMA_GetFlagStatus(DMA1_FLAG_TC6) == RESET){}//等待DMA操作完成,在参考手册的149页可以仔细看这个寄存器4 ]) p* n* n9 @( Z5 T9 p1 R5 ?
-
' y: @7 W" y- h$ [8 ?, J# N7 K' B( F - while(1){
" P7 X {# ]0 T. k/ `9 O - if(USART_GetFlagStatus(USART1,USART_FLAG_TXE))判断是否能用串口输出
9 M* M O" O: V( L, r, j7 F - {& d/ g: _7 C- f: D
- printf_string(zimu_1);输出zimu_1数组
- w4 ?/ y1 y& d - delay(3000);延时
2 ?- p9 y" X2 ]/ T( |, f. x, s - }
8 _/ y% q. T. V- D: ~& I/ t' R - }
& k7 } }, l, x9 x6 g' L- K - }
: w2 E3 W2 K+ N, f7 } - void printf_string(char* a); H% h/ @9 Y, J) r! u8 r3 r
- {0 A- u: R7 }* Y% R, o2 u
- while(*a != '\0')直到数组末尾' v: w6 x8 Q+ l# ~5 g
- {. R8 M9 n; ~: J& S$ q
- USART1->DR = *a;赋值给USART的数据寄存器
" F$ O( R# p( h; D" m - while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));等待发送成功+ h: {" }& v& G3 Z% I
- a++;地址加一+ A6 ~& J o6 L% U$ l& u
- }" m, D9 P5 x2 ?' ~; A& F
- }
复制代码 ( V U1 G8 m# J
" x1 ] Y- r% R+ _) W本文到此结束,因博主水平有限,如有错误,敬请指出,不胜感激!' n: ?; _; W: e, s1 f- ^! b
$ X/ k5 e- J& C% i# S! v3 r
$ |, C- c0 V- U& U( f亲测,可运行。详细代码如下:% D) M' j t' l l3 L3 e) C; U
- #include<stm32f10x.h>, |# ^+ r: @* W; F$ W4 y% Z
- #define uint unsigned int7 S' H: s" J6 a& G& _4 N
- #define uchar unsigned char, ?* |9 t: `4 } @8 `/ x
-
/ B5 d+ L3 f6 L9 u- P, X9 Q( ` - char zimu[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
* y \' r* H/ } - char zimu_1[32]={'.'};; x* b4 L2 S% G9 P& Q
- void delay(uint n)' y' S6 [5 Q- \1 C; H ?
- {
" U, ?+ F8 }! @% |. W! S - int i,j;
5 C) K; C3 U& U# p, _( X7 T - for(i=0;i<n;i++)
C# k2 p2 \7 w( C( a# I4 K- {' b' r - for(j=0;j<8500;j++);. w8 u9 t) W/ J2 I
- }9 _9 b3 X- f) O. N
-
% u# a1 s1 N& l3 ~& J" O* P - void IO_Init(): F8 S6 _) t" h1 R6 D7 c
- {$ Q3 a8 o* v5 F A8 C5 E4 j
- GPIO_InitTypeDef Uart_A;
' N) L/ b3 N: t% H - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);$ |4 \. q* E* W
-
( e! X0 a. m+ E' M' L, m - Uart_A.GPIO_Pin = GPIO_Pin_9;7 | c. c6 D' {/ Y+ J
- Uart_A.GPIO_Speed = GPIO_Speed_50MHz;# v! W( M9 y- F+ ~* f: Y0 {
- Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;) y' a) k+ Z# H3 ~9 \
- GPIO_Init(GPIOA,&Uart_A);
; r8 i9 Z; P, ?: u% Y - / K0 e* l( d& `0 U' Q/ q M
- Uart_A.GPIO_Pin = GPIO_Pin_10;
z1 c& o, ~: ]7 {& [ - Uart_A.GPIO_Speed = GPIO_Speed_50MHz;- b" i) Y: U! B
- Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //page 110
* J4 u7 E+ D, `( R - GPIO_Init(GPIOA,&Uart_A);
/ ~# e$ W& `) h5 G; ? - & x/ W* v; n- o, V3 I" j b: L) w- B
- }/ Z9 o0 S& X% ?# I) e4 p
- void Usart1_Init()
6 W; z7 P' r2 x+ ?) R1 y; p8 c) T) q - {$ G. h9 X/ Y0 Y. p* x( W" d
- USART_InitTypeDef Uart;) z3 i$ X: ]' v7 j4 e
-
. u! P* |; ^. ]( B; f$ D+ @ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);3 k: x! B: Q5 c6 t
- Uart.USART_BaudRate = 115200;! R/ n) v. O2 ?; ?
- Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
y' e m% T$ y - Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;" t) j) C( P+ a
- Uart.USART_Parity = USART_Parity_No;$ l/ O$ E% }3 a
- Uart.USART_StopBits = USART_StopBits_1;
, C9 c" }! p1 @3 d8 c' \ - Uart.USART_WordLength = USART_WordLength_8b;6 M7 u+ X8 B! x. Q
- USART_Init(USART1,&Uart);; Z* b6 R- o6 A8 Y2 \# P- y
-
& }8 ]/ e4 H3 \* H - USART_Cmd(USART1,ENABLE);
! o' ]% D9 } Q- I - USART_ClearFlag(USART1,USART_FLAG_TC); //page 540* J0 `& ]- i' X% I# X1 I
- }
+ H* k2 T" n. C - : b A/ a# q/ q5 g
- void Dma_Init()* Z J6 C9 O: _3 a( C, A
- {; C! T6 C6 f- g$ p3 X6 E1 c
- DMA_InitTypeDef dma;
" l H7 N1 D5 @ - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
/ U) W [& z+ J) L7 U/ ?+ Q - dma.DMA_MemoryBaseAddr = (u32)zimu;
: Y% b' d% O7 E, I ?7 q - dma.DMA_PeripheralBaseAddr = (u32)zimu_1;
: d$ s- E9 `' q - dma.DMA_DIR = DMA_DIR_PeripheralDST;+ ~( A$ k$ {( q. |( R8 G
-
) q5 t! x8 v8 k" {# q# { - dma.DMA_BufferSize = 26;# v+ R$ X4 E! `" I& }1 w) _% H
- dma.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; o3 h! Q2 c) Z
- dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;" Q; f# O" `+ z. s9 M
- ' ^! Z# w/ c* L& @7 Z! u- w/ z# w# b
- dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
$ D: u8 Z0 _7 B$ ?; q) i& J- H - dma.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
# e4 `1 C' I. }8 o% w/ [ - 8 h- X! {1 M$ e3 H+ _) t
- dma.DMA_Mode = DMA_Mode_Normal;
" W% _' }2 H, F% a6 L+ t7 w - dma.DMA_Priority = DMA_Priority_High;1 w! }8 [8 |' k9 Q$ o/ U
- dma.DMA_M2M = DMA_M2M_Enable;; k; y0 X5 z: x8 v: X1 F/ C
-
. m' O7 t: x9 x" f x( p - DMA_Init(DMA1_Channel6,&dma);
0 Z9 S+ S; ?& z" o - DMA_Cmd(DMA1_Channel6,ENABLE);+ s2 ?3 G3 Z5 U
- }
3 b, \& k2 J0 b& u# j& g! ? - int main()
: Y" r1 j* g5 d% _: T/ I7 D - {
~; y2 n4 A% q) @! o, x' p, V - void printf_string(char* a);( }6 { q) q2 u2 @' @0 _' W
- IO_Init();+ V6 @0 s+ C4 n6 O0 ~7 D, O6 [
- Usart1_Init();
8 K" H H% a- E9 v - Dma_Init();
3 @8 {. A+ C1 {) |$ |1 p! p" @ - . t6 c4 _1 j: R6 a* b
- GPIOC->BSRR = GPIO_Pin_13;
$ L: h5 P2 Y: q4 G+ D -
; d% ]* ~- n: f+ U; c: G) C( @' g - while(DMA_GetFlagStatus(DMA1_FLAG_TC6) == RESET){}
4 p: R0 A, X3 E& E- O - * K4 w' X: y, Y0 R' L+ l% n# ?& g! |, m
- while(1){, S" D( |( b0 p1 y$ w3 F3 i
- if(USART_GetFlagStatus(USART1,USART_FLAG_TXE))
2 l2 c+ i+ D/ n7 ? - {* v- w' I8 j {* h* n3 z1 u0 Q3 l
- printf_string(zimu_1);5 X2 o1 Y& |# ]3 o
- delay(3000);
5 S, V) A0 L$ E: C" Y) W - }% R2 v. i4 T' l! f- n3 L+ d
- }7 F9 O- y% d7 R" V8 t' u
- }2 H- b6 ], s9 E3 c F
- void printf_string(char* a)8 ~; j! v, l* s' k& e! M# Z+ B) J
- {
* j$ G1 U0 @+ O* L) | - //USART1->CR1 &= ~USART_CR1_TXEIE;1 x- k: X0 q, m0 G3 {1 ?) F
- USART1->CR1 |= USART_CR1_TXEIE;
+ n* t% {7 Z, }7 w - while(*a != '\0')
6 V+ o4 k% w' X/ R6 X - {
& j$ ~8 p8 G8 ^8 P! D" P; Z - USART1->DR = *a;# C, z, Q% D5 M. z
- while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));. b, ]6 X: g) d# [9 \# E
- a++;
: F. o6 E; }4 Z( J5 H/ h# Z - }# g5 D4 b; a, {
- }
复制代码
: u& [: J* ?; L0 n————————————————0 [! q, U8 M+ G& A
版权声明:家安' T9 X* ~( p* g
" g& N! d& }( \7 p! y3 {# I# v! C" B4 ]+ \: m ~2 B
|