[STM32F4] STM32F407:基于DMA的ADC数据采集与处理

[复制链接]
5198|53
 楼主| 周半梅 发表于 2025-2-28 08:35 | 显示全部楼层 |阅读模式
AD, ADC, DM, DMA, ST
在嵌入式系统中,ADC(模数转换)广泛应用于传感器数据采集、音频信号处理等场合。而STM32F407微控制器,凭借其强大的硬件资源和灵活的外设配置,成为了很多高性能数据采集应用的首选。本文将详细介绍如何使用STM32F407通过DMA(直接内存访问)方式高效地采集模拟信号,并进行数据处理。
项目背景与需求
在许多实时系统中,数据采集的速度和精度至关重要。STM32F407内建12位的ADC转换器,可以进行高精度的模拟信号采样。通常情况下,CPU通过轮询方式获取ADC数据,但这种方式会占用大量处理器时间,尤其是在需要频繁采样的场合。而DMA可以在没有CPU干预的情况下直接将ADC转换结果传输到内存,极大地提高了系统效率。
本项目的目标是使用STM32F407的ADC和DMA功能,实时采集模拟信号并将数据存储到内存中。我们将使用DMA进行数据传输,以减少CPU负担,并通过简单的处理算法展示如何处理这些数据。
硬件配置
STM32F407开发板配备了多个模拟输入引脚,可以连接到外部传感器或信号源。本示例中,我们将使用STM32F407的ADC1模块和PA0引脚作为输入源,采集模拟信号。
软件环境
开发环境选择STM32CubeIDE,它结合了STM32CubeMX进行配置,并提供了HAL库支持。使用此环境,可以简化初始化代码的编写,并轻松地配置DMA和ADC。
步骤1:STM32CubeMX配置
  • 打开STM32CubeMX并创建一个新的STM32F407项目。
  • 在“Pinout & Configuration”页面,选择PA0引脚为ADC输入。
  • 启用ADC1模块,选择DMA传输模式。
  • 在“Configuration”页面,启用DMA功能,并将ADC1的数据传输到内存。
  • 配置ADC的采样频率,设置为合适的采样速率,确保能够满足应用的实时需求。
  • 生成代码并导入STM32CubeIDE。
步骤2:代码实现
  1. #include "stm32f4xx_hal.h"

  2. #define ADC_BUFFER_SIZE 100

  3. ADC_HandleTypeDef hadc1;
  4. DMA_HandleTypeDef hdma_adc1;
  5. uint32_t adc_buffer[ADC_BUFFER_SIZE]; // DMA缓存区,用于存储ADC采样数据

  6. // ADC和DMA初始化
  7. void ADC_DMA_Init(void)
  8. {
  9.     // 配置ADC
  10.     __HAL_RCC_ADC1_CLK_ENABLE();
  11.     hadc1.Instance = ADC1;
  12.     hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 12位分辨率
  13.     hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  14.     hadc1.Init.ContinuousConvMode = ENABLE; // 连续转换模式
  15.     hadc1.Init.DiscontinuousConvMode = DISABLE;
  16.     hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
  17.     hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  18.     hadc1.Init.NbrOfConversion = 1; // 只采集一个通道

  19.     HAL_ADC_Init(&hadc1);

  20.     // 配置DMA
  21.     __HAL_RCC_DMA2_CLK_ENABLE();
  22.     hdma_adc1.Instance = DMA2_Stream0;
  23.     hdma_adc1.Init.Channel = DMA_CHANNEL_0;
  24.     hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
  25.     hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
  26.     hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
  27.     hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  28.     hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
  29.     hdma_adc1.Init.Mode = DMA_CIRCULAR; // 循环模式
  30.     hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
  31.     HAL_DMA_Init(&hdma_adc1);

  32.     // 将DMA与ADC关联
  33.     __HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);

  34.     // 启动DMA
  35.     HAL_ADC_Start_DMA(&hadc1, adc_buffer, ADC_BUFFER_SIZE);
  36. }

  37. // ADC采集数据处理函数
  38. void Process_ADC_Data(void)
  39. {
  40.     for (int i = 0; i < ADC_BUFFER_SIZE; i++) {
  41.         // 对采集到的数据进行处理,例如计算平均值、滤波等
  42.         uint32_t processed_data = adc_buffer[i]; // 这里仅做简单处理
  43.         printf("ADC采样数据[%d]: %ld\n", i, processed_data);
  44.     }
  45. }

  46. int main(void)
  47. {
  48.     HAL_Init();
  49.     SystemClock_Config();

  50.     // 初始化ADC和DMA
  51.     ADC_DMA_Init();

  52.     while (1) {
  53.         // 每隔一定时间处理一次采集的数据
  54.         HAL_Delay(1000);  // 假设每秒处理一次数据
  55.         Process_ADC_Data();
  56.     }
  57. }
