STM32---adc-fft-信号相位差
目录
前言:
在信号处理领域,测量两个信号之间的相位差在许多应用中至关重要,如电力系统的同步、振动分析、以及通信系统中的相位调制。STM32系列微控制器,特别是STM32F407,具有强大的ADC模块,可以实现多路同步采样。通过使用三重ADC同步采样,并结合快速傅里叶变换(FFT),我们可以精确地测量信号之间的相位差。本次将分享如何使用STM32,利用三重ADC同步采样模式,配合FFT测信号相位差。本教程使用stm32f4,基于cubemx、keil5开发。(相位差这一概念,存在于频率相同,相位不同的信号中)
基础知识:
有关FFT的使用方法,大家可以先看看这篇博客
STM32系列微控制器(如STM32F407)提供了多个ADC模块,允许用户配置它们以同步方式采样多个通道。STM32的多ADC模块可以通过一个公共触发源(例如一个定时器)来实现同步启动,从而保证多ADC通道的采样在同一时间点进行。
正文:
关于时钟,串口,定时器这些比较常规的配置,我就不多做解释了,在下面这篇文章中我有过详细的介绍,如果需要的话,大家可以先看看这篇文章了解一下。下面ADC的配置比较重要!!!
——《stm32-HAL 电赛信号教程》
时钟配置:
基础配置:
串口配置:
TIM定时器:
这里我开的是2M采样率。128M/64=2M
ADC配置:
DMA配置:
到此,配置完成。
代码示例:
这里就以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的信号,可以发现两图案是重叠的,证明确实是同步采样。
结语:
测量相位的内容较多且较为复杂,可以有点难理解,希望我的分享对大家能有帮助。如果需要完整代码,可以私信我或者留言,有疑问或建议欢迎留言!(这些代码都是在实验室验证过的哟)