stm32fl07采集交流电电压,通过fft找出最大幅值,以及电压的相位
时间: 2024-05-07 11:23:08 浏览: 72
要采集交流电电压,需要使用模拟输入通道。在STM32F407中,可以使用内置的ADC模块进行模拟输入。下面是一个简单的示例代码,可以采集电压并转换为数字信号:
```c
#include "stm32f4xx.h"
#include <stdio.h>
#include <math.h>
#define ADC1_DR_ADDRESS ((uint32_t)0x4001204C)
#define SAMPLES 512
#define PI 3.14159265358979323846
uint16_t ADCConvertedValues[SAMPLES];
float realValues[SAMPLES];
float imagValues[SAMPLES];
float magnitudeValues[SAMPLES/2];
float phaseValues[SAMPLES/2];
void GPIO_Configuration(void);
void ADC_Configuration(void);
void FFT(void);
int main(void)
{
GPIO_Configuration();
ADC_Configuration();
while(1)
{
ADC_SoftwareStartConv(ADC1);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
FFT();
//找出最大幅值及其相应的频率
float max = magnitudeValues[0];
int index = 0;
for(int i = 1; i < SAMPLES/2; i++)
{
if(magnitudeValues[i] > max)
{
max = magnitudeValues[i];
index = i;
}
}
float frequency = (float)index / SAMPLES * 10000; //假设采样率为10kHz
printf("Maximum magnitude: %f\n", max);
printf("Frequency: %f Hz\n", frequency);
printf("Phase: %f radians\n", phaseValues[index]);
}
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//使能GPIOA时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//配置PA0为模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void ADC_Configuration(void)
{
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
//使能ADC1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
//配置ADC1
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
//配置ADC1的通道0为模拟输入
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);
//启动ADC1的转换
ADC_Cmd(ADC1, ENABLE);
}
void FFT(void)
{
//将采样值转换为实数
for(int i = 0; i < SAMPLES; i++)
{
realValues[i] = (float)ADCConvertedValues[i] / 4096.0 * 3.3;
imagValues[i] = 0.0;
}
//计算FFT
for(int i = 0; i < SAMPLES/2; i++)
{
float realSum = 0.0;
float imagSum = 0.0;
for(int j = 0; j < SAMPLES; j++)
{
realSum += realValues[j] * cos(2 * PI * i * j / SAMPLES);
imagSum -= realValues[j] * sin(2 * PI * i * j / SAMPLES);
}
realValues[i] = realSum;
imagValues[i] = imagSum;
}
//计算幅值和相位
for(int i = 0; i < SAMPLES/2; i++)
{
magnitudeValues[i] = sqrt(realValues[i]*realValues[i] + imagValues[i]*imagValues[i]) / (SAMPLES/2);
phaseValues[i] = atan2(imagValues[i], realValues[i]);
}
}
```
在上面的代码中,我们采用了512点FFT计算电压的频谱,找出最大幅值及其相应的频率,以及该频率的相位。注意,这里假设采样率为10kHz,因此频率的单位是Hz,相位的单位是弧度。
阅读全文