ADC acquisition experiment

Keywords: Single-Chip Microcomputer IoT stm32

catalogue

Test requirements:

Experimental equipment:

Experimental ideas:

Experimental steps:

Summary:

Program source code:

Test requirements:

Collect 50hz AC through stm32ADC and display it through serial port

Experimental equipment:

Wildfire stm32MINI series with stm32f103RC chip

Experimental ideas:

Trigger ADC through Tim (timer) for data sampling, and convert the collected data into the specified array through DMA. After one sampling, traverse the array, read the row data, determine the maximum and minimum values, and obtain the peak and peak values through the difference between the maximum and minimum values. Through mathematical operation, the effective value and peak value are obtained.

Note: the voltage displayed by the generator is peak to peak. When there is no external circuit connected, the single chip microcomputer can only collect 0~3.3V. Therefore, the data voltage obtained by a single chip multiplied by two is the voltage displayed by the generator.

Experimental steps:

1. Write ADC configuration:

static void ADCx_Mode_Config(void)
{
	ADC_InitTypeDef ADC_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	  //Enable ADC1 channel clock

	//ADC1 initialization
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 			//Independent ADC mode
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;  			//Turn off scanning mode
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;			//Turn off continuous conversion mode
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;   	//Use external trigger mode
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 			//Right alignment of collected data
	ADC_InitStructure.ADC_NbrOfChannel = 1; 			//Number of channels to convert
	ADC_Init(ADCx, &ADC_InitStructure);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);				//Configure ADC clock to divide PCLK2 by 6, i.e. 12Hz
	ADC_RegularChannelConfig(ADCx, ADC_Channel_6, 1, ADC_SampleTime_239Cycles5);		//Configure ADC1 channel 6 to 239.5 sampling cycles 
	
	//Enable ADC, DMA
	ADC_DMACmd(ADCx,ENABLE);
	ADC_Cmd(ADCx,ENABLE);
 
	ADC_ResetCalibration(ADCx);				//Reset calibration register
	while(ADC_GetResetCalibrationStatus(ADCx));				//Wait for the calibration register reset to complete
 
	ADC_StartCalibration(ADCx);				//ADC calibration
	while(ADC_GetCalibrationStatus(ADCx));				//Wait for calibration to complete
	
	ADC_ExternalTrigConvCmd(ADCx, ENABLE);		//Set external trigger mode enable
}

2.DMA configuration:

/* DMA1 to configure */
void DMAx_Mode_Config()
{
	DMA_InitTypeDef DMA_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_AHBPeriphClockCmd(DMA_CLK,ENABLE);	  										//Enable ADC1 channel clock
	
	//DMA1 initialization
	DMA_DeInit(DMA_CHANNE);
	DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) ( & ( ADCx->DR ) );			//ADC1 address
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue; 			//Memory address
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 								//Direction (from peripheral to memory)
	DMA_InitStructure.DMA_BufferSize =  (uint32_t)DMA_LEN; 							//Size of transmitted content
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 				//Fixed peripheral address
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 						//Memory address increment
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; 	//Peripheral data unit
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ;   			//Memory data unit
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular  ; 								//DMA mode: cyclic transmission
	DMA_InitStructure.DMA_Priority = DMA_Priority_High ; 							//Priority: high
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;   									//Disable memory to memory transfer
	DMA_Init(DMA_CHANNE, &DMA_InitStructure);  										//Configuring DMA1
	
	DMA_ITConfig(DMA_CHANNE,DMA_IT_TC, ENABLE);										//Enable transmission completion interrupt

	NVIC_InitStructure.NVIC_IRQChannel = DMA_IRQN;									//Interrupt source settings
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;						//Preemptive Priority Scheduling 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;								//Sub priority
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;									//Enable interrupt
	NVIC_Init(&NVIC_InitStructure);
	
	DMA_Cmd(DMA_CHANNE,ENABLE);
}

3.ADC_GPIO settings

//GPIO configuration, PA6
void GPIO_Mode_Config()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(GPIO_CLK, ENABLE);	  					//Enable GPIOA clock 

	//PA6 as analog channel input pin   
	GPIO_InitStructure.GPIO_Pin = GPIO_PIN;		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIO_PORT, &GPIO_InitStructure);
}

4. Timer configuration

