catalogue
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)
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!