一. 对于大容量的STM32芯片有2个DMA控制器,控制器1有7个通道,控制器2有5个通道

  每个通道都可以配置一些外设的地址。

  

  

  二. 通道的配置过程:

  

  1. 首先设置CPARx寄存器和CMARx寄存器。

  通过DMA控制器把一个地址的值复制到另外一个地址,通过DMA控制器自动开启一条通道完成。

  CPARx寄存器存放的是外设的地址

  CMARx寄存器存储的是存储器的地址

  2. 设置数据传输方向,是否循环模式,是不是开启外设和存储器的增量模式,还有数据宽度,是8位,16位还是32位。

  比如设置成存储器的地址增量,那么传输一个数据过去后它的地址自动递增。

  3. 设置要传输的数据量

  4. 设置通道的优先级

  5. 全部设置好后就可以启动DMA通道。

  启动后数据就开始传输,传输的过程中可以读CNDTRx寄存器,可知道当前还剩多少个数据。数据传输到一半或全部传输完毕后有响应的标志位置1,如果开启了中断,可以进入相应的中断程序。

  一。常用的DMA函数

  

  1.DMA初始化函数

  

void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx); //设置要开启的通道,还有一些参数,包括外设基地址,存储器基地址,传输的数据量,增量模式,数据宽度等。

  2.DMA使能函数

  void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);

  3.开启相应中断的函数

 

 void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);

  4.设置CNDTRx和读CNDTRx函数

  

void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber);

  uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

  二。常用的外设DMA使能函数

  需要开启外设的DMA使能才能够使用DMA功能。

  这些函数分布在外设各自的头文件中。

  

  三。DMA初始化函数

  

  对应下面的代码学习:

  

u16 DMA1_MEM_LEN; //保存DMA每次数据传送的长度

  //DMA1的各通道配置

  //这里的传输形式是固定的,这点要根据不同的情况来修改

  //从存储器->外设模式/8位数据宽度/存储器增量模式

  //DMA_CHx:DMA通道CHx

  //cpar:外设地址

  //cmar:存储器地址

  //cndtr:数据传输量

  void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)

  {

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输

  DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值

  DMA1_MEM_LEN=cndtr;

  DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设ADC基地址

  DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设

  DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位

  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式

  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输

  DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道

  USART1_Tx_DMA_Channel所标识的寄存器

  }

  四。DMA配置的一般过程

  

  五。实验

  使用串口1发送DMA

  dma.h文件

  