/* TIM2 to configure */
void TIMx_Mode_Config(u16 arr,u16 psc)												//arr is the reloading value and psc is the pre frequency division coefficient
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(TIM_CLK, ENABLE); 								//Clock enable

	//Timer TIM2 initialization
	TIM_TimeBaseStructure.TIM_Period = arr; 								//Sets the value of the auto reload register cycle of the load activity at the next update event
	TIM_TimeBaseStructure.TIM_Prescaler =psc; 								//Sets the prescaled value used as the divisor of TIMx clock frequency
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 				//Set clock division: TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 			//TIM up count mode
	TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);							//Initializes the time base unit of TIMx according to the specified parameters
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;						//Select timer mode: TIM pulse width modulation mode 1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;			//Compare output enable
	TIM_OCInitStructure.TIM_Pulse = TIM_PULSE;								//Pulse width
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;				//Output polarity: TIM output is relatively low polarity
	TIM_OC2Init(TIMx, & TIM_OCInitStructure);								//Initialize peripheral TIM2_CH2
	
	TIM_Cmd(TIMx, ENABLE); 													//Enable TIMx
	TIM_CtrlPWMOutputs(TIMx, ENABLE);
}

5.DAM terminal configuration

void DMA1_Channel1_IRQHandler(void)
{
	
	uint8_t i;
	uint16_t max=0;
	uint16_t min=4096;
    if(DMA_GetITStatus(DMA1_IT_TC1)!=RESET)
	{
		ADC_Cmd(ADC1, DISABLE);    //Disable ADC

		for(i=0;i<FFT_LENGTH;i++)
		{

		   if(max<ADC_ConvertedValue[i])
			 {
				 max=ADC_ConvertedValue[i];
			 }
			 if(min>ADC_ConvertedValue[i])
			 {
				 min=ADC_ConvertedValue[i]; 
			 }
		}
		fengzhi=(float)(max-min)*(3.3/4096);
		printf("Peak value:%.2f\r\n",fengzhi);
		printf("Valid values are:%.2f\r\n",(fengzhi/sqrt(2.0)));
		ADC_Cmd(ADC1, ENABLE);//Enable ADC  
    }
    DMA_ClearITPendingBit(DMA1_IT_TC1);
}

6. Configuration of other related functions

/* Data definition */
__IO uint16_t ADC_ConvertedValue[ADC_LEN] = {0};							// Collected and stored data
float fengzhi = 0;															//Definition of peak value
//float youxiao = 0; 														// The effective value is obtained by dividing the peak value by sqr(2), and the variable is not used yet
//float Rms = 0;

7. initialization

/* initialization */
void Adc_Init()
{
	TIMx_Mode_Config(100,71);		//(72000000/71+1)/(100+1)=10000HZ;
	ADCx_Mode_Config();
	DMAx_Mode_Config();
	GPIO_Mode_Config();
}

All the above are written in ADC.c file

Preparation of ADC.h file

#ifndef	__BSP_ADC_H
#define	__BSP_ADC_H

#include "stm32f10x.h"
#include "stdio.h"
#include "math.h"

/* General definition */
#define FFT_LENGTH	200

/* ADC Related pin definitions */
#define	ADCx	ADC1
#define ADC_LEN	200
#define	ADC_CLK	RCC_APB2Periph_ADC1

/* ADC Input pin definition */
#define	GPIO_PORT	GPIOC
#define	GPIO_PIN	GPIO_Pin_1
#define GPIO_CLK	RCC_APB2Periph_GPIOC

/*	DAM Related configuration */
#define	DMA_CLK		RCC_AHBPeriph_DMA1
#define DMA_CHANNE	DMA1_Channel1
#define	DMA_IRQN	DMA1_Channel1_IRQn;
#define DMA_LEN		200

/* TIM Related configuration */
#define TIMx		TIM2
#define	TIM_PULSE	50
#define	TIM_CLK		RCC_APB1Periph_TIM2

/* Function definition */
void Adc_Init(void);

#endif  /*__BSP__ADC_H*/

  The main function only needs to be added to the main function   Adc.Init()   that will do

Summary:

This experiment includes many contents. Through this experiment, the understanding of ADC, DMA and TIM functions is strengthened, and the learning content is further expanded. Pay attention to the bits and pieces of chapters and start down-to-earth in order to stabilize knowledge.

Program source code:

The input pin depends on the code. It is currently set to PC1, that is, the red line of the generator function is connected to PC1

Original version (unmodified, the program has been tested and can achieve the purpose of experiment)

Password: 0328 original

Beautified Version (function definition based on the original version for easy modification)

Password: 0328 beautification version

Note: in view of the network, I only do CTRl+C and CTRl+V, and modify and delete the code as required!

Posted by Randuin on Tue, 16 Nov 2021 18:48:13 -0800