赞
踩
目录
在信号处理领域,测量两个信号之间的相位差在许多应用中至关重要,如电力系统的同步、振动分析、以及通信系统中的相位调制。STM32系列微控制器,特别是STM32F407,具有强大的ADC模块,可以实现多路同步采样。通过使用三重ADC同步采样,并结合快速傅里叶变换(FFT),我们可以精确地测量信号之间的相位差。本次将分享如何使用STM32,利用三重ADC同步采样模式,配合FFT测信号相位差。本教程使用stm32f4,基于cubemx、keil5开发。(相位差这一概念,存在于频率相同,相位不同的信号中)
有关FFT的使用方法,大家可以先看看这篇博客
STM32系列微控制器(如STM32F407)提供了多个ADC模块,允许用户配置它们以同步方式采样多个通道。STM32的多ADC模块可以通过一个公共触发源(例如一个定时器)来实现同步启动,从而保证多ADC通道的采样在同一时间点进行。
关于时钟,串口,定时器这些比较常规的配置,我就不多做解释了,在下面这篇文章中我有过详细的介绍,如果需要的话,大家可以先看看这篇文章了解一下。下面ADC的配置比较重要!!!
——《stm32-HAL 电赛信号教程》
这里我开的是2M采样率。128M/64=2M
到此,配置完成。
这里就以ADC1和ADC2两个ADC采集为例,获得信号的相位差。但实际这个程序也采集了ADC3的数据,处理方法跟这两一样的哈。
(1)宏定义
- /* Private define ------------------------------------------------------------*/
- /* USER CODE BEGIN PD */
- #define FFT_LENGTH 1024
- #define ADC1_DMA_Size 3072
- #define ADC2_DMA_Size 1024
(2)定义数组变量
- int freq1=0; //获得ADC1采集信号的频率
- int freq2=0; //获得ADC2采集信号的频率
- float phase_1=0; //获得ADC1采集信号的相位
- float phase_2=0; //获得ADC2采集信号的相位
- float phase_differ=0; //相位差
- int SAM_FRE=2000000; //采样率-与cubemx配置的数据一致
- float fft_inputbuf1 [FFT_LENGTH*2];
- float fft_inputbuf2 [FFT_LENGTH*2];
- float fft_outputbuf1[FFT_LENGTH];
- float fft_outputbuf2[FFT_LENGTH];
- uint32_t ADC1_ConvertedValue[1024][3];//存放各ADC采集到的数据
(3)数据处理
打开ADC-DMA开启数据采集和传输。
- HAL_ADC_Start(&hadc1);
- HAL_ADC_Start(&hadc2);
- HAL_ADC_Start(&hadc3);
-
- HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t*)ADC1_ConvertedValue,3072);
- HAL_TIM_Base_Start(&htim8);
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
主函数main中
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- if(DMA_FLAG==1)
- {
- DMA_FLAG=0;
-
- HAL_TIM_Base_Stop(&htim8); //关闭ADC-tim,防止数据处理时数据变化
- HAL_ADCEx_MultiModeStop_DMA(&hadc1);
- HAL_ADC_Stop(&hadc1);
- HAL_ADC_Stop(&hadc2);
- HAL_ADC_Stop(&hadc3);
-
- for(int i=0;i<1024;i++)
- {
- //printf("%d,%d,%d\r\n",ADC1_ConvertedValue[i][0],ADC1_ConvertedValue[i][1],ADC1_ConvertedValue[i][2]);
- fft_inputbuf1[i*2]= (ADC1_ConvertedValue[i][0])*3.3/4095;//将ADC1采集的数据放到FFT待处理数组中
- fft_inputbuf1[2*i+1]=0;
- fft_inputbuf2[i*2]= (ADC1_ConvertedValue[i][1])*3.3/4095;//将ADC2采集的数据放到FFT待处理数组中
- fft_inputbuf2[2*i+1]=0;
- }
-
- arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_inputbuf1,0,1); //ADC1采集的数据FFT运算
- arm_cmplx_mag_f32(fft_inputbuf1, fft_outputbuf1, FFT_LENGTH);
-
- arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_inputbuf2,0,1); //ADC2采集的数据FFT运算
- arm_cmplx_mag_f32(fft_inputbuf2, fft_outputbuf2, FFT_LENGTH);
-
- freq1= findmax((float*)fft_outputbuf1,1024,2); //获得ADC1采集信号的频率
- freq2= findmax((float*)fft_outputbuf2,1024,2); //获得ADC2采集信号的频率
-
- phase_1=Phase_atan(fft_inputbuf1,freq1); //获得ADC1采集信号的相位
- phase_2=Phase_atan(fft_inputbuf2,freq2); //获得ADC2采集信号的相位
- phase_differ=phase_1-phase_2; //计算相位差
-
- if(phase_differ>180) //相位调整
- {
- phase_differ=phase_differ-360;
- }
- if(phase_differ<-180)
- {
- phase_differ=phase_differ+360;
- }
- printf("phase_differ = %f\r\n",phase_differ);
-
- HAL_Delay(1000);
-
- HAL_ADC_Start(&hadc1);
- HAL_ADC_Start(&hadc2);
- HAL_ADC_Start(&hadc3);
-
- HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t*)ADC1_ConvertedValue,3072);
- HAL_TIM_Base_Start(&htim8);
-
- }
-
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }

信号频率计算函数
- int findmax(float*arry,uint16_t len,uint16_t s) //s表示从第几个数开始找
- {
- int i;
- int j=s;
- for(i=s;i<len/2;i++)
- {
- if(arry[i]>arry[j])
- {
- j=i;
- }
- }
- return j;
- }
相位计算函数:FFT计算后的fft_inputbuf数组中,虚部除实部就是相位。
- //相位计算函数
- float Phase_atan(float32_t *inputSignal,uint32_t index)
- {
- return atan(inputSignal[2*index+1] / inputSignal[2*index]) / PI * 180;
- }
OKOK,代码编写完成,大家可以打ADC1与ADC2采集的数据使用vofa+打印出来,用函数信号发生器产生两个频率相同,相位差为0的信号,可以发现两图案是重叠的,证明确实是同步采样。
测量相位的内容较多且较为复杂,可以有点难理解,希望我的分享对大家能有帮助。如果需要完整代码,可以私信我或者留言,有疑问或建议欢迎留言!(这些代码都是在实验室验证过的哟)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。