打印
[STM32F4]

STM32F4 hal库 ADC + DMA + DSP + FFT 实现920K波形频率的采集

[复制链接]
435|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-7-20 13:56 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
DSP, DMA, DM, ADC, AD
使用开发板:立创开发板·天空星STM32F407

要实现920K波形频率的采集,使用定时器触发adc采集才能使adc采集频率可调,废话不多说接下来先进行cubemx的配置教程。

1、选择开发板



2、系统配置





3、时钟配置(重要)

(1)一定要使用外部晶振通道才能确保时钟的准确。

(2) 总线时钟配置成144MHz,因为stm32f407的adc采样率最高可以达到2.4M的速率,此时APB2总线经过2分频达到72MHz,ADC在经过2分频后,就可以达到ADC规定的最高时钟频率36MHz,adc的采样率计算公式:采样率 = ADC时钟频率 / (采样周期 + 12) 。这里选择3个Cycles,此时adc采样率就是最高的2.4M。




4、TIM配置

(1)使用定时器3,定时器3的时钟总线是APB1 72MHz,Trigger Event Selection选update Event,分频系数3,装载值13,此时定时器的频率为1846153Hz,不要开启定时器中断。频率太快了,开了会导致程序会死在中断。计数器的时钟频率 f  = TimeClockFren /((Prescaler + 1) * (Period + 1) );



5、ADC配置

(1)选一个adc通道,开启DMA,正常模式

如果选择循环模式,频率太高会导致程序死在dma中断中。





选择3Cycles,使adc采样达到2.4M

6、开启串口



7、生成工程(新手)






到此我们的工程就已经建好了。接下来进行代码的编写。

1、串口重定向

#include "stdio.h"
#ifdef __GNUC__
     #define PUTCHAR_PROTOTYPE int _io_putchar(int ch)
#else
     #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__*/

/******************************************************************
     *@brief  Retargets the C library printf  function to the USART.
     *@param  None
     *@retval None
******************************************************************/
PUTCHAR_PROTOTYPE
{
     HAL_UART_Transmit(&huart1, (uint8_t *)&ch,1,0xFFFF);
     return ch;
}

2、添加DSP库

参考链接:https://blog.csdn.net/qq_34022877/article/details/117855263

3、傅里叶变换

(1)定义相关数组及宏定义

#include "stdio.h"
#include "arm_math.h"
#include "arm_const_structs.h"

#define adc_SIZE 2048*2// ADC 采样大小的定义
uint32_t adcConvertValue[adc_SIZE]={0};// 存放 ADC 采样数据的数组
uint8_t flag=0;// 标记位,用于标识 ADC 采样是否完成

float32_t frequency ;// 用于存放计算结果的频率变量
// FFT 相关参数的定义
#define FFT_SIZE 2048
#define FFT_LEN FFT_SIZE
#define SAMPLING_FREQUENCY 1846153.84615f //adc采样频率
float32_t inputSignal[FFT_SIZE*2];// FFT 输入信号数组
float32_t fftOutput[FFT_SIZE/2];// FFT 输出数组
uint32_t index_;// 存放 FFT 输出中最大值的索引

(2)创建一个fft的计算函数

void fftCalculate(void)// FFT 计算函数
{
    arm_cfft_f32(&arm_cfft_sR_f32_len2048, inputSignal, 0, 1);// 执行 FFT 计算
    arm_cmplx_mag_f32(inputSignal, fftOutput, FFT_LEN/2);// 计算 FFT 输出的幅度
    index_ = 0;// 查找 FFT 输出中的最大值
    float32_t maxValue = fftOutput[1];
//    for (uint32_t i = 1; i < FFT_LEN/2; i++)
//    {
//        if (fftOutput > maxValue)
//        {
//            maxValue = fftOutput;
//            index = i;
//        }
//    }
                arm_max_f32(&fftOutput[1], FFT_LEN/2, &maxValue, &index_); // 使用 arm_max_f32 函数快速找到 FFT 输出中的最大值及其索引
    frequency = (float32_t)index_ * (float32_t)SAMPLING_FREQUENCY / (float32_t)FFT_SIZE;// 根据最大值的索引计算信号的频率

}

