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

【经验分享】STM32 DMA总结库函数串口使用DMA

[复制链接]
STMCU小助手 发布时间:2022-5-8 19:00
前言
9 v) o$ r$ v  @/ k6 w5 U! KDMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接* ^" n( `. O9 w4 ~, N0 K# F
控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备; b0 @' y. j1 z, h/ g
开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。
3 ]/ R) ^# B! S/ e
2 m. z  M8 H: R: v% o5 d一、配置步骤
8 J6 N; c9 M1 b' o" ~' Q1)使能 DMA 时钟

3 A3 h6 E/ m: ?
' {7 f( W6 O8 M& U: H* A
  1. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能 DMA 时钟
复制代码
/ p! w: e3 N* K6 n: \: {

5 d' q, F/ i, q& Y) m2)初始化 DMA 通道 4 参数

3 J7 y6 M7 S6 b/ e1 Y1 |( M1 d, m* n' d$ ]
  1. void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)
复制代码
  1. DMA_InitTypeDef DMA_InitStructure;8 v7 H& R* F% _
  2. DMA_InitStructure.DMA_PeripheralBaseAddr = &USART1->DR; //DMA 外设 ADC 基地址
    % g0 P9 f, t  y9 t7 a6 H
  3. DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA 内存基地址
    " t' n2 X( f  \7 w
  4. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //从内存读取发送到外设
    & }9 j4 v* O3 m
  5. DMA_InitStructure.DMA_BufferSize = 64; //DMA 通道的 DMA 缓存的大小
    * Y0 N0 Z8 t& ?4 P7 K9 ]  S
  6. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不变& ^3 J, N( ^) l$ t( B& O
  7. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址递增) O; v2 ?  t; }5 N
  8. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //8 位# x, H$ V* V' a
  9. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 8 位; C& }7 L- X+ ?8 J
  10. DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式2 M! w" B! M, w4 W+ U1 V
  11. DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA 通道 x 拥有中优先级4 f( j( g; R1 B0 ?$ x* d
  12. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非内存到内存传输
    / w( N+ a7 a% b4 w
  13. DMA_Init(DMA_CHx, &DMA_InitStructure); //根据指定的参数初始化
复制代码

0 ~4 b" u) g/ M7 J2 x6 N7 f; M3)使能串口 DMA 发送
  1. USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
复制代码

% a  ^; O! s# B2 E( [7 {4)使能 DMA1 通道 4,启动传输7 |( g- E: `- Q2 a5 e
2 o: Z1 N! G( a2 Z
  1. DMA_Cmd(DMA_CHx, ENABLE);
复制代码
3 _4 K9 T, s) K% n" Q" Q
5)查询 DMA 传输状态8 J' E  x' R) Y# `: F$ M; R

/ O6 ^7 u3 P  q" e! G& }; o在 DMA 传输过程中,我们要查询 DMA 传输通道的状态:& f+ k( S) O2 \- Q" u* s4 o
$ }& f( f/ Q. m4 q; g: S: x
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG)& l+ j+ p3 Q: `' N
" `, y2 v6 q# F+ k: S( M# K; N6 `( g) i
比如我们要查询 DMA 通道 4 传输是否完成:
2 ?: M. M* F  Q9 S# I7 Z/ w- R4 k$ n$ l5 X; J2 M- k
DMA_GetFlagStatus(DMA2_FLAG_TC4);! p+ m, @7 m7 \3 ]+ x6 @
" z( R3 z% m# }; R" v5 {* @
获取当前剩余数据量大小的函数:
  1. uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx)
复制代码

7 A* d' o$ z* @  [9 W比如我们要获取 DMA 通道 4 还有多少个数据没有传输:
  1. DMA_GetCurrDataCounter(DMA1_Channel4);
复制代码

