当前位置: 首页 > news >正文

STM32F103用CubeMX实现ADC欠采样:用800Hz采样率捕获1kHz正弦波的保姆级教程

STM32F103用CubeMX实现ADC欠采样:用800Hz采样率捕获1kHz正弦波的保姆级教程

当信号频率超过奈奎斯特采样定理的限制时,传统方法会要求我们提升采样率。但通过欠采样技术,我们能够以远低于信号频率的采样率捕获高频信号。本文将手把手教你如何在STM32F103上实现用800Hz采样率准确捕获1kHz正弦波。

1. 硬件准备与环境搭建

在开始之前,我们需要准备以下硬件和软件环境:

  • STM32F103C8T6开发板(蓝色药丸板即可)
  • USB转TTL串口模块(用于数据传输)
  • 信号发生器(或能输出1kHz正弦波的设备)
  • STM32CubeMX v6.x
  • Keil MDK-ARM或STM32CubeIDE
  • VOFA+(或其它串口波形显示工具)

提示:如果使用其它STM32F103系列开发板,只需注意引脚兼容性。VOFA+是一款免费的串口数据可视化工具,支持多种协议。

安装好开发环境后,我们先计算几个关键参数:

采样间隔 = 1/800Hz = 1.25ms 等效采样率 = 信号频率 × 每周期采样点数 = 1kHz × 4 = 4kHz

2. CubeMX工程配置

启动CubeMX并按照以下步骤配置:

2.1 时钟树设置

  1. 选择外部晶振(HSE)作为时钟源
  2. 配置系统时钟为72MHz
  3. 设置APB2总线时钟为72MHz(ADC时钟源)

关键参数表

参数
HCLK72MHz
APB136MHz
APB272MHz
ADC预分频6分频
ADC时钟12MHz

2.2 ADC配置

  1. 启用ADC1
  2. 选择"Regular Conversion Mode"
  3. 设置"Data Alignment"为Right
  4. 启用"DMA Continuous Requests"
  5. 配置"Number Of Conversion"为1
// 生成的ADC初始化代码片段 hadc1.Instance = ADC1; hadc1.Init.ScanConvMode = DISABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1;

2.3 定时器配置(TIM3)

  1. 启用TIM3
  2. 设置时钟源为内部时钟
  3. 配置为"Trigger Output"模式
  4. 设置预分频器(PSC)为999
  5. 设置自动重载值(ARR)为89

定时器参数计算

定时器频率 = 72MHz / (PSC+1) = 72,000Hz 定时周期 = (ARR+1) / 定时器频率 = 90 / 72,000 = 1.25ms 触发频率 = 1 / 1.25ms = 800Hz

2.4 DMA配置

  1. 添加DMA通道(ADC1)
  2. 设置模式为"Circular"
  3. 数据宽度为"Word"
  4. 内存地址递增
// DMA配置示例 hdma_adc1.Instance = DMA1_Channel1; hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE; hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; hdma_adc1.Init.Mode = DMA_CIRCULAR;

3. 代码实现与调试

生成代码后,我们需要添加一些用户代码来实现完整功能。

3.1 主程序逻辑

#define SAMPLE_SIZE 400 // 采集400个点(约5个周期) uint32_t adcBuffer[SAMPLE_SIZE]; int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); MX_ADC1_Init(); MX_TIM3_Init(); HAL_ADC_Start_DMA(&hadc1, adcBuffer, SAMPLE_SIZE); HAL_TIM_Base_Start(&htim3); while (1) { // 数据通过DMA自动采集 // 可通过串口定期发送数据 } }

3.2 串口发送数据

添加串口发送函数,将采集到的数据发送到上位机:

void sendDataToPC(uint32_t *data, uint16_t size) { for(int i=0; i<size; i++) { uint16_t value = data[i] & 0xFFFF; // 取低16位 uint8_t buffer[2]; buffer[0] = value >> 8; buffer[1] = value & 0xFF; HAL_UART_Transmit(&huart1, buffer, 2, HAL_MAX_DELAY); HAL_Delay(1); // 防止发送过快导致丢包 } }

3.3 VOFA+配置

  1. 打开VOFA+,选择串口模式
  2. 设置正确的串口号和波特率
  3. 选择"FireWater"协议
  4. 添加波形显示控件
  5. 设置Y轴范围为0-3.3V(对应ADC值0-4095)

4. 结果分析与优化

当信号发生器输出1kHz正弦波时,我们将在VOFA+上看到类似下图的波形:

采样点分布示例: 周期1:点A(0°) → 周期2:点B(90°) → 周期3:点C(180°) → 周期4:点D(270°) 周期5:点A(0°) → 周期6:点B(90°) → ...

常见问题及解决方案

  1. 波形不连续或错位

    • 检查定时器配置是否正确
    • 确保信号频率准确为1kHz
    • 调整采样点数使其为信号周期的整数倍
  2. ADC值不稳定

    • 添加RC低通滤波电路(如1kΩ电阻+100nF电容)
    • 在代码中添加软件滤波(如移动平均)
  3. 数据传输丢失

    • 降低串口波特率(如改为115200)
    • 增加发送间隔时间

对于更精确的应用,可以考虑以下优化:

  • 使用定时器的主从模式实现更精确的触发
  • 添加硬件触发同步电路
  • 实现自动增益控制(AGC)适应不同幅值信号

在实际项目中,我发现最关键的三个参数是:

  1. 定时器触发间隔的精确性
  2. 信号频率的稳定性
  3. 采样点数与信号周期的匹配关系
http://www.cnnetsun.cn/news/2048796.html

相关文章:

  • 别再只盯着永恒之蓝了!手把手复现Samba CVE-2007-2447老漏洞(附Metasploit实战)
  • Real-ESRGAN-GUI:AI图像增强工具的终极指南
  • Clion配置Qt开发环境踩坑实录:MSVC 2017 vs MinGW,我的选择与避坑清单
  • 告别手动复制粘贴!用Python脚本批量抓取ENA数据库的Accession详细信息(附完整代码)
  • AI专著写作高效方案:AI工具一键生成20万字专著,格式规范易操作!
  • 揭秘AI写专著:AI专著生成工具大推荐,20万字专著轻松搞定!
  • vcpkg搭配CMake和VS Code:打造跨平台C++开发环境的完整配置指南
  • 新手程序员第一次接私活全流程指南:从注册平台到安全收款(避坑版)
  • 如何高效编辑赛博朋克2077存档:专业玩家的完整指南
  • 实战分享Flutter Web 开发:解决跨域(CORS)问题的终极指南
  • 从阿克曼角异响到安全转弯:冬季用车与直角转弯的完整指南
  • 从数据帧到精准定位:深度解析sensor_msgs/NavSatFix消息的实战应用
  • 保姆级教程:Windows 10下用Anaconda为Stable Diffusion WebUI创建Python 3.10专属环境(附换源指南)
  • sklearn的precision_score报UndefinedMetricWarning?别慌,这其实是模型在‘交白卷’
  • 多模态数据库设计:应对异构数据存储与查询的挑战
  • 遗传图谱与QTL可视化:用MapChart 2.32绘制带LOD曲线的专业图表
  • XPS深度解析:从原理到实战,攻克材料表面分析核心难题
  • 告别手动操作:用MATLAB脚本自动化处理GLDAS土壤湿度数据并生成动态变化图
  • 量子编程零门槛时代终结:VSCode 2026插件强制启用Rust底层运行时,现有Python扩展兼容率骤降至38%——你还在用旧版吗?
  • DeOldify在文化遗产数字化中的应用:古籍插图与档案修复
  • VSCode 2026跨端调试新纪元(2026.1正式版深度适配报告):仅3个插件+2行launch.json,实现跨平台断点同步与状态镜像
  • Abaqus仿真进阶:如何准确模拟软体抓手的抓取力(Blocking Force)与接触行为
  • BN层真的是‘炼丹’万能药吗?聊聊我在小Batch Size和RNN上踩过的坑
  • 别再手动截图了!用Lumerical脚本批量导出FDTD仿真数据(附Python处理代码)
  • Kaggle老手都在用的随机森林调参避坑指南:从特征重要性到OOB误差的实战技巧
  • MLOps社区如何重塑机器学习工程实践
  • 3000+免费生物科学矢量图标:Bioicons让你的科研图表设计变得简单快速
  • Bioicons:3000+免费科研矢量图标库如何彻底改变科学可视化工作流
  • 【freeModbus】STM32 HAL库移植避坑指南:从零搭建稳定Modbus从站
  • 抖音内容永久保存指南:douyin-downloader批量下载工具完全解析