(3)在while中添加代码

                printf("frequency is:%f\n",frequency);
                if(flag==1)
                {
                        flag=0;
                       
                        for(int j=0;j<FFT_SIZE;j++)//采样数据转换
                        {
                                inputSignal[j*2]=(adcConvertValue[j])*3.3f/4096.0f;//12位采样数字值对应为0-3.3伏
                                inputSignal[j*2+1]=0;//交替插零,添加数据的虚部
                        }

                        fftCalculate();
                        HAL_TIM_Base_Start(&htim3);        //重新启动定时器3
                        HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adcConvertValue,adc_SIZE);//重新开始下一轮采集
                       
                }               

(4)在DMA中断中停止定时器和DMA,中断函数在stm32f4xx_it.c文件中。

extern uint8_t flag;
extern TIM_HandleTypeDef htim3;
extern ADC_HandleTypeDef hadc1;
void DMA2_Stream0_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream0_IRQn 0 */

  /* USER CODE END DMA2_Stream0_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_adc1);
  /* USER CODE BEGIN DMA2_Stream0_IRQn 1 */
        HAL_TIM_Base_Stop(&htim3);//定时器3停止
        HAL_ADC_Stop_DMA(&hadc1);//停止ADC的DMA传输
        flag=1;//标志位置1,表示本次采样结束
  /* USER CODE END DMA2_Stream0_IRQn 1 */
}
(5)开启定时器和DMA

HAL_TIM_Base_Start(&htim3);//启动定时器3
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adcConvertValue,adc_SIZE);//启动ADC的DMA传输
DMA中断一次说明adc转换完成一次,此时把标志flag值赋值1,那么在while中把adc采集值赋值给傅里叶变换数组后,进行fft的计算,从而得出所测波形的频率。根据抽样定理我们可以知道,采样率要是最高频率的两倍,所以理论上要测1MHz频率时,adc的采样率要设置成2MHz。参考文章:https://blog.csdn.net/qq_5995380 ... 1001.2014.3001.5506

傅里叶参考:https://blog.csdn.net/qq_3402287 ... 1001.2014.3001.5502

附上效果图





————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_65209277/article/details/140467911

使用特权

评论回复
沙发
Aist2018| | 2024-7-20 14:17 | 只看该作者
请把CUBEMX里关联ADC和TIM3的页面图放出,我看看你ADC时钟选择画面

使用特权

评论回复
板凳
Aist2018| | 2024-7-20 14:26 | 只看该作者
请帮忙看看我的情况,我是用STM32L431RCT6  定时器2中断发起ADC 采样, 发现HAL_ADC_STATE_REG_EOC自己固定频率置位,和我定时器2设置的频率无关,注意到ADC自己有自己的时钟,我再stm32cubeMX里想设置成定时器2控制采样频率,结果系统不工作了。现在问题是看我发的CUBEMX时钟配置图,ADC有自己时钟,我在CUBEMX里找不到TIME2的总线APB2时钟,只有一个异步时钟和同步时钟两个选项。我无法关联TIME2和ADC时钟。你看我发的CUBEMX配置图里哪有PLCCLK时钟2选项,只有异步或者同步时钟选项,怎么关联ADC和时钟2啊?






使用特权

评论回复
地板
4c1l| | 2024-7-27 11:13 | 只看该作者
转到“Pinout & Configuration”标签页,选择一个可用的定时器(例如TIM1、TIM2等)。

使用特权

评论回复
5
4c1l| | 2024-7-27 11:14 | 只看该作者
使用 STM32F407 开发板配置 CubeMX 以实现 920kHz 的 ADC 采样频率需要详细配置系统时钟和定时器。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1724

主题

15099

帖子

10

粉丝