这里首先非常感谢“四臂西瓜”这位博主的学习资料以及他的代码!
STM32实现FFT,求取幅度频谱_stm32 fft-CSDN博客
我这里只是将他的代码整合了一次,添加了一些我自己的粗浅理解
FFT(快速傅里叶变换),我们使用这个变换是用于将一段复杂的信号分解,分解为几段不同的波形,以此直观的理解这一段信号
整合后的FFT
#include "main.h"
#include "fft.h"
#include "adc.h"
#include "tim.h"
#include "arm_math.h"
#include "arm_const_structs.h"
#include <stdio.h>
#define FFT_LENGTH 1024
__IO uint8_t AdcConvEnd = 0;
uint16_t adcBuff[FFT_LENGTH];
float fft_inputbuf[FFT_LENGTH * 2];
float fft_outputbuf[FFT_LENGTH];
void fft()
{
HAL_ADC_Start_IT(&hadc3); //开启ADC3中断
HAL_ADC_Start_DMA(&hadc3,(uint32_t*)adcBuff,FFT_LENGTH);//开启DMA数模转换
HAL_TIM_Base_Start(&htim3); //开启TIM3定时器
while(!AdcConvEnd); //等待转换完毕
for (int i = 0; i < FFT_LENGTH; i++)
{
fft_inputbuf[i * 2] = adcBuff[i] * 3.3 / 4096;//实部赋值,* 3.3 / 4096是为了将ADC采 集到的值转换成实际电压
fft_inputbuf[i * 2 + 1] = 0;//虚部赋值,固定为0.
}
/*
arm_cfft_f32是ARM CMSIS-DSP库中的一个函数,用于执行复数FFT变换。
arm_cfft_sR_f32_len1024 是一个预定义的FFT结构体,表示FFT的长度为1024。
fft_inputbuf 是输入的复数数据数组,存储了要进行FFT变换的数据。
0 表示不进行逆FFT变换(即进行正向FFT变换)。
1 表示对输入数据进行位反转(bit reversal),这是FFT算法的一部分。
*/
arm_cfft_f32(&arm_cfft_sR_f32_len1024, fft_inputbuf, 0, 1);
/*
arm_cmplx_mag_f32 是ARM CMSIS-DSP库中的一个函数,用于计算复数的幅度(即模)。
fft_inputbuf 是输入的复数数据数组,存储了FFT变换后的结果。
fft_outputbuf 是输出的幅度数组,存储了每个频率分量的幅度值。
FFT_LENGTH 是FFT的长度,即1024。
*/
arm_cmplx_mag_f32(fft_inputbuf, fft_outputbuf, FFT_LENGTH);
/*这里,fft_outputbuf[0]存储的是直流分量(即频率为0的分量)。
由于FFT的输出结果是复数,直流分量的幅度需要除以1024(即FFT的长度)来得到实际的幅度值。*/
fft_outputbuf[0] /= 1024;
/*对于其他频率分量(即非直流分量),幅度需要除以512(即FFT长度的一半)来得到实际的幅度值。
这是因为FFT的输出是对称的,且每个频率分量的幅度是实际幅度的两倍。*/
for (int i = 1; i < FFT_LENGTH; i++)//输出各次谐波幅值
{
fft_outputbuf[i] /= 512;
}
printf("FFT Result:\r\n");
for (int i = 0; i < FFT_LENGTH; i++)//输出各次谐波幅值
{
printf("%d:\t%.2f\r\n", i, fft_outputbuf[i]);
}
}
在配置过程中cubemx可能会出现DSP库配置出错的情况
FFT.c(29): error: #20: identifier "arm_cfft_f32_len1024" is undefined
这里也有解决方法
第二步一定要添加",ARM_MATH_CM4",这里前面一定要添加英文的“,”,如果是F1系列改为“M3”的尾缀,是H7是“M7”
第三步添加路径
D:\keil5\stm32\DMA+ADC+TIM_FFT\Drivers\CMSIS\DSP\Include
也就是在这个路径下添加