DMA字节存储器存储

一般与ADC模数转换配合使用,ADC将不断接收到的模拟数据转化为数字量存储在寄存器中。使用规则组进行AD转换时,由于其数据寄存器只有一个,同时扫描多个数据通道时,会形造成数据覆盖。这时候可以使用DMA来搬运数据,每一次AD转换完成后及时将数据搬运到其他地方,避免数据被覆盖。

DMA运行的条件:

DMA使能

有触发源

传输计数器计数值大于0

外设寄存器:仅表示需要搬运数据的某个寄存器,可以是外设的寄存器也可以是系统内的某个存储器。

任意通道都可以使用软件触发

而硬件触发时不同的外设的DMA通道不一致

硬件触发DMA时应该主动开启该外设的DMA功能。

   如: ADC_DMACmd(ADC1,ENABLE);                                                    //开启ADC的DMA功能
 

ADC扫描模式下,每转换完成一次数据,将数据写入到ADC_DR后,发出触发信号。DMA随即将ADC_DR位置的数据搬运到存储器。然后ADC再不断转换写入数据,不断触发DMA去搬运数据,从而实现多路ADC及其数据的存储。

单路DMA:

#include "stm32f10x.h"                  // Device header

uint16_t MyDMA_Size;                                                        //全局变量,存储传输次数
/**
  * 函    数:DMA初始化 
  * 参    数:uint32_t AddrA 需要转运的数据首地址
  * 参    数:uint32_t AddrA 转运后数据存储的地址
  * 参    数:uint16_t Size  转运的数据个数
  * 返 回 值:
  */
void MyDMA_Init(uint32_t AddrA,uint32_t AddrB ,uint16_t Size)
{
	MyDMA_Size=Size; 
	/*开启时钟*/
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	/*配置DMA*/
	DMA_InitTypeDef DMA_InitStructrue;										//定义结构体
	DMA_InitStructrue.DMA_PeripheralBaseAddr= AddrA; 						//外设基地址,即需要转运的数据首地址
	DMA_InitStructrue.DMA_PeripheralInc= DMA_PeripheralInc_Enable;			//地址是否自增
	DMA_InitStructrue.DMA_PeripheralDataSize= DMA_PeripheralDataSize_Byte;  //传出多少宽度的数据
	DMA_InitStructrue.DMA_MemoryBaseAddr=  AddrB;							//转运后数据存储的地址
	DMA_InitStructrue.DMA_MemoryDataSize= DMA_PeripheralDataSize_Byte; 		//写入多少宽度的数据
	DMA_InitStructrue.DMA_MemoryInc= DMA_MemoryInc_Enable;					//地址是否自增
	DMA_InitStructrue.DMA_DIR= DMA_DIR_PeripheralSRC; 						//数据传输方向
	DMA_InitStructrue.DMA_BufferSize= Size;									//传输数据的次数
	DMA_InitStructrue.DMA_M2M= DMA_M2M_Enable;								//存储器到存储器:软件出发 OR 外设到存储器:硬件触发
	DMA_InitStructrue.DMA_Mode= DMA_Mode_Normal; 							//传输模式 Normal:计数器不重装 OR Circular:计数器重装 不能与软件出发同时使用
	DMA_InitStructrue.DMA_Priority= DMA_Priority_Medium;					//传输优先级
	DMA_Init(DMA1_Channel1,&DMA_InitStructrue);								// 读取结构体,完成初始化
	
	DMA_Cmd(DMA1_Channel1,DISABLE);											//是否开启DMA转运,这里先不开启
}
/**
 * 函    数:数据转运,转运数据数为MyDMA_Size
  * 参    数:无
  * 返 回 值:
  */
void MyDMA_Transfer(void)
{
	DMA_Cmd(DMA1_Channel1,DISABLE);											//失能,修改计数器值时DMA不能处于使能状态
	DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);						//设置计数器的值
	DMA_Cmd(DMA1_Channel1,ENABLE);											//使能,开始转运数据
	
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);							//等待数据转运完成
	DMA_ClearFlag(DMA1_FLAG_TC1);											//清除标志位
}

