STM32F4X DMA

news2025/2/1 5:59:42

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框图

在这里插入图片描述

DMA通道

STM32F4X的每一个DMA控制器有8个数据流,每个数据流又有8个通道。每个通道都会对应相关的外设。
在这里插入图片描述
在这里插入图片描述

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 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比作是一条公路,那么源寄存器就是起点,目标寄存器就是终点。
在这里插入图片描述

存储器到存储器

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

存储器到外设

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

外设到存储器

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

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;
	  }
		

	}
  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/999915.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文简介,数字时代的数据交易模式

在数字时代&#xff0c;数据作重要的信息和资源&#xff0c;未来获得更高质量的数据资源&#xff0c;数据交易越来越常见&#xff0c;数据也成为企业重要的无形资产。 2022年3月出台的《中共中央、国务院关于加快建设全国统一大市场的意见》强调要加快培育数据要素市场&#xf…

Zabbix登录绕过漏洞复现(CVE-2022-23131)

0x00 前言 最近在复现zabbix的漏洞&#xff08;CVE-2022-23131&#xff09;&#xff0c;偶然间拿到了国外某公司zabbix服务器。Zabbix Sia Zabbix是拉脱维亚Zabbix SIA&#xff08;Zabbix Sia&#xff09;公司的一套开源的监控系统。该系统支持网络监控、服务器监控、云监控和…

Jetpack Compose 1.5 发布:全新 Modifier 系统助力性能提升

不久前 Compose 1.5.0 稳定版发布&#xff0c;在组合的性能方面得到明显改善&#xff0c;这主要归功于对 Modifier API 的持续重构。 Modifier 是 Compose 中的重要概念&#xff0c;为 Composition 中的 LayoutNode 配置各种样式信息以用于后续渲染。在 1.3.0 之前的 Modifier …

Java知识点二

Java知识点二 1、Comparable内部比较器&#xff0c;Comparator外部比较器2、源码结构的区别:1&#xff09;Comparable接口&#xff1a;2&#xff09;Comparator接口&#xff1a; 2、Java反射 1、Comparable内部比较器&#xff0c;Comparator外部比较器 我们一般把Comparable叫…

【MySQL】表的增删改查

目录 MySQL表的增删查改 Create 单行数据全列插入 多行数据指定列插入 插入否则更新 替换数据 Retrieve SELECT 列 全列查询 指定列查询 查询字段为表达式 为查询结果指定别名 结果去重 WHERE 条件 查询英语不及格的同学及其英语成绩 查询语文成绩在80到90分的…

【自动化测试】如何在jenkins中搭建allure

相信大家在做自动化测试过程中&#xff0c;都会用到自动化测试环境&#xff0c;目前最常见的就是通过容器化方式部署自动化测试环境&#xff0c;但对于一些测试小白&#xff0c;不是很会搭建持续集成环境&#xff0c;特别是从0-1的过程&#xff0c;需要自行搭建很多依赖环境&am…

完全保密的以太坊交易:Aztec网络的隐私架构

1. 引言 Aztec为隐私优先的以太坊zkRollup&#xff1a;即其为具有完全隐私保护的L2。 为了理解私有交易的范式变化性质&#xff0c;以及为什么将隐私直接构建到网络架构中很重要&#xff0c;必须首先讨论为什么以太坊不是私有的。 2. 以太坊&#xff1a;公有链 以太坊为具有…

设计师常用的8款作图软件推荐

在数字时代&#xff0c;绘图软件已经成为设计师不可缺少的工具。从图形设计到插图&#xff0c;从传统绘图到人工智能绘画&#xff0c;为了实现高效、方便、创意的设计&#xff0c;设计师需要一个强大的绘图软件。本文将介绍8个易于使用的绘图软件&#xff0c;每个软件都具有独特…

ME51N 采购申请屏幕增强仅显示字段

1、业务需求 通过委外工单生成的采购申请&#xff0c;需要将自定义“图号”字段显示在采购申请中&#xff0c;且只用于显示即可 2、增强实现 增强表EBAN的结构CI_EBANDB 增强点CMOD&#xff1a;MEREQ001 出口EXIT_SAPLMEREQ_001 首先在TOP文件中引入全局CI_EBANDB 创建子屏…

动态渲染 echarts 饼图(vue 2 + axios + Springboot)

