STM32F103,DMA数据转运以及配合AD多通道使用的两种方法

一、配置MDA的流程:

1、开启RCC的时钟

2、初始化DMA:配置他的外设和存储器的起始地址、数据宽度、地址是否自增,他们的方向,有多少个通道,DMA的循环模式,配置触发方式,优先级,最后一步开启DMA。

3、DMA的转运:先把计数器清零,调用专用函数,使能计数器,是从最后一个序列开始自减的,判断是否转运完成标志位,清除标志位。

二、函数模块代码和使用方式

1、这个只有DMA模块

#include "stm32f10x.h"                  // Device header

uint16_t MyDMA_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_PeripheralDataSize=DMA_PeripheralDataSize_Byte;   //数据宽度8比特
	DMA_InitStructrue.DMA_PeripheralInc=DMA_PeripheralInc_Enable;	        //地址自增
	DMA_InitStructrue.DMA_MemoryBaseAddr=AddrB;
	DMA_InitStructrue.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
	DMA_InitStructrue.DMA_MemoryInc=DMA_MemoryInc_Enable;                  //地址自增
	DMA_InitStructrue.DMA_DIR=DMA_DIR_PeripheralSRC;                       //方向A->B
	DMA_InitStructrue.DMA_BufferSize=Size;                                 //多少通道
	DMA_InitStructrue.DMA_Mode=DMA_Mode_Normal;                            //DMA循环模式,单次
	DMA_InitStructrue.DMA_M2M=DMA_M2M_Enable;                              //软件触发
	DMA_InitStructrue.DMA_Priority=DMA_Priority_Medium; 				//优先级中等
	DMA_Init(DMA1_Channel1,&DMA_InitStructrue);
	
	DMA_Cmd(DMA1_Channel1,DISABLE);                                      //开DMA
}

void MyMDA_Transfer(void)
{
	DMA_Cmd(DMA1_Channel1,DISABLE);                        //清除计数器
	DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);     //设置开始转运
	DMA_Cmd(DMA1_Channel1,ENABLE);							//使能计数器,从最后一个倒序,4->1
	while (DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);       //转运完成标志位,转运完成标志位置1
	DMA_ClearFlag(DMA1_FLAG_TC1);                         //清除标志位
}




#include "stm32f10x.h"                  // Device header
#include"OLED.h"
#include"Delay.h"
#include"MyDMA.h"
uint8_t DataA[]={0x01,0x02,0x03,0x04};
uint8_t DataB[]={0,0,0,0};
int main(void)
{
	OLED_Init();
	MyDMA_Init((uint32_t)DataA,(uint32_t)DataB,4);
	
	OLED_ShowString(1,1,"DataA:");
	OLED_ShowHexNum(1,9,(uint32_t)DataA,8);
	OLED_ShowString(3,1,"DataB:");
	OLED_ShowHexNum(3,9,(uint32_t)DataB,8);

	while(1)
	{
		DataA[0]++;
		DataA[1]++;
		DataA[2]++;
		DataA[3]++;
		OLED_ShowHexNum(2,1,DataA[0],2);
		OLED_ShowHexNum(2,4,DataA[1],2);
		OLED_ShowHexNum(2,7,DataA[2],2);
		OLED_ShowHexNum(2,10,DataA[3],2);
		
//		OLED_ShowHexNum(4,1,DataB[0],2);
//		OLED_ShowHexNum(4,4,DataB[1],2);
//		OLED_ShowHexNum(4,7,DataB[2],2);
//		OLED_ShowHexNum(4,10,DataB[3],2);
//		Delay_ms(1000);
		MyMDA_Transfer();
		
//		OLED_ShowHexNum(2,1,DataA[0],2);
//		OLED_ShowHexNum(2,4,DataA[1],2);
//		OLED_ShowHexNum(2,7,DataA[2],2);
//		OLED_ShowHexNum(2,10,DataA[3],2);
		
		OLED_ShowHexNum(4,1,DataB[0],2);
		OLED_ShowHexNum(4,4,DataB[1],2);
		OLED_ShowHexNum(4,7,DataB[2],2);
		OLED_ShowHexNum(4,10,DataB[3],2);
		Delay_ms(1000);
		
	}
}

2、DMA和AD多通道的第一种方式

#include "stm32f10x.h"                  // Device heade


