STM32F4单片机ADC采样及ARM-DSP库的FFT

2023-11-18

模拟信号经过ADC采样后变成数字信号,数字信号可以进行FFT运算,在频域中更容易分析信号的特征。本文将介绍如何用STM32F4的进行ADC采样,并利用ARMDSP库里的FFT算法对ADC采样值进行快速傅里叶变换。

我使用的是STM32F407VG单片机,由于需要的ADC采样值较多(采集了4096个点),所以配置了STM32的ADC和DMA,使用DMA将ADC采样值传输到内存效率更高。配置外设时,使用APB2时钟的2分频作为ADCCLK,ADC采样时间为84个ADCCLK,Tconv(总转换时间) = 采样时间+12个ADCCLK,理论上ADC的采样频率约4,375,00Hz。为了保证信号的完整性,由奈奎斯特定理知采样频率需要大于信号中最高频率的2倍,因此该外设配置方法测量的信号频率不应大于218,750Hz。外设配置代码如下:

GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure; 
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef  NVIC_InitStructure;	

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2|RCC_AHB1Periph_GPIOC,ENABLE);	
while(DMA_GetCmdStatus(DMA2_Stream0)!=DISABLE);				
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 	
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);  	
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE); 	
//init GPIO ADC1, channel 14
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;	
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;					
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;			
GPIO_Init(GPIOC, &GPIO_InitStructure);
	
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&(ADC1->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned int)&(fft.ADC_ConvertedValue[0]);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 4096;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0,&DMA_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

DMA_ClearFlag(DMA2_Stream0,DMA_IT_TC);
DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE);//使能数据流传输完成中断
DMA_Cmd(DMA2_Stream0,ENABLE);

ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;//84M/2 = 42M
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
	
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1,&ADC_InitStructure);
ADC_Cmd(ADC1,ENABLE);
	
ADC_RegularChannelConfig(ADC1,ADC_Channel_14,1,ADC_SampleTime_84Cycles);//转换时间84个ADC周期
 
ADC_SoftwareStartConv(ADC1);
ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);
ADC_DMACmd(ADC1,ENABLE);

接下来,将ADC的采样值转换为对应的电压值,利用DSP库的FFT算法进行FFT运算,计算幅频特性。这里,我使用的是基4浮点FFT算法,基4的算法比基2的算法运算速度更快。代码如下:

#define FFT_LENGTH 4096
void FFTTestTask(void *arg)
{
    OS_ERR err;
    CPU_TS ts;
    arm_cfft_radix4_instance_f32 scfft;
    int i = 0;
    unsigned char str[10];
	
    arm_cfft_radix4_init_f32(&scfft,FFT_LENGTH,0,1);//FFT初始化
    while(1)
    {
        OSTaskSemPend(0,OS_OPT_PEND_BLOCKING,&ts,&err);//等待传输完成信号量
	for(i=0;i<FFT_LENGTH;i++)
	{
    	    fft.fft_input[2*i] = (float)fft.ADC_ConvertedValue[i]*3.3f/4096.0f;//实部为ADC采样值
	    fft.fft_input[2*i+1] = 0;//虚部为0
	}		
	arm_cfft_radix4_f32(&scfft,fft.fft_input);//FFT运算
	arm_cmplx_mag_f32(fft.fft_input,fft.fft_output,FFT_LENGTH);//计算每个点的模值
	for(i=0;i<FFT_LENGTH;i++)
	{
            sprintf((char*)str,"%.2f\r\n",fft.fft_output[i]);
	    board.UART4Send(str,strlen((char*)str));//将数据打印至串口助手,便于观察
	    OSTimeDly(1,OS_OPT_TIME_DLY,&err);
	}
	OSTimeDly(500,OS_OPT_TIME_DLY,&err);
	board.ADC1_DMA2Enable();//重新启动ADC转换和DMA传输
    }
}

实验中,我用FPGA和DAC做了DDS信号发生器,生成波形函数为f= 1.65+1.65\cdot cos(2\cdot \pi \cdot 1937\cdot t)。用上述方法采集电压信号进行FFT运算,最后使用MATLAB绘制了部分幅频特性曲线。直流分量的理论幅值为6758.4,实际值7168.2;基波分量的理论幅值为3379.2,实际值3454.3。

不足之处请大佬指正。