目录 前言1. 项目搭建1.1. 前端1.2. 后端 2. 后端数据渲染前端2.1 补充1&#xff1a;在 vue 中使用 axios2.2. 补充2&#xff1a;Springboot 处理跨域问题2.3. 修改前端代码2.3.1 修改饼图样式2.3.2 调用后台数据渲染饼图2.3.3 改造成内外两个圈 前言 因为上文中提到的需求就是…

轻松上手Three.js:JavaScript 3D库指南

1.Three.js概述 Three.js是使用JavaScript语言编写的一款运行在浏览器中的3D引擎。与WebGL不同&#xff0c;开发人员在使用Three.js进行开发时&#xff0c;无须掌握高深的图形学知识&#xff0c;只需使用少量JavaScript代码即可创建出一个3D场景。可以说&#xff0c;Three.js的…

恒运资本:小盘股的优点?投资小盘股要注意哪些方面?

股市是一个充溢时机和危险的当地&#xff0c;不同出资者有不同的偏好&#xff0c;有的人喜爱追逐大盘蓝筹股&#xff0c;有的人则钟情于小盘股。那么小盘股的长处&#xff1f;出资小盘股要注意哪些方面&#xff1f;恒运资本也为我们准备了相关内容&#xff0c;以供参考。 小盘股…

vue+springboot+mysql的垃圾分类管理系统

1、引言 设计结课作业,课程设计无处下手&#xff0c;网页要求的总数量太多&#xff1f;没有合适的模板&#xff1f;数据库&#xff0c;java&#xff0c;python&#xff0c;vue&#xff0c;html作业复杂工程量过大&#xff1f;毕设毫无头绪等等一系列问题。你想要解决的问题&am…

六、Hive数据仓库应用之Hive事务(超详细步骤指导操作,WIN10,VMware Workstation 15.5 PRO,CentOS-6.7)

Hive远程模式部署参考&#xff1a; 一、Hive数据仓库应用之Hive部署&#xff08;超详细步骤指导操作&#xff0c;WIN10&#xff0c;VMware Workstation 15.5 PRO&#xff0c;CentOS-6.7&#xff09; 文章目录 一、事务的设计与特点1、事务的特点2、事务的设计3、事务的实现 二、…

【LeetCode刷题笔记】动态规划 — 70.爬楼梯

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多算法知识专栏&#xff1a;算法分析&#x1f525; 给大家跳段街舞感谢…

Python不是一种伟大的编程语言?

作为一门简洁易用、生态蓬勃且具有高泛用性的编程语言&#xff0c;Python一直以来都被不少人称作“编程语言中的瑞士军刀”。 尤其随着近来AI热潮席卷全球&#xff0c;Python在编程语言圈中的地位也随之水涨船高&#xff0c;甚至一度被视作AI专用语言或大数据专用语言。 然而…

Netty核心原理:一、基础入门-04:NettyServer字符串解码器

文章目录 一、前言介绍二、代码实现2.1 工程结构2.2 Netty服务端字符串解码器实现2.2.1 服务端处理器2.2.2 通道初始化2.2.3 netty服务端 2.3 单元测试 一、前言介绍 &#x1f4a1; 服务端接收数据后我们希望是一个字符串或者是一个对象类型,而不是字节码。 在 netty 中是否可以…

数据结构与算法基础-学习-33-归并排序

目录 一、基本思想 二、算法思路 1、合并两个有序序列 2、分治法 三、算法源码 1、MergeSortTwoSortData 2、TwoWayMergeSortRecurtionSentryQueue 四、算法效率分析 五、Linux环境编译测试 六、小感慨 排序的其他相关知识点和源码分享可以参考之前的博客&#xff1a…

解决 Android 依赖冲突

解决办法 问题原因就是&#xff0c;各个模块所有的依赖&#xff08;递归&#xff09;的 jar 包最后都会加载到安卓的项目中&#xff0c;你可以选择 project 形式查看 External Libraries&#xff0c;都在这了。所以解决问题关键就是干掉冲突&#xff0c;剩下一个就行了&#xf…

将Apache服务与内网穿透结合,让您的网站可以公网访问

Apache服务安装配置与结合内网穿透实现公网访问 文章目录 Apache服务安装配置与结合内网穿透实现公网访问前言1.Apache服务安装配置1.1 进入官网下载安装包1.2 Apache服务配置 2.安装cpolar内网穿透2.1 注册cpolar账号2.2 下载cpolar客户端 3. 获取远程桌面公网地址3.1 登录cpo…