选择DMA循环采集DMA_CIRCULAR
uint16_t ADCRes[ADC_DMA_BUF_SIZE]; //变量易变,编译器不能随便优化
#define ADC_Ech_Channel 3
#define ADC_DMA_BUF_SIZE 10 * ADC_Ech_Channel/* ADC DMA采集 BUF大小, 应等于ADC通道数的整数倍 */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADCRes, ADC_DMA_BUF_SIZE*2);
循环采集不需要打开下面停止重启DMA采集的注释
void DMA1_Channel1_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
// HAL_GPIO_TogglePin(GPIOB,LED_RED_Pin);
adc_dma_ok = 1; /* 标记DMA传输完成 */
// HAL_ADC_Stop_DMA(&hadc1);
/* USER CODE END DMA1_Channel1_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_adc1);
/* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
// HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADCRes, ADC_DMA_BUF_SIZE*2);
/* USER CODE END DMA1_Channel1_IRQn 1 */
}
选择定时器触发
使用串口绘制实时曲线 —— SerialChart – QIYUEXIN – 博客园
https://www.cnblogs.com/qiyuexin/p/7067646.html
(388条消息) 串口波形显示软件SerialChart的使用_天外飞仙CUG的博客-CSDN博客
https://blog.csdn.net/zhang062061/article/details/114109581
(387条消息)
STM32_如何添加DSP库
_stm32 dsp_江湖上都叫我秋博的博客-CSDN博客
https://blog.csdn.net/heqiunong/article/details/124346055
生成项目后,我们需要的DSP库已经包含到STM32CubeMX生成的项目文件夹中了
路径: 项目路径/Drivers/CMSIS/DSP
打开项目后,需要更改三个位置
-
把arm_cortexM4lf_math.lib包含到项目中
-
把arm_cortexM3l_math.lib包含到项目中
添加一个预定义 ” ,ARM_MATH_CM4
3、添加包含路径 Include Paths。” 项目路径/Drivers/CMSIS/DSP/Include ”
测试代码
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "arm_math.h" // 包含一个arm_math.h
/* USER CODE END Includes */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
float data; // 定义一个全局变量
/* USER CODE END 0 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
data = arm_sin_f32(3.1415926/6); // 用DSP库里面的函数arm_sin_f32计算 sin(Π/6)
}
/* USER CODE END 3 */
测试结果
方法2:(388条消息)
STM32CubeMX关于添加DSP库的使用
_W_oilpicture的博客-CSDN博客
https://blog.csdn.net/WandZ123/article/details/125593908
(387条消息) 音乐频谱显示小玩具——FFT在STM32中的实现与应用_max4466电路图_To丶紫罗兰的博客-CSDN博客
(
https://www.likecs.com/show-203853067.html
)
(387条消息) stm32f1单片机上用FFT测量信号频率(高精度、过程详细)_stm32 fft_Mr Justin的博客-CSDN博客
void DMA1_Channel1_IRQHandler(void)
{
u16 i = 0;
DMA_Cmd(DMA1_Channel1, DISABLE);
DMA_ClearITPendingBit(DMA_IT_HT);
DMA_ClearITPendingBit(DMA1_IT_TC1); //清除中断标志位
for(i=0;i<NPT;i++)
InBufArray[i] = ((signed short)(ADC_Value[i])) << 16; //左移16位,高16位存放实部
cr4_fft_1024_stm32(OutBufArray, InBufArray, NPT);
GetPowerMag(); //获取信号谐波分量的幅值
DMA_Cmd(DMA1_Channel1, ENABLE);
}
(387条消息) 基于STM32的FFT频谱分析+波形识别_stm32fft频谱分析__鑫鑫鑫_的博客-CSDN博客
基于HAL库的STM32的DSP库详解(附FFT应用) – 廖伟伟 – 博客园
https://www.cnblogs.com/lwwBKY/p/14063829.html
如果查看DSP库的各个函数的原型,可以添加源码库文件, 则当前工程目录下的Drivers\CMSIS\DSP_Lib\Source目录可以查看,当然安装目录下也有该库源文件。
BasicMathFunctions
基本数学函数:提供浮点数的各种基本运算函数,如向量加减乘除等运算。
CommonTables
arm_common_tables.c文件提供位翻转或相关参数表。
ComplexMathFunctions
复杂数学功能,如向量处理,求模运算的。
ControllerFunctions
控制功能函数。包括正弦余弦,PID电机控制,矢量Clarke变换,矢量Clarke逆变换等。
FastMathFunctions
快速数学功能函数。提供了一种快速的近似正弦,余弦和平方根等相比CMSIS计算库要快的数学函数。
FilteringFunctions
滤波函数功能,主要为FIR和LMS(最小均方根)等滤波函数。
MatrixFunctions
矩阵处理函数。包括矩阵加法、矩阵初始化、矩阵反、矩阵乘法、矩阵规模、矩阵减法、矩阵转置等函数。
StatisticsFunctions
统计功能函数。如求平均值、最大值、最小值、计算均方根RMS、计算方差/标准差等。
SupportFunctions
支持功能函数,如数据拷贝,Q格式和浮点格式相互转换,Q任意格式相互转换。
TransformFunctions
变换功能。包括复数FFT(CFFT)/复数FFT逆运算(CIFFT)、实数FFT(RFFT)/实数FFT逆运算(RIFFT)、和DCT(离散余弦变换)和配套的初始化函数。
相关函数说明以及示例也可在安装路径Keil_v5\ARM\PACK\ARM\CMSIS\4.5.0\CMSIS\Documentation\DSP\html下获得,自行查阅。
(387条消息) STM32F103如何实现 FFT?_wenzi嵌入式软件的博客-CSDN博客
FFT 变换之后和原始信号的对应关系
假设我们对一个波形进行了采样,采样了 N 个点,经过 FFT 之后,就可以得到 N 个点的 FFT 结果,每一个点就对应着一个频率点。这个点的模值,就是该频率下的幅度特性。具体的关系就是如果原始信号的峰值为 A ,那么 FFT 的结果的每个点的模值就是 A 的 N / 2 倍。而第一个点就是直流分量,它的模值是直流分量的 N 倍。而每个点的相位就是在该频率下的信号的相位,第一个点表示的是直流分量,也就是 0 HZ的点,而最后一个点 N 的再下一个点(实际这个点是不存在的),也就是 N+1 个点则表示的是采样频率 Fs,这中间被 N – 1 个点平均分成 N 等份,每一个点的频率依次增加。也就是如果要计算某个点的频率,那么就只需要这样计算即可:Fn = (n – 1) * Fs / N。
从上述所展示的公式,我们可以知道 Fn 所能够分辨的频率为 Fs / N,如果采样频率 Fs 为 1024Hz,采样点数为 1024 点,则可以分辨到 1 HZ。也就是说采样 1s 时间的信号并做 FFT ,则结果可以分析精确到 1 Hz,如果采样 2 s 时间的信号并做 FFT,则结果可以分析精确到 0.5 Hz,所以也就说明了一个道理,如果要提高频率分辨率,则必须增加采样点数,也就是采样时间,下面这张图更能够清晰地表示这种关系:
将原信号变换之后的频谱的宽度与原始信号也存在一定的关系。根据 Nyquist采样定律,FFT 之后的频谱宽度最大只能是原始信号采样率的 1/2,如果原始信号的采样频率为 4GS/s,那么 FFT 之后的频宽最多只能是 2GHz,这还只是理想情况。所以也能够得出一个结论:时域信号的采样率乘上一个固定系数即是变换之后频谱的宽度,可以用如下所示的一张图清晰说明:
经过上述的分析,我们有了如下的结论:
更高的频谱分辨率需要有更长的采样时间,更宽的频谱分布需要提高对于原始信号的采样率,那我们在实际的使用过程中,当然是希望频谱更宽,分辨率更加精确,那么示波器的长存储就是必要的。
(387条消息) STM32CubeMX配置ADC采样(轮询、中断、DMA)_Sense_long的博客-CSDN博客
void DMA1_Channel1_IRQHandler(void)
{
g_adc_dma_sta = 1; /* 标记DMA传输完成 */
HAL_ADC_Stop_DMA(&hadc1);
for (int i = 0; i < (ADC_DMA_BUF_SIZE - 1) ; i++) /* 每个通道采集了10次数据,进行10次累加 */
{
temp = (float)g_adc_dma_buf[i] * (3.3 / 4096);
printf("%d %x %fV \r\n",i,g_adc_dma_buf[i],temp);
}
/* USER CODE END DMA1_Channel1_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_adc1);
/* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&g_adc_dma_buf, ADC_DMA_BUF_SIZE);
}
#define ADC_Ech_Channel 5
#define ADC_DMA_BUF_SIZE 10 * ADC_Ech_Channel /* ADC DMA采集 BUF大小, 应等于ADC通道数的整数倍 */
extern uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE];
int main(void)
{
MX_DMA_Init();
MX_ADC1_Init();
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&g_adc_dma_buf, ADC_DMA_BUF_SIZE);
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (g_adc_dma_sta == 1)
{
temp = (float)g_adc_dma_buf[i] * (3.3 / 4096);
printf(" %x %f V \r\n",g_adc_dma_buf[i],temp);
}
}
}
stm32f103+FFT+OLED的音乐频谱制作(干货 只需三步即可) | 小蜜蜂
https://www.lmlphp.com/user/56/article/item/9127/
ZLG_GUI方便绘图 不用GUI也可以 看自己需求