; x/ w, q9 B# X; c+ H* u二、代码实例+ x/ t! ]! J: G
我们需要创建dma.c 文件和其头文件 dma.h,8 j% y8 T7 r4 d# J% `
同时我们要引入 DMA 相关的库函数文件 stm32f10x_dma.c 和 stm32f10x_dma.h。( _) `  o, f, J: N  s, X
" U3 o# q" ^+ R5 H; M# h+ |9 K6 u
——dma.c 文件# q7 j# k8 y: v  L( D

9 K9 z% x' b4 Y3 l1 Q
  1. #include "dma.h"8 e/ U9 i. k4 |5 `. ^# x& v, t
  2. DMA_InitTypeDef DMA_InitStructure;8 u+ h1 T* C; k3 x
  3. u16 DMA1_MEM_LEN;//保存 DMA 每次数据传送的长度
    5 S! A. K8 e! e/ r( a& W
  4. //DMA1 的各通道配置7 h% @+ H' D- H/ t4 w
  5. //这里的传输形式是固定的,这点要根据不同的情况来修改
    4 L+ C# z0 r- M
  6. //从存储器->外设模式/8 位数据宽度/存储器增量模式
    ' d6 n& L+ V* ^) O& y
  7. //DMA_CHx:DMA 通道 CHx
    ) S% [2 t2 U% Z& U
  8. //cpar:外设地址
    6 H+ k. E! V3 M. I) \
  9. //cmar:存储器地址
    + ~& s$ E, |* W* D
  10. //cndtr:数据传输量' A  K) i  M8 d& j$ H) R0 m
  11. void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)( H; f; u' k9 E4 K
  12. {' S& L+ h9 j+ d
  13. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能 DMA 时钟/ t: X, D. P# _" g7 z, M  U
  14. DMA_DeInit(DMA_CHx); //将 DMA 的通道 1 寄存器重设为缺省值
    8 o8 y( {6 A1 t5 x! ?  ?
  15. DMA1_MEM_LEN=cndtr;. g% |, g8 q! c& g* g4 B
  16. DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA 外设 ADC 基地址
    - P, @9 E8 i0 o" _) C7 M
  17. DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA 内存基地址
    / r; d! S9 O- T! ?& l7 M0 m" T
  18. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向内存到外设. L3 {  i1 A7 @' A) O
  19. DMA_InitStructure.DMA_BufferSize = cndtr; //DMA 通道的 DMA 缓存的大小' t$ u( n. P. L, j) w
  20. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不变
    ! ?# `1 Y6 n+ v8 d, `' A; t- y( s
  21. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址寄存器递增( Q5 b# `1 P) v8 j
  22. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; $ w7 L6 Q/ d4 N- p( F- A
  23. //数据宽度为 8 位
    : G8 ]9 n2 v; u
  24. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度
    ) H4 j' i8 c" K/ O$ r* S
  25. //为 8 位
    & r% v" a: ~% k1 n; ?2 J3 ~$ w
  26. DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式  T4 B7 Q1 T7 C% W
  27. DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DM 通道拥有中优先级& D, U' w0 T' X# C
  28. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非内存到内存传输) U: ]% t3 J9 V; W& a" h/ N9 S
  29. DMA_Init(DMA_CHx, &DMA_InitStructure); //初始化 DMA 的通道* k7 U& j8 L5 {2 p* r0 x! X
  30. }   M( P1 g7 Z+ V
  31. //开启一次 DMA 传输
    4 w9 f8 S, k! F2 y% B1 ]
  32. void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
    * R9 }% Z$ [- P, t1 x# {
  33. {   R& [" c& Y3 _5 v5 {1 x
  34. DMA_Cmd(DMA_CHx, DISABLE ); //关闭 USART1 TX DMA1 所指示的通道 5 U! M! ~* ?- ^/ C+ M5 Z( t" s
  35. DMA_SetCurrDataCounter(DMA1_Channel4,DMA1_MEM_LEN);//设置 DMA 缓存的大小  A  z8 k% N; b4 R" A8 C4 w
  36. DMA_Cmd(DMA_CHx, ENABLE); //使能 USART1 TX DMA1 所指示的通道
    5 {, ^# @4 [& F+ I$ o, ]+ t
  37. }3 v  |/ c; q/ u; M
复制代码
( ?6 o" w5 B) N7 H" t' }
赞 收藏 评论0 发布时间:2022-5-8 19:00

举报

0个回答

所属标签

相似技术帖

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