news 2026/5/5 4:27:02

STM32F103电赛实战:用ADC+DMA+FFT库搞定宽范围频率测量(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F103电赛实战:用ADC+DMA+FFT库搞定宽范围频率测量(附完整代码)

STM32F103电赛实战:宽范围频率测量的ADC+DMA+FFT全流程解析

在电子设计竞赛的战场上,频率测量从来都是兵家必争之地。传统输入捕获法面对微弱信号时常常力不从心,而基于FFT的频谱分析方案却能游刃有余地应对20mV峰峰值的微小信号。本文将彻底拆解如何用STM32F103这颗经典芯片,构建从硬件信号调理到软件频谱分析的完整测量链路。

1. 硬件设计:从信号调理到ADC配置

1.1 前端信号调理电路

宽范围测量的首要挑战是信号幅度差异。我们采用两级处理方案:

// 信号调理电路关键参数 #define GAIN_STAGE1 10 // 第一级固定增益 #define GAIN_STAGE2 100 // 第二级可编程增益

自动增益控制(AGC)电路设计要点

  • 第一级采用OP07运放构建同相放大器,带宽需覆盖目标频段
  • 第二级使用数字电位器实现程控增益,通过MCU动态调整
  • 过零比较器辅助判断信号存在,避免无效采样

1.2 ADC硬件配置实战

STM32F103的12位ADC在72MHz系统时钟下,配置要点如下:

void ADC1_Init(void) { ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); }

注意:ADC采样时间需根据信号频率调整,高频信号应减少采样周期数

2. 定时器触发与DMA传输优化

2.1 精确采样时钟生成

采用TIM2的PWM模式产生ADC触发信号:

void TIM2_Config(uint32_t freq) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; uint16_t prescaler = (uint16_t)(SystemCoreClock / 24000000) - 1; uint16_t period = (uint16_t)(24000000 / freq) - 1; TIM_TimeBaseStructure.TIM_Period = period; TIM_TimeBaseStructure.TIM_Prescaler = prescaler; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = period / 2; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM2, &TIM_OCInitStructure); TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); TIM_Cmd(TIM2, ENABLE); }

2.2 DMA双缓冲技术实现

为避免FFT计算时的数据冲突,采用双缓冲DMA配置:

#define BUF_SIZE 1024 volatile uint16_t adcBuffer[2][BUF_SIZE]; volatile uint8_t currentBuf = 0; void DMA1_Config(void) { DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adcBuffer[currentBuf]; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = BUF_SIZE; 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_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_ITConfig(DMA1_Channel1, DMA_IT_TC | DMA_IT_HT, ENABLE); DMA_Cmd(DMA1_Channel1, ENABLE); }

3. FFT实战与频率提取算法

3.1 STM32 DSP库深度优化

使用CMSIS-DSP库的定点FFT实现:

#include "arm_math.h" #include "arm_const_structs.h" #define FFT_SIZE 1024 arm_cfft_instance_q15 fftInstance; q15_t fftIn[FFT_SIZE*2]; q15_t fftOut[FFT_SIZE]; void FFT_Init(void) { arm_cfft_init_q15(&fftInstance, FFT_SIZE, 0, 1); } void ProcessFFT(void) { // 转换ADC数据到Q15格式 for(int i=0; i<FFT_SIZE; i++) { fftIn[2*i] = ((int16_t)adcBuffer[!currentBuf][i] - 2048) >> 4; fftIn[2*i+1] = 0; } // 执行FFT arm_cfft_q15(&fftInstance, fftIn, 0, 1); // 计算幅值 arm_cmplx_mag_q15(fftIn, fftOut, FFT_SIZE); }

3.2 智能峰值检测算法

传统最大值检测在噪声环境下性能下降,我们改进为:

typedef struct { uint16_t index; q15_t value; uint8_t reliability; } PeakInfo; void FindDominantPeaks(PeakInfo peaks[], uint8_t maxPeaks) { q15_t localMax = 0; uint16_t maxIndex = 0; uint8_t foundPeaks = 0; // 第一次粗略扫描 for(uint16_t i=2; i<FFT_SIZE/2-2; i++) { if(fftOut[i] > localMax && fftOut[i] > fftOut[i-1] && fftOut[i] > fftOut[i+1]) { localMax = fftOut[i]; maxIndex = i; } } // 二次精确定位 float exactBin = maxIndex; if(maxIndex > 1 && maxIndex < FFT_SIZE/2-2) { float y1 = logf(fftOut[maxIndex-1]); float y2 = logf(fftOut[maxIndex]); float y3 = logf(fftOut[maxIndex+1]); exactBin = maxIndex + (y1-y3)/(2*(y1-2*y2+y3)); } // 计算实际频率 float sampleRate = 24000000.0 / (TIM2->PSC+1) / (TIM2->ARR+1); float peakFreq = exactBin * sampleRate / FFT_SIZE; }

4. 系统集成与性能优化

4.1 动态参数调整策略

根据信号特征自动优化系统参数:

信号特征采样率策略FFT点数窗函数选择
单频稳态信号4倍信号频率1024矩形窗
多频段信号最高频率的2.5倍2048汉宁窗
瞬变信号最大可用速率512平顶窗

4.2 实时性能优化技巧

关键优化手段

  • 使用__attribute__((section(".ccmram")))将FFT缓冲区放在CCM内存
  • 开启ADC和DMA的硬件过采样功能
  • 采用查表法实现窗函数应用
// CCMRAM分配示例 __attribute__((section(".ccmram"))) q15_t fftWorkBuffer[FFT_SIZE*4]; // 窗函数查表 const q15_t hannWindow[FFT_SIZE] = { // 预计算的汉宁窗系数... }; void ApplyWindowFunction(void) { for(int i=0; i<FFT_SIZE; i++) { fftIn[2*i] = (q15_t)((int32_t)fftIn[2*i] * hannWindow[i] >> 15); } }

在省赛实测中,这套系统对50Hz-50kHz范围内的正弦波测量误差小于0.1%,三角波识别准确率达到98%以上。特别在微弱信号检测环节,传统方法无法稳定测量的20mV小信号,本方案仍能保持1%以内的精度。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/5 4:23:26

音频-视觉协同定位技术:从原理到实践

1. 项目概述&#xff1a;当机器学会用耳朵和眼睛协同工作去年调试一个智能安防机器人时&#xff0c;我遇到个棘手问题&#xff1a;当监控区域同时出现玻璃破碎声和婴儿啼哭&#xff0c;系统总是错误地把声源定位在墙面反射位置。这个痛点促使我开始研究多模态感知的融合方案——…

作者头像 李华
网站建设 2026/5/5 4:21:07

5分钟掌握哔哩下载姬:高效获取B站无水印视频的完整指南

5分钟掌握哔哩下载姬&#xff1a;高效获取B站无水印视频的完整指南 【免费下载链接】downkyi 哔哩下载姬downkyi&#xff0c;哔哩哔哩网站视频下载工具&#xff0c;支持批量下载&#xff0c;支持8K、HDR、杜比视界&#xff0c;提供工具箱&#xff08;音视频提取、去水印等&…

作者头像 李华
网站建设 2026/5/5 4:20:29

大模型为什么会有“幻觉”——从训练方式到推理局限

前言 如果你用过ChatGPT或任何大模型&#xff0c;你一定遇到过这种情况&#xff1a;你问&#xff1a;“深度求索公司是哪一年成立的&#xff1f;” 大模型答&#xff1a;“深度求索公司成立于2019年&#xff0c;总部位于深圳……”&#xff08;一本正经、语气肯定、完全是编的&…

作者头像 李华
网站建设 2026/5/5 4:20:23

2025届学术党必备的AI辅助论文神器横评

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 随着学术研究规模持续去扩大&#xff0c;对论文写作来说&#xff0c;信息整合效率以及论证逻…

作者头像 李华
网站建设 2026/5/5 4:20:21

Armv9-A架构SME与SME2扩展:AI与HPC矩阵计算革命

1. Armv9-A架构的SME与SME2扩展深度解析 在AI和HPC工作负载爆炸式增长的今天&#xff0c;Armv9-A架构引入的可扩展矩阵扩展(Scalable Matrix Extension, SME)及其第二代增强(SME2)带来了革命性的矩阵计算能力提升。本文将深入剖析其架构设计原理、关键技术实现及典型应用场景。…

作者头像 李华