Acquisition of multiple ADCs - stm32

         In the actual application process, the acquisition of ADC is mostly collected by multiple channels at the same time. For example, to collect data from multiple sensors at the same time, we may need to configure multiple channels of ADC acquisition, and multi-channel ADC acquisition is mostly used. DMA, generally speaking, transferring data through DMA does not pass through the CPU, which can effectively reduce the burden on the CPU. We only need to complete the corresponding initialization through the CPU when using it, and the transmission itself is carried out by DMA, and for the collected data We only need to put the data of different channels into the specified array to get the specific data of different channels.

DMA channel configuration process:
1. Set the address registered by the peripheral in the DMA_CPARx register. When a peripheral data request occurs, this address will be the source or target of data transfer.
2. Set the address of the data storage register in the DMA_CMARx register. When a peripheral data request occurs, the transmitted data will be read from or written to this address.
3. Set the amount of data to be transferred in the DMA_CNDTRx register. This value is decremented after each data transfer.
4. Set the priority in the PL[1:0] bits of the DMA_CCRx register.
5. In the DMA_CCRx register, set the direction of data transfer, the circular mode, the incremental mode of peripherals and memory, the data width of peripherals and memory, half of the transfer will generate an interrupt, or the
     transfer will be completed to generate an interrupt.
6. Set the ENABLE bit of the DMA_CCRx register to enable the channel.

The specific configuration process we show through the code

First define an array so that we can store data, and the size of the array can be based on actual needs.

u16 ADC_convered[2]={0,0};

Then the initialization of the io port (I also directly enabled the clock of the ADC here) 

static void ADC_GPIO_CONFIG(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1	, ENABLE );	//使能 
    ADC1通道时钟
	//PA1 作为模拟通道输入引脚                         
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//初始化两个GPIO
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
}

The next step is the main event - the initialization of DMA and ADC (some parts need to configure multiple channels)

static void ADC_MODE_CONFIG_(void)
{ 	
	
	DMA_InitTypeDef DMA_InitInstructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	DMA_DeInit(DMA1_Channel1);//复位
	DMA_InitInstructure.DMA_PeripheralBaseAddr =(u32)(&(ADC1->DR));//配置外设的基址,取adc 
    数据寄存器的地址
	DMA_InitInstructure.DMA_MemoryBaseAddr = (u32)ADC_convered;//把DMA的数据存入数组
	DMA_InitInstructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设到DMA
	DMA_InitInstructure.DMA_BufferSize = 2;//2个通道
	DMA_InitInstructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//
	DMA_InitInstructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitInstructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitInstructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitInstructure.DMA_Mode = DMA_Mode_Circular;//不断地传输,有数据就传输
	DMA_InitInstructure.DMA_Priority = DMA_Priority_High;//DMA优先级
	DMA_InitInstructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel1,&DMA_InitInstructure);
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA请求
	
	
	
	
	
	ADC_InitTypeDef ADC_InitStructure; 
	ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立 
    模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;	//模数转换工作在多通道模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//模数转换工作在连续转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是 
    外部触发启动
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 2;	//顺序进行规则转换的ADC通道的数目
	ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄 
    存器   




	RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
		//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1,1, ADC_SampleTime_239Cycles5 );	 
      //ADC1,ADC1通道1,采样时间为239.5周期
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2,2, ADC_SampleTime_239Cycles5 );	 
     //ADC1,ADC1通道2,采样时间为239.5周期

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

	
	ADC_ResetCalibration(ADC1);	//使能复位校准  
	 
	while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束
	
	ADC_StartCalibration(ADC1);	 //开启AD校准
 
	while(ADC_GetCalibrationStatus(ADC1));	 //等待校准结束
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能	
	 
	//while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束


}				  

Then put the initialization program into one piece, which is convenient to call

void Adc_Init()
{
   ADC_GPIO_CONFIG();
   ADC_MODE_CONFIG_();
}

Next is the main function part. The main function mainly depends on what kind of function is to be realized. After initialization, it is actually to display the collected data or set the threshold and then perform the corresponding operation.

extern u16 ADC_convered[2];

int main(void)
{ 
   delay_init();
	//uart_init(9600);//串口初始化为9600,串口打印需要对其进行初始化
   float temp[2];
   delay_init();
   Oled_Init();
   Adc_Init();

	float value;
	float value1;
	char buf[5];
	char buf1[5];

	while(1)
	{
	    temp[0]=(float)ADC_convered[0]/4096*3.3;
		temp[1]=(float)ADC_convered[1]/4096*3.3;//结果-电压转换
		
		//printf("\r\n THE AD1 is = %f V \r\n",temp[0]);
		//printf("\r\n THE AD2 is = %f V \r\n",temp[1]);
	
        value = temp[0];
		sprintf(buf,"%f",value);
		Oled_Display_String(0,0,buf);//显示电压值
		
		value1 = temp[1];  
	    sprintf(buf1,"%f",value1);	
		Oled_Display_String(2,0,buf1);//显示电压值
		
		//Oled_Display_String(4,0,buf1);//	
		
		delay_ms(500);//延时了一小会儿,要不数据变化太快,看的心烦
        //我这儿是把电压值显示在了oled上
	}	  
}	

Please point out any mistakes, thank you

 

Guess you like

Origin blog.csdn.net/qq_52487856/article/details/119425241