STM32103的DMA转运,配置详解

DMA简介

1.DMA(Direct Memory Access)直接存储器存取
2.DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源
3.12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)
4.每个通道都支持软件触发特定的硬件触发

STM32F103C8T6 DMA资源:DMA1(7个通道)

存储器映像

在这里插入图片描述

DMA框图

可以看到DMA挂载在AHB总线上
DMA1有7个通道
DMA2有5个通道
仲裁器:毕竟是多通道共用一条总线,所以的通道分时复用这条总线,为了防止冲突,仲裁器根据优先级来决定谁先用,谁后用;
在总线矩阵那里也有一个仲裁器,如果CPU和DMA都要访问同一个目标时;DMA就会暂停CPU的访问,以防止冲突,不过总线仲裁器,任然会保证CPU得到一半的总线带宽,使得CPU正常工作
在这里插入图片描述

DMA基本结构

在这里插入图片描述

DMA请求

注意硬件请求的DMA通道并不是任意的,已经分配好通道了
例如:ADC1请求 通道1
在这里插入图片描述

数据宽度与对齐

简单的理解就是:
源地址>目标地址:高位去掉保留低位
源地址<目标地址:高位补零
注意大小端
在这里插入图片描述

数据转运+DMA

在这里插入图片描述

ADC扫描模式+DMA

在这里插入图片描述

通过以上了解,接下来结合代码进一步掌握

接下来看DMA.H的相关库函数

void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);
//恢复缺省值
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);
//DMA初始化
void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);
//结构体初始化
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);
//使能,开启DMA
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);
//DMA中断输出使能
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); 
//设置DMA当前数据寄存器(给传输计数器写数据)
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);
//获取当前数据寄存器(返回传输数据寄存器的值)
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
//获取标志位状态
void DMA_ClearFlag(uint32_t DMAy_FLAG);
//清除标志位状态
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);
//获取中断标志位状态
void DMA_ClearITPendingBit(uint32_t DMAy_IT);
//清除中断标志位状态

DMA转运配置驱动代码

储存器和储存器之间转换

#include "MyDMA.h"

uint16_t MyDMA_Size;
/**
  * @brief  DMA1_Channel1初始化,存储器到存储器转运
  * @param  
  * @retval 3个条件才能让DMA工作
  * @attention  1.传输计数器大于0  2.触发源有触发信号  3.DMA使能
  */
void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size)
{
	MyDMA_Size = Size;
	/***************************开启时钟********************************/
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	/***************************定义结构体变量********************************/
	DMA_InitTypeDef DMA_InitStructure;
	/***************************DMA参数配置********************************/
	DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;//外设站点的起始地址
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度,字节
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;//是否自增
	DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;//存储器站点的起始地址
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//数据宽度,字节
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//是否自增
	
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向:外设站点到存储器
	DMA_InitStructure.DMA_BufferSize = Size;//缓存区大小;其实就是传输计数器
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//传输模式;其实就是是否使用自动重装
	DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;//是否是存储器到存储器;其实就是是否是硬件触发,还是软件触发
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//优先级
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);//初始化
	
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能
}
/**
  * @brief  DMA传输函数
  * @param  调用一次传输一次
  * @retval 
  * @attention  给DMA赋值要先让其**失能**
  */
void MyDMA_Transfer(void)
{
	DMA_Cmd(DMA1_Channel1, DISABLE);//失能
	DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);//给传输计数器赋值
	DMA_Cmd(DMA1_Channel1, ENABLE);//使能
	
	while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);//等待转运完成标志位置1
	DMA_ClearFlag(DMA1_FLAG_TC1);//清除转运完成标志位
}

外设和储存器之间转换

ADC1单次扫描模式,DMA单次转运模式

/**
  * @brief  ADC1单次扫描模式,DMA单次转运模式
  * @param  
  * @retval 
  * @attention  
  */
