STM32F4X DMA

STM32F4X DMA

  • 什么是DMA
  • STM32F4X DMA
    • DMA框图
      • DMA通道
      • DMA仲裁器
      • DMA FIFO
    • DMA传输模式
    • DMA传输方向
      • 存储器到存储器
      • 存储器到外设
      • 外设到存储器
    • DMA循环模式和普通模式
      • 循环模式(Circular)
      • 普通模式(Normal)
    • DMA源、目标寄存器增量模式
    • DMA例程
      • 存储器到存储器例程
      • 存储器到外设例程
      • 外设到存储器例程

什么是DMA

DMA又叫直接存储器访问,用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何CPU操作的情况下通过DMA快速移动数据。这样节省的CPU资源可供其它操作使用。

STM32F4X DMA

DMA框图

STM32F4X DMA_第1张图片

DMA通道

STM32F4X的每一个DMA控制器有8个数据流,每个数据流又有8个通道。每个通道都会对应相关的外设。
STM32F4X DMA_第2张图片
STM32F4X DMA_第3张图片

DMA仲裁器

虽然STM32F4X的DMA控制器有8个数据流,当有多个数据流产生请求时,DMA控制器每次只能处理一个数据流,这时就需要DMA仲裁器的帮忙了。仲裁器可以理解成是优先级选择器,顾名思义就是根据数据流的优先级来决定处理哪个通道。其优先级选择关系如下。

  • 在相同优先级的情况下,数据流编号低的优先级高,数据流编号高的优先级低。就是STR0>STR1>STR2>STR3>STR4>STR5>STR6>STR7。
  • 用户可以通过软件设置数据流的优先级,分别是低优先级、中等优先级、高优先级和非常高优先级。

DMA FIFO

FIFO 用于在源数据传输到目标之前临时存储这些数据,可以加快DMA的传输速度。在STM32F4X中每个DMA数据流都会有一个独立的4字FIFO,也就是16字节的FIFO。STM32F4X的DMA FIFO可以配置它的阀值,具体如下图所示。
STM32F4X DMA_第4张图片
上图描述了STM32F4X的DMA FIFO的阀值配置,看似很复杂,其实根据下面的例子就我们就可以知道其配置规则。
MSIZE:外设或存储器数据大小,用户可以配置成字节、半字或者字。
MBURST = INCR4: 每次传输4 * MSIZE的大小且FIFO必须是此乘积的整数倍
MBURST = INCR8: 每次传输8 * MSIZE的大小且FIFO必须是此乘积的整数倍
MBURST = INCR16: 每次传输16 * MSIZE的大小且FIFO必须是此乘积的整数倍
我们假设DMA的外设和存储器数据大小为半字,也就是2个字节,MSIZE就为2。MBURST设置为INCR4。
MSIZE = 2
MBURST = INCR4
此时传输的数据量就为MSIZE * 4 = 8字节,那么此时FIFO的阀值只能是8 * 1 = 8或者8 * 2 = 16,也就是阀值为二分之一或者是满。
上面就是FIFO的阀值配置的具体计算,我们也可以根据上面的表格进行配置。

DMA传输模式

DMA有两种传输模式,分别是突发传输和单次传输。突发传输需要跟FIFO结合使用,每次传输4 个、8 个和 16个节拍。单次传输就每次传输一个节拍数。

DMA传输方向

DMA一共有3种传输方向,分别是存储器到存储器,存储器到外设和外设到存储器。这3种传输方向都需要配置源寄存器和目标寄存器。如果把DMA比作是一条公路,那么源寄存器就是起点,目标寄存器就是终点。
STM32F4X DMA_第5张图片

存储器到存储器

存储器到存储器可以理解成就是MCU内部数据之间的搬运。
STM32F4X DMA_第6张图片
在此模式下,我们需要将源寄存器设置为需要发送数据的存储器地址,目标寄存器设置为需要接收数据的存储器地址。要注意的是使用存储器到存储器模式时,不允许循环模式和直接模式。只有 DMA2 控制器能够执行存储器到存储器的传输。

存储器到外设

存储器到外设一般用于将存储器的数据发送到外设,外设可以是串口的发送寄存器,SPI的发送寄存器等。
STM32F4X DMA_第7张图片
在此模式下,我们需要将源寄存器设置为需要发送数据的存储器地址,目标寄存器设置为需要接收数据的外设地址。

外设到存储器