#ifndef __DMA_H

  #define __DMA_H

  #include "sys.h"

  void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr);//配置DMA1_CHx

  void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);//使能DMA1_CHx

  #endif

  dma.c文件

  #include "dma.h"

  DMA_InitTypeDef DMA_InitStructure;

  u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度

  //DMA1的各通道配置

  //这里的传输形式是固定的,这点要根据不同的情况来修改

  //从存储器->外设模式/8位数据宽度/存储器增量模式

  //DMA_CHx:DMA通道CHx

  //cpar:外设地址

  //cmar:存储器地址

  //cndtr:数据传输量

  void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)

  {

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输,DMA在AHB总线上

  DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值

  DMA1_MEM_LEN=cndtr;

  DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设ADC基地址

  DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设

  DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位

  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式

  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输

  DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道 USART1_Tx_DMA_Channel所标识的寄存器

  }

  //开启一次DMA传输

  void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)

  {

  DMA_Cmd(DMA_CHx, DISABLE ); //关闭USART1 TX DMA1 所指示的通道

  DMA_SetCurrDataCounter(DMA1_Channel4,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小

  DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1 所指示的通道

  }

  注:DMA每传输完成一次,要传输的数据量都要自动清零,因此每次开启都要重新设置要传输的数据量。

  主程序中:

 

 for(i=0;i

  {

  if(t>=j)//加入换行符

  {

  if(mask)

  {

  SendBuff[i]=0x0a;

  t=0;

  }else

  {

  SendBuff[i]=0x0d;

  mask++;

  }

  }else//复制TEXT_TO_SEND语句

  {

  mask=0;

  SendBuff[i]=TEXT_TO_SEND[t];

  t++;

  }

  }

  这一段是 在每个字符串“ALIENTEK WarShip STM32F1 DMA 串口实验”后面添加0x0d和0x0a,也就是自动换行,这样在串口助手中接收到的数据就是ALIENTEK WarShip STM32F1 DMA 串口实验,然后自动换行,另外串口助手sscom程序有bug,不能自动换行,可以换其他串口助手观察。

资料分享便于后期的学习参考

(DMA专题讲解)
http://www.makeru.com.cn/live/1392_1048.html?s=45051

stm32 如何用DMA搬运数据
http://www.makeru.com.cn/live/detail/1484.html?s=45051

(stm32串口应用)
http://www.makeru.com.cn/live/1392_1164.html?s=45051
PWM脉宽调制技术
http://www.makeru.com.cn/live/4034_2146.html?s=45051

嵌入式单片机stm32之DMA实验的更多相关文章

  1. 嵌入式单片机STM32应用技术(课本)

    目录SAIU R20 1 6 第1页第1 章. 初识STM32..................................................................... ...

  2. STM32之DMA+ADC

    借用小甲鱼的经典:各位互联网的广大网友们.大家早上中午晚上好..(打下小广告,因为小甲鱼的视频真的很不错).每次看小甲鱼的视频自学都是比较轻松愉快的..我在想,如果小甲鱼出STM32的视频,我会一集不 ...

  3. STM32之DMA

    一.DMA简介 1.DMA简介 DMA(Direct Memory Access:直接内存存取)是一种可以大大减轻CPU工作量的数据转移方式. CPU有转移数据.计算.控制程序转移等很多功能,但其实转 ...

  4. STM32使用DMA发送串口数据

    1.概述 上一篇文章<STM32使用DMA接收串口数据>讲解了如何使用DMA接收数据,使用DMA外设和串口外设,使用的中断是串口空闲中断.本篇文章主要讲解使用DMA发送数据,不会讲解基础的 ...

  5. 嵌入式单片机之stm32串口你懂了多少!!

    stm32作为现在嵌入式物联网单片机行业中经常要用多的技术,相信大家都有所接触,今天这篇就给大家详细的分析下有关于stm32的出口,还不是很清楚的朋友要注意看看了哦,在最后还会为大家分享有些关于stm ...

  6. 嵌入式02 STM32 实验10 定时器中断

    优秀文章 https://blog.csdn.net/qq_38351824/article/details/82619734 一.STM32通用定时器(TIM2.TIM3.TIM4和TIM5共四个通 ...

  7. 嵌入式02 STM32 实验08 外部中断

    一.中断 由于某个事件的发生,CPU暂停当前正在执行的程序,转而执行处理事件的一个程序.该程序执行完成后,CPU接着执行被暂停的程序.这个过程称为中断.(我正在捉泥鳅,但是我妈喊我回家吃饭,我必须回家 ...

  8. 嵌入式02 STM32 实验07 串口通信

    STM32串口通信(F1系列包含3个USART和2个UART) 一.单片机与PC机串行通信研究目的和意义: 单片机自诞生以来以其性能稳定,价格低廉.功能强大.在智能仪器.工业装备以及日用电子消费产品中 ...

  9. 嵌入式02 STM32 实验01 端口复用和重映射

    内设与外设: 端口复用和端口重映射都需要了解内设和外设,那么什么是内设?什么是外设? 内设:单片机内部集成的功能一般包括:串口模块.SPI模块(Serial Peripheral Interface  ...

随机推荐

  1. AQS学习(二) AQS互斥模式与ReenterLock可重入锁原理解析

    1. MyAQS介绍    在这个系列博客中,我们会参考着jdk的AbstractQueuedLongSynchronizer,从零开始自己动手实现一个AQS(MyAQS).通过模仿,自己造轮子来学习 ...

  2. python模块--pathlib

    类/属性/方法 返回值 参数 说明 .Path() p 创建Path对象 path 路径         p.parent Path 返回上一级路径 p.parents iter 上一级路径, 上上级 ...

  3. POJ3625Building Roads

    Building Roads Description Farmer John had just acquired several new farms! He wants to connect the ...

  4. mybatis的mapper特殊字符转移以及动态SQL条件查询

    前言 我们知道在项目开发中之前使用数据库查询,都是基于jdbc,进行连接查询,然后是高级一点jdbcTemplate进行查询,但是我们发现还是不是很方便,有大量重复sql语句,与代码偶合,效率低下,于 ...

  5. Jmeter系类(31) - JSR223(1) | 控件介绍

    JSR233 介绍 JSR223控件执行JSR223脚本代码用于创建/更新所需的某些变量 JSR223可以使用其内置的变量,有助于精简脚本,提高开发测试的效率 由于JSR223脚本编译方式基本相同,J ...

  6. 鸿蒙内核源码分析(内存映射篇) | 虚拟内存虚在哪里 | 百篇博客分析OpenHarmony源码 | v15.03

    百篇博客系列篇.本篇为: v15.xx 鸿蒙内核源码分析(内存映射篇) | 虚拟内存虚在哪里 | 51.c.h .o 内存管理相关篇为: v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪些分 ...

  7. kubeadm 如何将节点加入集群

    kubeadm join 使用 token 过期之后(24小时过期),如何加入集群 一.重启生成新token # 创建新token kubeadm token create # 查看是否存在有效的 t ...

  8. .Net微服务实战之可观测性

    系列文章 .Net微服务实战之技术选型篇 .Net微服务实战之技术架构分层篇 .Net微服务实战之DevOps篇 .Net微服务实战之负载均衡(上) .Net微服务实战之CI/CD .Net微服务实战 ...

  9. Java编译运行环境讨论(复古但能加深对Java项目的理解)

    Java编译运行环境讨论(复古但能加深对Java项目的理解) 如今我们大多数情况都会使用IDE来进行Java项目的开发,而一个如今众多优秀的IDE已经能够帮助我们自动的部署并调试运行我们的Java程序 ...

  10. Ubuntu20.04安装 maven并配置阿里源

    Ubuntu20.04安装 maven并配置阿里源 sudo apt update sudo apt install maven #安装maven,默认安装路径为/usr/share/maven 添加 ...