代码下载: STM32F4 ADC采样FFT运算测试代码

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32F4单片机ADC采样及ARM-DSP库的FFT 的相关文章

  • STM32 Nucleo 上的上升沿中断多次触发

    我正在使用 STM32 NUCLEO F401RE 微控制器板 我有一个扬声器 经过编程 当向上 向下推操纵杆时 可以按设定的量改变频率 我的问题是 有时 通常 当向上 向下推动操纵杆时 频率会增加 减少多次 这意味着 ISR 正在执行多次
  • fftw c2c:转换后的真实数据中缺少对称性

    最近我遇到了一些关于fftw的使用及其c2c转换的问题 参见 3d c2c fft 与 fftw 库 https stackoverflow com questions 10374656 3d c2c fft with fftw libra
  • 如何获得定义频带内的所有 fft bin 数量?

    我用的是matlab软件 对于我的问题 我有一个音频信号 我正在其上应用 STFT 我取一段 46 ms specifially chosen 我的信号消失了y audio signal 并使用FFT在上面 然后我进入下一段 直到音频信号结
  • 如何使用python将一幅图像的相位和不同图像的幅度组合成一幅图像

    我想将一幅图像的相位谱和不同图像的幅度谱组合成一幅图像 我得到了图像A和图像B的相位谱和幅度谱 这是代码 f np fft fft2 grayA fshift1 np fft fftshift f phase spectrumA np an
  • 使用 fft 查找每个谐波的相位

    我用的是Matlab 我有一个正弦信号 X 放大器 220 频率 50 我添加了 3 个谐波 x1 gt h2 放大器 30 频率 100 相位 30 x2 gt h4 放大器 10 频率 200 相位 50 x3 gt h6 放大器 05
  • 在 Android 上查找音调

    如何从我的语音记录中找到最小 最大 平均 标准偏差音调 我使用 AudioRecord 来录制我的声音 frequency 8000 channelConfiguration AudioFormat CHANNEL CONFIGURATIO
  • DSP——获取所有频率的幅度

    这个问题与 DSP 音频处理 squart还是log来利用fft https stackoverflow com questions 20057831 dsp audio processing squart or log to levera
  • fft 和小波

    我可以使用 fft 获取加载的 1 秒音频文件的频率 相位和幅度 并重新创建它 我现在想做的是找出每个频率在 1 秒音频文件中的开始位置和结束位置 并将数据放入数组中 示例 100hz 从 0 23 秒到 0 34 秒开始 104 34hz
  • FFT 的窗口大小与数据长度

    我正在尝试对流音频数据进行快速频谱分析以捕获元音 类似于 JLip sync 使用 PyAudio 在短时间内 0 0625 秒 捕获小块 1024 的语音数据 使用 numpy fft 进行分析 并使用 numpy hanning 窗口消
  • 当端点和 PMA 地址均更改时,CubeMX 生成的 USB HID 设备发送错误数据

    我正在调试我正在创建的复合设备的问题 并在新生成的仅 CubeMX 代码中重新创建了该问题 以使其更容易解决 我添加了少量代码main 让我发送 USB HID 鼠标点击 并在按下蓝色按钮时使 LED 闪烁 uint8 t click re
  • 这个小波变换实现正确吗?

    我正在寻找 FFT 的替代方案来用 python 创建频谱分析仪 我听说小波变换比短时 FFT 更快并且提供更好的时间精度 我查阅了这篇维基百科文章 其中介绍了 Java 中的 Haar 小波变换实现 https en wikipedia
  • NumPy 中 exp(-x^2) 的快速傅立叶变换

    I have to calculate numerically the 2nd derivative of a Gaussian function I ve read every question on this topic here bu
  • 如何使用Matlab提高PSD的分辨率

    我有音频信号 我用 Matlab 读取该信号 并使用 pwelch 获取其 PSD 这是我正在使用的代码 x Fs audioread audioFile wav x x 1 mono xPSD f pwelch x hamming 512
  • 傅里叶变换定理 matlab

    我目前正在尝试理解二维傅里叶位移定理 根据我到目前为止所了解到的情况 图像空间中的平移会导致相位差异 但不会导致频率空间中的幅度差异 我试图用一个小例子来演示这一点 但它只适用于行的移位 而不适用于列的移位 这是一个小演示 我只在这里显示幅
  • 通过傅里叶空间填充进行插值

    我最近尝试在 matlab 上实现一个在傅立叶域中使用零填充的插值方法的简单示例 但我无法正常工作 我总是有一个小的频移 在傅里叶空间中几乎不可见 但它在时空上产生了巨大的误差 由于傅里叶空间中的零填充似乎是一种常见 且快速 的插值方法 因
  • 频域和空间域的汉明滤波器

    我想通过在 MATLAB 中应用汉明滤波器来消除一维信号中的吉布斯伪影 我所拥有的是k1这是频域中的信号 我可以通过应用 DFT 来获取时域信号k1 s1 ifft ifftshift k1 该信号具有吉布斯伪影 现在 我想通过 A 乘以汉
  • 在音频文件中查找音频样本(频谱图已存在)

    我正在努力实现以下目标 使用 Skype 拨打我的邮箱 有效 输入密码并告诉邮箱我要录制新的欢迎信息 有效 现在 我的邮箱告诉我在嘟嘟声后录制新的欢迎消息 我想等待蜂鸣声然后播放新消息 不起作用 我如何尝试实现最后一点 使用 FFT 和滑动
  • 提高 Python 中的 FFT 性能

    Python 中最快的 FFT 实现是什么 看来 numpy fft 和 scipy fftpack 都基于 fftpack 而不是 FFTW fftpack 和 FFTW 一样快吗 使用多线程 FFT 或分布式 MPI FFT 怎么样 您
  • 在 MATLAB 中使用 FFT 的频率响应

    这是场景 使用频谱分析仪 我有输入值和输出值 样本数是32000采样率为2000样本 秒 输入是正弦波50 hz 输入为电流 输出为压力 单位 psi 我如何使用 MATLAB 根据这些数据计算频率响应 使用 MATLAB 中的 FFT 函
  • GCC 变量映射和 MISRA-C

    我主要知道两种使用 GCC 声明内存映射寄存器的方法 有许多变体 使用双字段 每个外设的数据结构等 要么使用初始化为正确地址的指针 例如volatile uint32 t pMyRegister uint32 t 0xDEADBEEFUL