步骤3:调试与测试
  • 编译并烧录代码到STM32F407开发板。
  • 使用调试工具检查DMA是否正确地将ADC数据传输到内存。
  • 通过串口输出查看采集到的ADC数据,并进行相应的处理。
总结
通过使用DMA进行ADC数据采集,可以有效减少CPU的负担,提高系统的实时性。STM32F407的ADC和DMA硬件资源使得这一过程非常高效,能够处理较高频率的数据采样。在本示例中,我们使用DMA将ADC采集的数据存储到内存,并通过简单的处理算法进行数据分析,适用于需要实时数据采集与处理的嵌入式应用。

公羊子丹 发表于 2025-2-28 08:35 | 显示全部楼层
这篇文章太棒了,STM32F407的ADC和DMA功能用得很好,学到了不少!
 楼主| 周半梅 发表于 2025-2-28 08:35 | 显示全部楼层
我也在做类似的项目,使用DMA传输ADC数据确实能节省不少处理时间,非常感谢这个例子!
帛灿灿 发表于 2025-2-28 08:36 | 显示全部楼层
代码写得很简洁,刚好用到我们项目中。对于DMA的配置有点疑惑,能否再详细解释一下?
童雨竹 发表于 2025-2-28 08:36 | 显示全部楼层
这个DMA模式的好处真的很大,能减少CPU的负担,提高效率,完美!
万图 发表于 2025-2-28 08:36 | 显示全部楼层
按照这个方法配置后,采样数据很稳定。期待看到更复杂的例子,比如如何处理多个通道的ADC数据。
Wordsworth 发表于 2025-2-28 08:36 | 显示全部楼层
这个示例给了我很多灵感,我也在考虑使用DMA来处理更高频率的数据采集,真的很实用!
Pulitzer 发表于 2025-2-28 08:37 | 显示全部楼层
太棒了!本来我还在为如何优化ADC采样而苦恼,今天看了这个,直接解决问题了。
Bblythe 发表于 2025-2-28 08:37 | 显示全部楼层
用DMA处理ADC数据确实能极大提高系统的性能,STM32F407的硬件资源好强大!
Uriah 发表于 2025-2-28 08:37 | 显示全部楼层
我尝试了这篇代码,完美运行!不过能否加一个简单的低通滤波处理,让数据更加平滑?
Clyde011 发表于 2025-2-28 08:37 | 显示全部楼层
非常感谢,代码示例清晰易懂,DMA确实是一种高效的方式来提升数据采集的性能。
dspmana 发表于 2025-3-4 19:45 | 显示全部楼层
数据采集与处理能够高效地完成模拟信号到数字信号的转换,并将数据快速传输到内存
robertesth 发表于 2025-3-4 21:40 | 显示全部楼层
使用环形指针 循环覆盖旧数据。              
51xlf 发表于 2025-3-9 19:08 | 显示全部楼层
根据ADC的分辨率设置DMA的数据宽度,如12位ADC对应设置数据宽度为DMA_PeripheralDataSize_HalfWord。同时,根据要传输的数据量设置缓冲区大小,即DMA的传输长度。
lihuami 发表于 2025-3-9 19:43 | 显示全部楼层
使用STM32CubeMX配置和使用DMA进行ADC数据采集
jimmhu 发表于 2025-3-9 20:29 | 显示全部楼层
根据实际需求选择合适的 DMA 模式,如循环模式或单次模式。循环模式适用于连续采集数据的场景,单次模式适用于只需要采集一次数据的场景。
sanfuzi 发表于 2025-3-9 21:11 | 显示全部楼层
基于DMA的ADC数据采集与处理在STM32F407上是一个非常高效的解决方案,
ulystronglll 发表于 2025-3-9 22:15 | 显示全部楼层
可以使用串口调试工具(如PuTTY、Tera Term等)查看ADC数据。
abotomson 发表于 2025-3-9 22:57 | 显示全部楼层
将外部模拟信号源连接到STM32F407的ADC输入引脚。例如,可以使用PA0引脚作为ADC1的输入通道。
cemaj 发表于 2025-3-10 09:58 | 显示全部楼层
在DMA传输完成后,可以在主循环或中断服务程序中处理采集到的数据。例如,可以计算数据的平均值、进行滤波处理,或者将数据发送到其他外设进行进一步处理。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

167

主题

6128

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部