08 FFT实验
up的视频讲解配置 ADC 与 DMA 采样,导入 FFT 驱动,并用 SerialPie 观察实验输出。
up视频里的实验代码: 👣FFT实验代码
FFT驱动代码: FFT驱动代码
整个ARM-DSP库的详细说明,大家可以参考这里ARM-DSP
1 🔌 硬件连接(复用)

2 🖥️ 软件操作
本节通用的 CubeMX 配置使用与 FIR 操作页相同的截图,工程命名与 FFT 驱动导入使用本节截图。依次完成以下步骤。
1 CubeMX配置
新建工程与选择芯片
打开 STM32CubeMX,点击 File → New Project,搜索 STM32F103C8T6,双击对应芯片创建工程。


配置下载接口与时钟
在 System Core → SYS 中,将 Debug 设置为 Serial Wire。再进入 RCC,将 HSE 设置为 Crystal/Ceramic Resonator。


进入 Clock Configuration,按图将主频设置为 72 MHz。若出现时钟求解提示,按图确认,再核对调整后的主频与 ADC 时钟配置。

配置ADC
打开 Analog → ADC1,勾选 IN1(PA1),按图将规则组的外部触发源选择为 Timer 3 Trigger Out event。



展开 Rank,将通道 1 的 Sampling Time 设置为 7.5 Cycles。

配置DMA
进入 DMA Settings,点击 Add 并选择 ADC1,添加 ADC 的 DMA 请求。

配置TIM3触发
打开 Timers → TIM3,启用 Internal Clock。在参数页中,将 Prescaler 设置为 72 - 1,Counter Period 设置为 200 - 1。


在 Trigger Output (TRGO) Parameters 中,将 Trigger Event Selection 设置为 Update Event,用于触发 ADC 采样。

配置串口
打开 Connectivity → USART1,将模式设置为 Asynchronous。

生成工程
进入 Project Manager,将工程名设置为 FFT_TEST,填写保存位置,工具链选择 MDK-ARM。

在 Code Generator 中,按图选择只复制需要的库文件,并勾选为每个外设生成独立的 .c/.h 文件。

点击 GENERATE CODE,生成完成后点击 Open Project,进入 MDK。

2 MDK配置
下载并放入FFT驱动
从本页的 FFT 驱动下载入口获取压缩包,解压后把完整的 FFT 驱动文件夹放入工程目录,与 Core、Drivers、MDK-ARM 文件夹同级。


添加头文件路径
打开 Options for Target → C/C++,点击 Include Paths 右侧的按钮,新建一项并选择工程中的 FFT 驱动文件夹。

添加宏定义
在同一页的 Define 中,保留原有宏定义,在末尾用英文逗号分隔并追加 ARM_MATH_CM3,然后确认保存。

添加驱动文件与库文件
打开工程文件管理窗口,新建 FFT 分组,点击 Add Files 并进入 FFT 驱动目录。

将文件类型切换为 All files (*.*),按图选中驱动目录中的全部文件,点击 Add,再关闭窗口并确认。

设置MicroLIB
进入 Options for Target → Target,按视频工程配置勾选 Use MicroLIB,然后确认保存。

3 实验代码
全局
#include <stdio.h>
#include "fft.h"
#define FFT_LEN 256
uint16_t adc_dma_buf[FFT_LEN];
q15_t fft_out[FFT_LEN/2];
float fft_vpeak[FFT_LEN/2];
float fft_vrms[FFT_LEN/2];
//DMA搬运完指定ADC数据中断
volatile uint8_t flag = 0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
flag = 1;
}
// printf输出重定向
int fputc(int ch, FILE *f)
{
uint8_t temp = ch;
HAL_UART_Transmit(&huart1, &temp, 1, 100);
return ch;
}
main()
HAL_ADCEx_Calibration_Start(&hadc1);//ADC校正
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)adc_dma_buf,FFT_LEN);//开启DMA
HAL_TIM_Base_Start(&htim3);//开启定时器
while(1)
if(flag)
{
FFT(adc_dma_buf,fft_out,FFT_LEN);
FFT_Vpeak(fft_out,fft_vpeak,FFT_LEN);//将FFT后的值转化为电压(峰值)
FFT_Vrms(fft_out,fft_vrms,FFT_LEN);//将FFT后的值转化为电压(有效值)
for(int i=0; i<FFT_LEN/2; i++)
{
printf("%f\r\n",fft_vrms[i]);
}
flag = 0;
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)adc_dma_buf,FFT_LEN);//重新打开DMA
}
3 ♒️ 实验效果
下面分别展示使用 SerialPie 进行频谱分析,以及在 STM32 内部完成 FFT 后发送结果的效果。连接开发板对应的串口时,保持 SerialPie 的串口参数与工程配置一致。
1 ADC采样数据发送到SerialPie进行频谱分析
STM32 将 ADC 采样后的数据通过串口发送到 SerialPie,由 SerialPie 进行频谱分析。切换到“频谱”页面,按图设置参数,查看频谱图像。

2 STM32内部FFT后发送到SerialPie显示
STM32 在内部完成 FFT 运算,再将处理后的结果通过串口发送到 SerialPie。上面的实验代码对应这一种方式,发送的是 fft_vrms 数组中的数据。
切换到 SerialPie 的“波形”页面,将显示模式设置为“刷新模式”,批次识别选择“自动时间识别”,查看 STM32 发来的 FFT 结果。