#if 0
uint16_t AD_Value[5];//存储的位置
void AD_DMA_Init(void)
{
	/*****************************开启时钟******************************/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	/*****************************结构体变量******************************/
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	DMA_InitTypeDef DMA_InitStructure;
	/****************************ADCCLK分频器*******************************/
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);		//6分频;72MHZ/6=12MHZ
	
	/*****************************引脚模式配置******************************/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |  GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	/*****************************规则组输入通道配置放到读取函数里******************************/
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);	//规则组输入通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);	//规则组输入通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);	//规则组输入通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);	//规则组输入通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5, ADC_SampleTime_55Cycles5);	//规则组输入通道
	/****************************ADC结构体初始化*******************************/
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//工作模式:独立模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐:右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发转换选择:内部软件触发
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//单次转换	//需要不断触发
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;			//扫描转换模式
	ADC_InitStructure.ADC_NbrOfChannel = 5;					//通道数目为1~16之间
	ADC_Init(ADC1, &ADC_InitStructure);
	ADC_DMACmd(ADC1,ENABLE);	//ADC——DMA使能
	ADC_Cmd(ADC1, ENABLE);		//开启ADC电源

	/***************************DMA参数配置********************************/
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//外设站点的起始地址
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度,半字,取DR寄存器的低16位
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//是否自增,不自增
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;//存储器站点的起始地址
	DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度,字节
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//是否自增,自增
	
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向:外设站点到存储器
	DMA_InitStructure.DMA_BufferSize = 5;//缓存区大小;其实就是传输计数器
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//传输模式;其实就是是否使用自动重装
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//是否是存储器到存储器;其实就是是否是硬件触发,还是软件触发
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//优先级
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);//初始化
	
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能
	/*****************************ADC进行校准******************************/
	ADC_ResetCalibration(ADC1);		//复位校准
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);		//判断校准是否完成(准备下次校准)
	ADC_StartCalibration(ADC1);		//启动校准
	while (ADC_GetCalibrationStatus(ADC1) == SET);			//获取校准状态
	
}

void  AD_DMA_GetValue(void)
{
	DMA_Cmd(DMA1_Channel1, DISABLE);//失能
	DMA_SetCurrDataCounter(DMA1_Channel1, 5);//给传输计数器赋值
	DMA_Cmd(DMA1_Channel1, ENABLE);//使能
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//开启软件触发转换
	
	while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);//等待转运完成标志位置1
	DMA_ClearFlag(DMA1_FLAG_TC1);//清除转运完成标志位
}
#endif

ADC1连续扫描模式,DMA连续循环转运模式

/**
  * @brief  ADC1连续扫描模式,DMA连续循环转运模式
  * @param  
  * @retval 
  * @attention  
  */