外设到存储器一般用于将外设的数据发送到存储器,外设可以是串口的接收寄存器,SPI的接收寄存器等。
STM32F4X DMA_第8张图片
在此模式下,我们需要将源寄存器设置为需要发送数据的外设地址,目标寄存器设置为需要接收数据的存储器地址。

DMA循环模式和普通模式

循环模式(Circular)

  • 在循环模式下,DMA的传输是循环进行,当DMA完成一次传输后会自动进入下一次传输,形成一个循环。
  • 在循环模式下,DMA把源数据寄存器中的数据搬到目标数据寄存器,当传输条件完成后,自动进行下一次传输
  • 循环模式适用于那些周期性数据传输的场景,比如ADC的采集,音视频数据流的传输等。

普通模式(Normal)

  • 在普通模式下,DMA的传输只会执行一次,当DMA完成一次传输后就会停止。
  • 在普通模式下,DMA会把源数据寄存器中的数据搬到目标数据寄存器,当传输条件完成后,就会停止。
  • 普通模式适用于那些只传输一次数据的场景,比如初始化传感器等。

DMA源、目标寄存器增量模式

DMA的源和目标寄存器有两个增量模式,分别是递增和固定

  • 递增模式:每一次数据传输之后,其地址指针会递增(增量为用户设置的数据大小)
  • 固定模式::每一次数据传输之后,其地址指针不变。

DMA例程

存储器到存储器例程

dma.c

void bsp_dma_u8_init(DMA_Stream_TypeDef* DMAy_Streamx,u32 dam_channel,u8 *src,u8 *dst,u32 len)
{
	DMA_InitTypeDef DMA_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_DMA1,ENABLE);   
	 
	DMA_InitStructure.DMA_Channel = dam_channel;                                           //通道选择
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)src;                                //DMA外设地址
	DMA_InitStructure.DMA_Memory0BaseAddr = (u32)dst;                                   //DMA 存储器0地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;                        //存储器到外设模式
	DMA_InitStructure.DMA_BufferSize = len;                                       //数据传输量 
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;               //外设非增量模式
	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_High;                          //中等优先级
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;       // 使能FIFO
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; // FIFO阀值满
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4;                    //
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;            //
	DMA_Init(DMAy_Streamx, &DMA_InitStructure);    

	
	while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE){}
	DMA_Cmd(DMAy_Streamx, ENABLE);


}

void bsp_dma_u16_init(DMA_Stream_TypeDef* DMAy_Streamx,u32 dam_channel,u16 *src,u16 *dst,u32 len)
{
	DMA_InitTypeDef DMA_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_DMA1,ENABLE);   
	 
	DMA_InitStructure.DMA_Channel = dam_channel;                                           //通道选择
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)src;                                //DMA外设地址
	DMA_InitStructure.DMA_Memory0BaseAddr = (u32)dst;                                   //DMA 存储器0地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;                        //存储器到外设模式
	DMA_InitStructure.DMA_BufferSize = len;                                       //数据传输量 
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;               //外设非增量模式
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                        //存储器增量模式
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;    //外设数据长度:16位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;            //存储器数据长度:16位
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                //使用普通模式 
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;                          //中等优先级
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;       // 使能FIFO
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;// FIFO阀值满
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC8;                    //存储器突发单次传输
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC8;            //外设突发单次传输
	DMA_Init(DMAy_Streamx, &DMA_InitStructure);    

	
	while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE){}
	DMA_Cmd(DMAy_Streamx, ENABLE);
}


void bsp_dma_u32_init(DMA_Stream_TypeDef* DMAy_Streamx,u32 dam_channel,u32 *src,u32 *dst,u32 len)
{
	DMA_InitTypeDef DMA_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_DMA1,ENABLE);   
	 
	DMA_InitStructure.DMA_Channel = dam_channel;                                           //通道选择
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)src;                                //DMA外设地址
	DMA_InitStructure.DMA_Memory0BaseAddr = (u32)dst;                                   //DMA 存储器0地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;                        //存储器到外设模式
	DMA_InitStructure.DMA_BufferSize = len;                                       //数据传输量 
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;               //外设非增量模式
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                        //存储器增量模式
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;    //外设数据长度:32位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;            //存储器数据长度:16位
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                //使用普通模式 
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;                          //中等优先级
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;      // 使能FIFO
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;// FIFO阀值满
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4;                    //存储器突发单次传输
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;            //外设突发单次传输
	DMA_Init(DMAy_Streamx, &DMA_InitStructure);    

	
	while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE){}
	DMA_Cmd(DMAy_Streamx, ENABLE);
}
	
	
ErrorStatus compare_u8_buff(u8 *src,u8 *dst,u32 len)
{
	int i;
	for(i = 0;i < len;i++)
	{
		if(src[i] != dst[i])
			return ERROR;
	}
	return SUCCESS;
}