随机推荐

  • 访谈:小学学历的程序员自主研发出框架级产品

    提到许松森 也许你并不知道他是谁 在Google中敲入这个名字 能找到的结果也寥寥无几 那么做为我们这一期采访的主角 他究竟是用什么在吸引着我们呢 打开许松森的blog 开篇就是 我的悲惨人生 读在字里行间 对他在逆境中的自我成长很是敬佩
  • java关于数组的函数_Java关于数组操作函数

    数组排序及元素查找 sort 方法对Java数组进行排序 binarySearch 方法来查找数组中的元素 返回该元素所在的位置 import java util public classtest public static voidmai
  • 漏洞挖掘之乱拳打死老师傅——Fuzzer

    背景 Fuzzer是一种通过产生一系列非法的 非预期的或者随机的输入向量给目标程序 从而完成自动化的触发和挖掘目标程序中的安全漏洞的软件测试技术 相比于形式化的软件漏洞测试技术 比如 符号执行技术 Fuzzer往往能够在实际的应用中挖掘更多
  • 【编程之路】面试必刷TOP101:动态规划(67-71,Python实现)

    面试必刷TOP101 动态规划 67 71 Python实现 67 不同路径的数目 一 小试牛刀 67 1 递归 首先我们在左上角第一个格子的时候 有两种行走方式 如果向右走 相当于后面在一个 n 1
  • vue 如何实现多页面应用(简单版)

    1 进入 build webpack base conf js目录下 在module exports的域里 找到entry 在那里配置添加多个入口 2 对开发环境run dev里进行修改 打开 build webpack dev conf
  • Rancher 图形化管理K8S

    题外话 之前我们一直都是使用命令行来管理K8S的 这种做法虽然对程序员来说看起来很炫酷 但有时候用起来还是挺麻烦的 今天我们来介绍一个K8S可视化管理工具Rancher 使用它可以大大减少我们管理K8S的工作量 希望对大家有所帮助 简介 R
  • Spyder更改为python3.10解释器

    Spyder更改为python3 10解释器 因为系统安装的python版本为3 10 但是官网下载最新的Spyder内置python版本为3 7 9 强迫症一犯就想着更改成3 10 步骤如下 偏好里面更改控制台的运行方式 根据个人习惯设置
  • java高频面试题含答案(网络)

    java高频面试题含答案 网络 1 http 响应码 301 和 302 代表的是什么 有什么区别 答 301 302 都是HTTP状态的编码 都代表着某个URL发生了转移 区别 301 redirect 301 代表永久性转移 Perma
  • 膜拜,阿里架构师着重推荐的SprinBoot手册—进阶、原理、实战与面试题分析指南

    我们知道 Spring Boot是一个集成性的开源框架 内部整合了很多第三方组件和框架 这些组件和框架应用如此之广泛 以至于大家反而往往对如何更好地使用Spring Boot自身的功能特性并不是很重视 事实上 Spring Boot自身的功
  • [小技巧] git: Your branch and 'origin/master' have diverged

    本文参考 http stackoverflow com questions 19864934 git your branch and origin master have diverged how to throw away local c
  • mac os x excel 单元格换行

    参考 http jingyan baidu com article 0f5fb09911cb366d8334ea07 html Windows 下是 alt 回车 mac os x 下变成 alt ctrl 回车
  • Vue3通透教程【十四】TS其他类型详解(一)

    文章目录 写在前面 对象类型 函数结构类型 数组类型 元组 枚举 类型别名 写在最后 写在前面 专栏介绍 凉哥作为 Vue 的忠实 粉丝输出过大量的 Vue 文章 应粉丝要求开始更新 Vue3 的相关技术文章 Vue 框架目前的地位大家应该
  • 毕业设计 STM32的智能WIFI视频人脸追踪监控系统

    0 前言 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的毕设题目缺少创新和亮点 往往达不到毕业答辩的要求 这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求 为了大家能够顺利以及最少的精力通过毕设 学长分享优质毕业设计项
  • 函数内变量的提升(function hoisting)

    1 函数内外有重名的变量时 局部变量会覆盖全局变量 原因是函数域优先于全局域 2 当js执行进入函数时 函数内部声明过的所有变量会被提到最前 但同时对变量的赋值等操作不会被提升 例 var a 123 function test alert
  • 12帧跑步动画分解图_今天给大家分享一个跑步动画教程和注意事项!希望有所帮助!...

    跑步的动画的制作 一 跑步的基本原理 前面介绍了走路的动画的制作 跑步的制作方式和走路的方式是一样的 但是我们怎样来区别这两个动作的不同呢 虽然跑步在日常生活中经常看见 但是我们可能从来没有仔细的分析每一个动作 现在我们再来简单的说一下走路
  • upload labs第二关

    从上往下 首先定义两个变量 其中一个为空 在点击提交按钮后 前提文件路径可以找到 开始看文件类型是否为jpeg png gif格式 is upload false msg null if isset POST submit if file
  • Docker搭建zookeeper

    问题背景 前言 本文参考自 docker compose快速搭建Zookeeper集群 熬到凌晨三点多验证部署成功 网上有很多文章已经无法正确部署了 因为有些东西版本升级了 版本跟不上就会报错 还有一种更加详细更加全面的部署方式 Docke
  • 新人如何快速高效的学习Java?

    如果是新人 不想通过培训班 想学java 那么我可以很认真的告诉你 如果你是因为兴趣学学 那么你怎么学都可以 建议你找一些零基础入门的视频来学习 先看一遍 认识一下Java是个什么东西 如果是想转行学习 靠这个来工作 那么你就要好好的制定一
  • 一台计算机要两个内网,局域网如何在一台电脑上设置两个IP地址

    由于工作原因 有时需要连接两个局域网 除了频繁地更换不同局域网的网线 还要不停地设置不同局域网的IP地址 真是很麻烦 下面是学习啦小编收集整理的局域网如何在一台电脑上设置两个IP地址 希望对大家有帮助 局域网在一台电脑上设置两个IP地址的方
  • STM32F4单片机ADC采样及ARM-DSP库的FFT

    模拟信号经过ADC采样后变成数字信号 数字信号可以进行FFT运算 在频域中更容易分析信号的特征 本文将介绍如何用STM32F4的进行ADC采样 并利用ARMDSP库里的FFT算法对ADC采样值进行快速傅里叶变换 我使用的是STM32F407