多路DMA:

使用ADC扫描模式+DMA时:

将ADC配置成扫描模式

DMA配置成循环模式

给ADC一次触发信号,硬件就会不断得进行数据的转换和转换完成后的数据搬运。

#include "stm32f10x.h"                  // Device header

uint16_t AD_Value[4]={0,0,0,0};


/**
  * 函    数:AD初始化
  * 参    数:无
  * 返 回 值:无
  */
void AD_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_ADC1, ENABLE);						//打开ADC1的时钟
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA, ENABLE);						//打开GPIOA的时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);							//开启DMA1的时钟

	
	/*设置ADC时钟分频*/
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);											//ADC时钟为系统六分频
	
	/*GPIO初始化*/
	GPIO_InitTypeDef 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(GPIOB,&GPIO_InitStructure);										//将PA0/1/2/3配置成模拟输入模式
	
	/*规则组通道配置*/
	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初始化*/
	ADC_InitTypeDef ADC_InitStructrue;											//定义结构体
	ADC_InitStructrue.ADC_Mode= ADC_Mode_Independent;							//模式,选择独立模式,仅使用单个ADC
	ADC_InitStructrue.ADC_DataAlign= ADC_DataAlign_Right;						//数据对齐,右对齐
	ADC_InitStructrue.ADC_ExternalTrigConv= ADC_ExternalTrigConv_None;			//外部触发,仅由软件触发
	ADC_InitStructrue.ADC_ContinuousConvMode= ENABLE;     						//连续转换,使能,软件触发一次后会连续转换
	ADC_InitStructrue.ADC_NbrOfChannel= 4 ;										//使用的通道数
	ADC_InitStructrue.ADC_ScanConvMode= ENABLE;									//扫描模式,使能,转换多个序列
	ADC_Init(ADC1,&ADC_InitStructrue);											//读入结构体
	
	/*配置DMA*/
	DMA_InitTypeDef DMA_InitStructure;	//定义结构体
	DMA_InitStructure.DMA_PeripheralBaseAddr= (uint32_t)&ADC1->DR; 				//外设基地址,即需要转运的数据首地址
	DMA_InitStructure.DMA_PeripheralDataSize= DMA_PeripheralDataSize_HalfWord;  //传出多少宽度的数据
	DMA_InitStructure.DMA_PeripheralInc= DMA_PeripheralInc_Disable;				//地址是否自增
	              
	DMA_InitStructure.DMA_MemoryBaseAddr=  (uint32_t)AD_Value;					//转运后数据存储的地址
	DMA_InitStructure.DMA_MemoryDataSize= DMA_MemoryDataSize_HalfWord; 			//写入多少宽度的数据
	DMA_InitStructure.DMA_MemoryInc= DMA_MemoryInc_Enable;						//地址是否自增
	              
	DMA_InitStructure.DMA_DIR= DMA_DIR_PeripheralSRC; 							//数据传输方向
	DMA_InitStructure.DMA_BufferSize= 4;										//传输数据的次数
	DMA_InitStructure.DMA_M2M= DMA_M2M_Disable;									//存储器到存储器:EN:软件触发  DIS:外设到存储器:硬件触发
	DMA_InitStructure.DMA_Mode= DMA_Mode_Circular;								//传输模式 Normal:计数器不重装 OR Circular:计数器重装 不能与软件出发同时使用
	DMA_InitStructure.DMA_Priority= DMA_Priority_Medium;						//传输优先级
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);									//读取结构体,完成初始化

	DMA_Cmd(DMA1_Channel1,ENABLE);												//是否开启DMA转运,这里先不开启
	ADC_DMACmd(ADC1,ENABLE);													//开启ADC的DMA功能
	ADC_Cmd(ADC1,ENABLE);														//启动ADC
	
	/*ADC校准*/
	ADC_ResetCalibration(ADC1);													//固定流程,内部有电路自动执行
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);
	ADC_StartCalibration(ADC1);
	while(	ADC_GetCalibrationStatus(ADC1)==SET);
	
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);										//触发信号,ADC转换一次


}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值