ErrorStatus compare_u16_buff(u16 *src,u16 *dst,u32 len)
{
	int i;
	for(i = 0;i < len;i++)
	{
		if(src[i] != dst[i])
			return ERROR;
	}
	return SUCCESS;
}

ErrorStatus compare_u32_buff(u32 *src,u32 *dst,u32 len)
{
	int i;
	for(i = 0;i < len;i++)
	{
		if(src[i] != dst[i])
			return ERROR;
	}
	return SUCCESS;
}

dma_tset_data.h

u8 src_u8_buff[] =
{
//随机数个数:100;每行显示个数:10;取值范围:0到255

148,	119,	56,	38,	124,	10,	219,	102,	125,	5,	
53,	188,	144,	202,	43,	70,	236,	3,	212,	145,	
125,	65,	139,	92,	146,	227,	66,	158,	214,	58,	
25,	202,	129,	235,	47,	81,	207,	148,	183,	104,	
178,	178,	79,	13,	195,	194,	142,	68,	127,	166,	
220,	167,	176,	75,	135,	29,	41,	137,	19,	234,	
182,	74,	209,	232,	83,	239,	179,	19,	156,	239,	
94,	75,	133,	193,	129,	86,	75,	253,	101,	37,	
171,	190,	198,	88,	81,	74,	226,	4,	147,	245,	
207,	179,	95,	66,	17,	172,	114,	76,	108,	117,
};


u16 src_u16_buff[] =
{

//随机数个数:100;每行显示个数:10;取值范围:256到65535

22787,	5224,	1902,	6448,	21531,	32946,	6422,	4832,	17488,	23689,	
13175,	8272,	21386,	8319,	18916,	4179,	23261,	12460,	8750,	31562,	
5051,	6408,	12149,	675,	26984,	26904,	3901,	10656,	32431,	29389,	
23748,	11098,	15316,	28841,	20116,	29189,	30921,	22307,	21076,	4981,	
6052,	21837,	6883,	30433,	9041,	18612,	21672,	2024,	18052,	10375,	
29731,	6865,	12018,	11260,	21192,	26135,	12481,	12272,	3598,	13605,	
15933,	8142,	23747,	14430,	1996,	26033,	20130,	5728,	22564,	9677,	
10791,	8842,	32955,	18699,	23714,	23740,	27263,	6899,	12427,	7773,	
7880,	32463,	15893,	6307,	23691,	32781,	18949,	2062,	3536,	16870,	
1733,	16694,	12646,	4669,	27572,	31431,	3285,	9162,	5825,	30922,	
};

u32 src_u32_buff[] =
{
   //随机数个数:100;每行显示个数:10;取值范围:65535到100000

88361,	75899,	94546,	97752,	82130,	75054,	97136,	68892,	98163,	83019,	
76892,	94669,	66625,	86400,	70941,	89254,	86425,	83976,	97555,	68700,	
77042,	70351,	78217,	77532,	68369,	71639,	95113,	92116,	68732,	70362,	
96244,	73846,	73264,	66353,	77266,	66681,	70294,	78068,	81638,	86112,	
83636,	68963,	97925,	87294,	75680,	94852,	80553,	87098,	76859,	67086,	
74562,	72464,	71451,	82822,	80844,	97496,	70857,	94632,	68390,	70603,	
68141,	67336,	97698,	92867,	75590,	82425,	77145,	95298,	70175,	96174,	
66753,	94902,	81406,	89759,	94081,	79355,	82654,	88110,	68995,	86562,	
84255,	97675,	72779,	78705,	89469,	95189,	68232,	78762,	82239,	84866,	
92649,	70801,	68272,	93952,	78642,	66472,	76243,	91292,	69775,	68413,	
};

main.c