uint16_t AD_Values[4];

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);     //开启ADC时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);       //6分频,对应就是72MHZ/6=12MHZ
	
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;    //初始化GPIO为输入模式,其他都为电平无效状态  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	
	ADC_InitTypeDef ADC_InitStructure;
	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_NbrOfChannel=4;                        //指定序列为多少个
	ADC_InitStructure.ADC_ScanConvMode=ENABLE;         //转换模式连续扫描模式
	ADC_Init(ADC1,&ADC_InitStructure);
		/*配置ADC的通道和序列*/
	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);
	/*初始化DMA*/
	DMA_InitTypeDef DMA_InitStructrue;
	DMA_InitStructrue.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;             //外设起始地址
	DMA_InitStructrue.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //十六位半字模式
	DMA_InitStructrue.DMA_PeripheralInc=DMA_PeripheralInc_Disable;	          //地址不自增
	DMA_InitStructrue.DMA_MemoryBaseAddr=(uint32_t)AD_Values;                //存储器起始地址
	DMA_InitStructrue.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
	DMA_InitStructrue.DMA_MemoryInc=DMA_MemoryInc_Enable;                    //地址自增
	DMA_InitStructrue.DMA_DIR=DMA_DIR_PeripheralSRC;                  //方向:外设->存储器
	DMA_InitStructrue.DMA_BufferSize=4;
	DMA_InitStructrue.DMA_Mode=DMA_Mode_Normal;            //DMA循环模式,单次
	DMA_InitStructrue.DMA_M2M=DMA_M2M_Disable;             //触发,不使用软件触发,使用硬件触发
	DMA_InitStructrue.DMA_Priority=DMA_Priority_Medium;    //优先级,中等优先级
	DMA_Init(DMA1_Channel1,&DMA_InitStructrue);

	DMA_Cmd(DMA1_Channel1,ENABLE);                        //开启DMA
	ADC_Cmd(ADC1,ENABLE);				                  //开启ADC
	ADC_DMACmd(ADC1,ENABLE);							  //ADC使能DMA
	
	ADC_ResetCalibration(ADC1);                         //复位校准
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);	//等待复位校准完成,复位校准完成(0)就跳出循环
	ADC_StartCalibration(ADC1);                         //开始校准
	while(ADC_GetCalibrationStatus(ADC1)==SET);         //等待校准完成
}
/*
调用这个函数触发传输计数器,软件触发DMA转运,等待转运完成,
转运完成之后,得到的数据自动转运到AD_Values数组
*/
void AD_GetValues(void)
{
	DMA_Cmd(DMA1_Channel1,DISABLE);
	DMA_SetCurrDataCounter(DMA1_Channel1,4);     //设置开始转运
	DMA_Cmd(DMA1_Channel1,ENABLE);
	
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);             //使用软件触发函数

	while (DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
	DMA_ClearFlag(DMA1_FLAG_TC1);
}
#include "stm32f10x.h"                  // Device header
#include"OLED.h"
#include"AD.h"
#include"Delay.h"


uint16_t AD0,AD1,AD2,AD3;
int main(void)
{
	OLED_Init();
	AD_Init();
	OLED_ShowString(1,1,"AD0:");
	OLED_ShowString(2,1,"AD1:");
	OLED_ShowString(3,1,"AD2:");
	OLED_ShowString(4,1,"AD3:");
	
	while(1)
	{
		AD_GetValues();
		OLED_ShowNum(1,5,AD_Values[0],4);
		OLED_ShowNum(2,5,AD_Values[1],4);
		OLED_ShowNum(3,5,AD_Values[2],4);
		OLED_ShowNum(4,5,AD_Values[3],4);
		Delay_ms(200);
		
	}
}

3、DMA和AD多通道的第二种使用方式,比上一个少了一个返回值的AD_GetValues();的函数的写法。

#include "stm32f10x.h"                  // Device heade


uint16_t AD_Values[4];

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);     //开启ADC时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);       //6分频,对应就是72MHZ/6=12MHZ
	
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;    //初始化GPIO为输入模式,其他都为电平无效状态  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	
	ADC_InitTypeDef ADC_InitStructure;
	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_NbrOfChannel=4;                        //指定序列是多少个
	ADC_InitStructure.ADC_ScanConvMode=ENABLE;         //转换模式连续扫描模式
	ADC_Init(ADC1,&ADC_InitStructure);
		/*配置ADC的通道和序列*/
	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);
	/*初始化DMA*/
	DMA_InitTypeDef DMA_InitStructrue;
	DMA_InitStructrue.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;             //外设起始地址
	DMA_InitStructrue.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //十六位半字模式
	DMA_InitStructrue.DMA_PeripheralInc=DMA_PeripheralInc_Disable;	          //地址不自增
	DMA_InitStructrue.DMA_MemoryBaseAddr=(uint32_t)AD_Values;                //存储器起始地址
	DMA_InitStructrue.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
	DMA_InitStructrue.DMA_MemoryInc=DMA_MemoryInc_Enable;                    //地址自增
	DMA_InitStructrue.DMA_DIR=DMA_DIR_PeripheralSRC;                  //方向:外设->存储器
	DMA_InitStructrue.DMA_BufferSize=4;
	DMA_InitStructrue.DMA_Mode=DMA_Mode_Circular;            //DMA循环模式,打开
	DMA_InitStructrue.DMA_M2M=DMA_M2M_Disable;             //触发,不使用软件触发,使用硬件触发
	DMA_InitStructrue.DMA_Priority=DMA_Priority_Medium;    //优先级,中等优先级
	DMA_Init(DMA1_Channel1,&DMA_InitStructrue);

	DMA_Cmd(DMA1_Channel1,ENABLE);                        //开启DMA
	ADC_Cmd(ADC1,ENABLE);				                  //开启ADC
	ADC_DMACmd(ADC1,ENABLE);							  //ADC使能DMA
	
	ADC_ResetCalibration(ADC1);                         //复位校准
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);	//等待复位校准完成,复位校准完成(0)就跳出循环
	ADC_StartCalibration(ADC1);                         //开始校准
	while(ADC_GetCalibrationStatus(ADC1)==SET);         //等待校准完成
	
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);             //使用软件触发函数
}

#include "stm32f10x.h"                  // Device header
#include"OLED.h"
#include"AD.h"
#include"Delay.h"


uint16_t AD0,AD1,AD2,AD3;
int main(void)
{
	OLED_Init();
	AD_Init();
	OLED_ShowString(1,1,"AD0:");
	OLED_ShowString(2,1,"AD1:");
	OLED_ShowString(3,1,"AD2:");
	OLED_ShowString(4,1,"AD3:");
	
	while(1)
	{

		OLED_ShowNum(1,5,AD_Values[0],4);
		OLED_ShowNum(2,5,AD_Values[1],4);
		OLED_ShowNum(3,5,AD_Values[2],4);
		OLED_ShowNum(4,5,AD_Values[3],4);
		Delay_ms(200);
		
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值