#if 1
uint16_t AD_Value[5];//存储的位置
void AD_DMA_Init(void)
{
	/*****************************开启时钟******************************/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	/*****************************结构体变量******************************/
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	DMA_InitTypeDef DMA_InitStructure;
	/****************************ADCCLK分频器*******************************/
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);		//6分频;72MHZ/6=12MHZ
	
	/*****************************引脚模式配置******************************/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |  GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	/*****************************规则组输入通道配置放到读取函数里******************************/
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);	//规则组输入通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);	//规则组输入通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);	//规则组输入通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);	//规则组输入通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5, ADC_SampleTime_55Cycles5);	//规则组输入通道
	/****************************ADC结构体初始化*******************************/
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//工作模式:独立模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐:右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发转换选择:内部软件触发
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;		//连续转换	//不需要不断触发
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;			//扫描转换模式
	ADC_InitStructure.ADC_NbrOfChannel = 5;					//通道数目为1~16之间
	ADC_Init(ADC1, &ADC_InitStructure);
	ADC_DMACmd(ADC1,ENABLE);	//ADC——DMA使能
	ADC_Cmd(ADC1, ENABLE);		//开启ADC电源

	/***************************DMA参数配置********************************/
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//外设站点的起始地址
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度,半字,取DR寄存器的低16位
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//是否自增,不自增
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;//存储器站点的起始地址
	DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度,字节
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//是否自增,自增
	
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向:外设站点到存储器
	DMA_InitStructure.DMA_BufferSize = 5;//缓存区大小;其实就是传输计数器
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//传输模式;循环模式;使用自动重装
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//是否是存储器到存储器;其实就是是否是硬件触发,还是软件触发
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//优先级
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);//初始化
	
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能
	/*****************************ADC进行校准******************************/
	ADC_ResetCalibration(ADC1);		//复位校准
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);		//判断校准是否完成(准备下次校准)
	ADC_StartCalibration(ADC1);		//启动校准
	while (ADC_GetCalibrationStatus(ADC1) == SET);			//获取校准状态
	/***************************直接放在初始化最后一行********************************/
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//开启软件触发转换
}
/*******直接不需要了
void  AD_DMA_GetValue(void)
{
	DMA_Cmd(DMA1_Channel1, DISABLE);//失能
	DMA_SetCurrDataCounter(DMA1_Channel1, 5);//给传输计数器赋值
	DMA_Cmd(DMA1_Channel1, ENABLE);//使能
	
	while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);//等待转运完成标志位置1
	DMA_ClearFlag(DMA1_FLAG_TC1);//清除转运完成标志位
}*/
#endif

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: STM32F103是一款常用的32位单片机,它内置了多个DMA通道,可以实现高效的数据传输。在配置STM32F103的DMA数据发送时,需要按照以下步骤进行: 1. 开启DMA时钟,打开DMA传输通道的时钟使能。 2. 配置DMA通道控制寄存器,设置DMA传输方向(内存到外设或者外设到内存),传输数据大小,传输模式(单次或循环),传输优先级等。 3. 配置DMA通道数据缓存区,指定数据源和目的地址。 4. 配置外设相关寄存器,如USART的发送数据寄存器或SPI的发送缓存寄存器等。 5. 启动DMA传输,通过设置相关位来启动DMA传输并等待传输完成。 需要注意的是,在设置DMA传输规则时,应该根据具体的外设接口和数据模式进行设置,以充分发挥STM32F103的DMA传输优势。 总之,STM32F103的DMA传输可以大大提高数据传输的效率和性能,对于高速数据传输、数据采集和通信应用具有重要意义。 ### 回答2: STM32F103DMA是一种微控制器,可以使用DMA功能进行数据传输。在配置STM32F103DMA发送时,需要设置以下几个参数: 1. 设置DMA通道:首先要设置哪个DMA通道将要被使用。这需要根据不同的需求来选择。 2. 设置数据大小:接下来设置数据的大小,这指的是传输的数据大小。 3. 设置源地址和目标地址:接着需要设置源地址和目标地址。这两个地址用来指定数据的储存位置。源地址指的是需要传输的数据的地址,目标地址指的是需要把数据传输到哪个位置。 4. 设置传输模式:传输模式用来指定传输的方式。有三种传输方式,分别为:普通传输模式、循环传输模式、单次传输模式。 5. 设置传输方向:传输方向指的是数据的传输方向,有两种方向:从内存到外设,从外设到内存。 配置完成后,就可以开始传输数据了。需要注意的是,在传输过程中需要根据需要进行数据交换。这就意味着在数据传输结束后需要对数据进行清理和处理,以确保数据的正确性。同时,为了确保传输的速度,还需要选择合适的DMA周期,使其与传输数据的速率相匹配。在数据传输过程中,若出现问题,可以参考错误代码进行排除。 ### 回答3: STM32F103DMA是一款基于ARM Cortex-M3架构的微控制器,具备DMA传输功能。以下是stm32f103DMA发送配置的方法: 首先,需要在STM32的寄存器中设置DMA传输的参数。在初始化时,需要指定发送数据的长度、目标地址、数据源地址、传输模式等参数。然后使能DMA传输,并开启发送模式。此外,还需要对每个DMA通道进行配置,包括通道优先级、传输周期、循环模式等。 在具体实现中,可以使用示波器和串口助手等工具来检测数据的传输情况。在发送前,需要检查发送缓冲区的数据是否正确并进行清空;在接收后,需要对接收到的数据进行解析和处理。同时,还要注意数据长度严格的控制,以确保传输的正确性和稳定性。 总之,STM32F103DMA发送配置需要细心和谨慎,需要充分理解掌握参数设置、DMA通道配置、数据处理等方面的技术知识,才能保证数据的安全性和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

领悟电子界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值