u8 dst_u8_buff[sizeof(src_u8_buff)/ sizeof(src_u8_buff[0])];
u16 dst_u16_buff[sizeof(src_u16_buff) / sizeof(src_u16_buff[0])];
u32 dst_u32_buff[sizeof(src_u32_buff) / sizeof(src_u32_buff[0])];
int main(void)
{
	int i;
	NVIC_PriorityGroupConfig(2);
	system_tick_init();
	
	bsp_usart_init(115200);

	bsp_dma_u8_init(DMA2_Stream0,DMA_Channel_0,src_u8_buff,dst_u8_buff,sizeof(src_u8_buff)/ sizeof(src_u8_buff[0]));
	while(DMA_GetFlagStatus(DMA2_Stream0,DMA_FLAG_TCIF0) != SET);
	if(compare_u8_buff(src_u8_buff,dst_u8_buff,sizeof(src_u8_buff)/ sizeof(src_u8_buff[0])) == SUCCESS)
		printf("u8 success\r\n");
	else
		printf("u8 error\r\n");
	
	
	bsp_dma_u16_init(DMA2_Stream1,DMA_Channel_1,src_u16_buff,dst_u16_buff,sizeof(src_u16_buff)/ sizeof(src_u16_buff[0]));
	while(DMA_GetFlagStatus(DMA2_Stream1,DMA_FLAG_TCIF1) != SET);
	if(compare_u16_buff(src_u16_buff,dst_u16_buff,sizeof(src_u16_buff)/ sizeof(src_u16_buff[0])) == SUCCESS)
		printf("u16 success\r\n");
	else
		printf("u16 error\r\n");
	
	bsp_dma_u32_init(DMA2_Stream2,DMA_Channel_2,src_u32_buff,dst_u32_buff,sizeof(src_u32_buff)/ sizeof(src_u32_buff[0]));
	while(DMA_GetFlagStatus(DMA2_Stream2,DMA_FLAG_TCIF2) != SET);
	if(compare_u32_buff(src_u32_buff,dst_u32_buff,sizeof(src_u32_buff)/ sizeof(src_u32_buff[0])) == SUCCESS)
		printf("u32 success\r\n");
	else
		printf("u32 error\r\n");
			
  while(1){
	  
	  
	  
	
	  
		delay_ms(1000);
	  
	}
  
}

存储器到外设例程


void bsp_dma_init(DMA_Stream_TypeDef* DMAy_Streamx,u32 dam_channel,u32 src,u32 dst,u32 len)
{
	DMA_InitTypeDef DMA_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_DMA1,ENABLE);   
	 
	DMA_InitStructure.DMA_Channel = dam_channel;                                           //通道选择
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)dst;                                //DMA外设地址
	DMA_InitStructure.DMA_Memory0BaseAddr = (u32)src;                                   //DMA 存储器0地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                        //存储器到外设模式
	DMA_InitStructure.DMA_BufferSize = len;                                       //数据传输量 
	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_High;                          //中等优先级
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;      
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                    //存储器突发单次传输
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;            //外设突发单次传输
	DMA_Init(DMAy_Streamx, &DMA_InitStructure);    

	
	while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE){}
	DMA_Cmd(DMAy_Streamx, ENABLE);


}

const u8 text_to_send[]="HuJeZC2ERQ6UIRIJMCa0";	 
#define SEND_BUF_SIZE ((sizeof(text_to_send) + 2) * 1000)	//发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.
u8 string_buff[SEND_BUF_SIZE];
int main(void)
{
	int i,j,t,mask = 0;
	NVIC_PriorityGroupConfig(2);
	system_tick_init();
	
	bsp_usart_init(115200);
	j=sizeof(text_to_send);	   
	for(i=0;i<SEND_BUF_SIZE;i++)//填充ASCII字符集数据
    {
		if(t>=j)//加入换行符
		{
			if(mask)
			{
				string_buff[i]=0x0a;
				t=0;
			}else 
			{
				string_buff[i]=0x0d;
				mask++;
			}	
		}else//复制TEXT_TO_SEND语句
		{
			mask=0;
			string_buff[i]=text_to_send[t];
			t++;
		}   	   
    }		 
	
	bsp_dma_init(DMA2_Stream7,DMA_Channel_4,(u32)string_buff,(u32)&USART1->DR,(sizeof(string_buff) / sizeof(string_buff[0])));
	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
	while(DMA_GetFlagStatus(DMA2_Stream7,DMA_FLAG_TCIF7) != SET);
	
  while(1){
	  
		delay_ms(1000);
	  
	}
  
}

外设到存储器例程

