【STM32 系列】EXTI11触发三ADC同步(并非同步)采样 —— 超精准设置采样率

引言

前段时间测试 fft 计算频率的准确性时,发现用定时器触发 ADC 采样所设置的采样率在某些频率上十分的不准确,并且会产生非常严重的频谱泄露问题(具体可以看上一篇文章:频谱泄露原因)。
下面是我封装的一个设置定时器频率的函数:

点击查看代码
#include "set_samplingrate.h"

/**
 * @brief 根据输入参数设置定时器以调整采样率
 * 
 * 此函数依据给定的定时器时钟频率和期望的采样率,计算并设置定时器的自动重载寄存器值,
 * 从而间接控制采样达到期望采样率。
 * 
 * @param timerHandle 定时器句柄。
 * @param Timer_ClockFreq 定时器的时钟频率。
 * @param SamplingRate 期望的采样率。
 * @return 返回期望设置的采样率。
 * 
 * @note 函数依赖定时器句柄已正确初始化,且相关硬件寄存器和库函数正常工作。
 */
float32_t Set_SamplingRate(TIM_HandleTypeDef* htim, float32_t Timer_ClockFreq, float32_t SamplingRate) 
{
    // 声明变量用于存储定时器经过预分频后的频率
    float32_t Timer_After_PSC_Freq;
    Timer_After_PSC_Freq = Timer_ClockFreq / (float32_t)(htim->Init.Prescaler + 1);
    // 计算并设置定时器的自动重载寄存器值,来调整ARR以达到期望采样率
    __HAL_TIM_SET_AUTORELOAD(htim, (Timer_After_PSC_Freq / SamplingRate) - 1);

    return SamplingRate;
}
点击查看代码
#ifndef __SET_SAMPLINGRATE_H
#define __SET_SAMPLINGRATE_H

#include "main.h"

extern float32_t Set_SamplingRate(TIM_HandleTypeDef* htim, float32_t Timer_ClockFreq, float32_t SamplingRate);

#endif

定时器触发误差来源

例如,博主使用的 H743 的 TIM3 的频率为200MHz,经过2分频后得到100MHz,在通过以上函数设置640kHz采样率,那么 CNT 的值就需要是156.25,但 CNT 的值只能是整形的156,那么最终得出的采样率值为$ \frac{100MHz}{156}=641025.64Hz $,这个看似微小的差异,其实可以造成极大的误差,此时就可以很清晰的看到频谱泄露带来的误差影响,甚至加窗后也解决不了:
实际频率7500Hz,计算得7500Hz
实际频率8125Hz,计算得7500Hz

EXTI11外部触发ADC采样

CubeMX配置

ADC1、2、3都是如此配置,假如你是H7系列的话,还需要注意时钟分频的问题,具体看这篇文章:H7时钟频率设置ADC

EXTI11测试结果

测试方式:使用信号发生器发生方波/脉冲给到 EXTI11 引脚,设置的方波/脉冲的频率就是采样率

1.使用640ksps采样率采样1024个点,采样5k倍数的正弦波/方波/三角波...加窗后并进行1024个点的 fft 运算

  • 采样5kHz正弦波:

  • 采样100kHz方波:

2.使用32768sps采样率采样32768个点,采样任意频率的正弦波/方波/三角波...加窗后并进行32768个点的 fft 运算

  • 采样4137Hz方波:

  • 采样10109Hz正弦波:

可以看到,使用外部 EXTI 触发设置的采样率,计算的频率非常的准确,加窗后更是无敌,十分推荐使用。

隐藏问题

使用定时器可以同步触发三个 ADC 同时采样,在使用三个 ADC 同时采样一个信号的时候,算得的相位差的误差是相当的小,误差只有0.1%;但是使用 EXTI 触发采样时,三个ADC并不是同时触发的,使得就算采样同一个信号,算得的相位差误差也会较大,就是由于这个特性引起的,目前还没办法解决。也是各有所长,按需使用吧。

博客导航

博客导航

posted @ 2025-03-20 20:04  膝盖中箭卫兵  阅读(239)  评论(0)    收藏  举报
ORCID iD icon https://orcid.org/0000-0001-5102-772X