#define   NUM      10000        //采集次数


extern u16 adc_value[2];
extern u16 translate_end ;
void ADC_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	
}

void DMA_ADC_Config(void)
{
	
	ADC_CommonInitTypeDef ADC_CommonInitStruct,ADC_CommonInitStructure;
	ADC_InitTypeDef ADC_InitStruct,ADC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	
	ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;                       //独立模式
	ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;  //两个采样阶段之间的延迟x个时钟
	ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_1;               //DMA使能(DMA传输下要设置使能)
	ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div4;                    //预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz 
	ADC_CommonInit(&ADC_CommonInitStruct);                                      //初始化 
		
	ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;                         //12位模式
	ADC_InitStruct.ADC_ScanConvMode =ENABLE;                                    //扫描(开启DMA传输要设置扫描)
	ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;                             //开启连续转换(开启DMA传输要设置连续转换)
	ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;    //禁止触发检测,使用软件触发
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;                         //右对齐	
	ADC_InitStruct.ADC_NbrOfConversion = 3;                                    //有几个通道传输就写几 (DMA传输下要设置为通道数)
	ADC_Init(ADC1, &ADC_InitStruct);                                            //ADC初始化

	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1,  ADC_SampleTime_480Cycles);   
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2,  ADC_SampleTime_480Cycles);   
	ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 3,  ADC_SampleTime_480Cycles);   

	
	ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
	ADC_DMACmd(ADC1, ENABLE);
	ADC_Cmd(ADC1, ENABLE); 


}

void DMA_Config(void)
{
	
	DMA_InitTypeDef DMA_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);   
	
	DMA_InitStructure.DMA_Channel = DMA_Channel_0;                                           //通道选择
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;                                //DMA外设地址
	DMA_InitStructure.DMA_Memory0BaseAddr = (u32)adc_value;                                   //DMA 存储器0地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                        //存储器到外设模式
	DMA_InitStructure.DMA_BufferSize = 3;                                       //数据传输量 
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;               //外设非增量模式
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                        //存储器增量模式
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;    //外设数据长度:16位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;            //存储器数据长度:16位
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                //使用普通模式 
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;                          //中等优先级
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;      
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                    //存储器突发单次传输
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;            //外设突发单次传输
	DMA_Init(DMA2_Stream0, &DMA_InitStructure);        


	DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0);
	//DMA_ClearFlag(DMA2_Stream0,DMA_IT_TC);
	DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE);
		
	NVIC_InitStructure.NVIC_IRQChannel=DMA2_Stream0_IRQn; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;                     //抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x01;                            //响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE){}
	DMA_Cmd(DMA2_Stream0, ENABLE);
		

}

void DMA2_Stream0_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA2_Stream0,DMA_IT_TCIF0) == SET)
	{
		translate_end = 1;
		DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0);
	}
}


u16 adc_value[3];
u32 adc_channel1_average_value = 0,adc_channel2_average_value = 0,adc_channel3_average_value = 0;
u16 translate_end = 0;
int main(void)
{
	int count = 0;
	float adc_temp_value1,adc_temp_value2,adc_temp_value3;
	NVIC_PriorityGroupConfig(2);
	system_tick_init();
	
	bsp_usart_init(115200);

	ADC_GPIO_Config();
	DMA_ADC_Config();
	DMA_Config();
	ADC_SoftwareStartConv(ADC1);   
  while(1){
	  if(translate_end)
	  {
		  if(count <= NUM)
		  {
			  adc_channel1_average_value += adc_value[0];
			  adc_channel2_average_value += adc_value[1];
			  adc_channel3_average_value += adc_value[2];
			  count++;

		  }
		  else
		  {
			  count = 0;
			  adc_temp_value1 = (float)(adc_channel1_average_value / NUM) * 3.3 / 4096;
			  adc_temp_value2 = (float)(adc_channel2_average_value / NUM) * 3.3 / 4096;
			  adc_temp_value3 = (float)(adc_channel3_average_value / NUM) * 3.3 / 4096;
			  printf("ch1 %f ch2 %f ch3 %f\r\n", adc_temp_value1,adc_temp_value2,adc_temp_value3);
			  adc_channel1_average_value = 0;
			  adc_channel2_average_value = 0;
			  adc_channel3_average_value = 0;
		  }
		
		  translate_end = 0;
	  }
		

	}
  
}

你可能感兴趣的:(STM32学习,stm32,嵌入式硬件)