STM32F103 ADC DMA采样与均值滤波处理实战指南

STM32F103 ADC DMA采样与均值滤波处理实战指南

在嵌入式开发中,ADC(模数转换器)是与外部模拟信号交互的重要外设之一。而STM32作为一款功能强大的微控制器,其ADC模块配合DMA(直接存储器访问)功能,可以高效地实现多通道数据采集与处理。本文将以STM32F103为例,详细介绍如何通过STM32CubeMX配置ADC DMA方式采样,并对3个通道的数据进行均值滤波处理。

一、硬件准备

• STM32F103开发板:确保开发板正常工作,所有引脚连接良好。

• 外部模拟信号源:例如可变电阻、温度传感器等,用于提供待采集的模拟信号。

• 串口调试助手:用于接收和查看最终的滤波结果。

二、软件环境搭建

• STM32CubeMX:用于图形化配置STM32的外设。

• STM32CubeIDE:用于编写代码和烧录程序。

三、ADC与DMA配置

(一)ADC配置

• 启动STM32CubeMX,创建一个新的项目,选择STM32F103C8T6作为目标芯片。

• 配置ADC模块:

复制代码
• 在左侧的外设列表中找到ADC1,双击打开配置界面。

• 设置ADC模式:选择Single模式,因为我们是逐个通道采集数据。

• 选择时钟源:选择APB2,确保ADC有足够的时钟频率。

• 配置采样时间:根据实际需求选择合适的采样时间,例如1.5 Cycles。

• 选择通道:将需要采集的3个通道(假设为PA0、PA1、PA2)添加到Regular Conversion Group中,并设置它们的采样顺序。例如,将PA0设置为第1个通道,PA1为第2个通道,PA2为第3个通道。

(二)DMA配置

• 启用DMA功能:

复制代码
• 在左侧的外设列表中找到DMA1,双击打开配置界面。

• 选择DMA1_Channel1(因为ADC1的DMA请求映射到DMA1_Channel1)。

• 配置DMA参数:

复制代码
• 方向:选择Peripheral to Memory,因为数据是从ADC传输到内存。

• 内存增量:选择Incremented Address,因为我们需要将数据存储到连续的内存地址中。

• 循环模式:选择Circular,这样在DMA传输完成后会自动重新开始,方便连续采集。

• 传输大小:设置为150(3个通道×50次采样)。

• 优先级:根据实际需求选择合适的优先级。

• 将DMA与ADC关联:

复制代码
• 在DMA Request选项中,选择ADC1作为请求源。

• 确保DMA Enable选项被勾选,以启用DMA功能。

(三)生成代码

• 配置完成后,点击Project菜单,选择Generate Code。

• 在生成代码的过程中,STM32CubeMX会自动生成ADC和DMA的初始化代码,并将它们添加到项目中。

四、代码实现

(一)初始化代码

在生成的代码中,ADC1_Init()DMA1_Channel1_Init()函数已经完成了大部分初始化工作。我们需要确保这些函数被正确调用。

c 复制代码
/* ADC1 DMA Init */
void MX_ADC1_DMA_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};
  DMA_HandleTypeDef hdma_adc1;

  /* DMA1_Channel1 初始化 */
  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_HALFWORD;
  hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
  hdma_adc1.Init.Mode = DMA_CIRCULAR;
  hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
  hdma_adc1.Init.MemBurst = DMA_MBURST_SINGLE;
  hdma_adc1.Init.PeriphBurst = DMA_PBURST_SINGLE;
  HAL_DMA_Init(&hdma_adc1);

  __HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);

  /* ADC1 初始化 */
  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 3;
  HAL_ADC_Init(&hadc1);

  /* 配置通道 */
  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);

  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = 2;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);

  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = 3;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

(二)DMA中断处理

在DMA中断中,我们需要处理采集到的数据。由于我们选择了循环模式,DMA会自动将采集到的数据存储到指定的内存地址中。在下面示例中,50次采样(传输大小:设置为150(3个通道×50次采样))完成后,3个通道就是150个数据,会进入以下的采样完成回调函数中,在这个函数中,我们进行均值滤波处理,并将数据发送到串口调试助手显示。实际应用中,只需要计算出平均值更新,然后在需要的时候使用这个值。

另外,如果对50个采样值滤波的周期有其他特殊需求的话,可以更改采样的缓存大小,以及更改ADC采样时间。比如,防止引入工频50Hz的干扰,采样周期就不能是50Hz,大家可以根据自己的实际情况进行调整。

c 复制代码
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  if (hadc->Instance == ADC1)
  {
    // 在这里处理采集到的数据
    // 例如,计算每个通道的均值
    uint16_t *data = (uint16_t*)hdma_adc1.Instance->CMAR;
    uint32_t sum[3] = {0};
    uint32_t avg[3] = {0};

    for (int i = 0; i < 50; i++)
    {
      sum[0] += data[i * 3];
      sum[1] += data[i * 3 + 1];
      sum[2] += data[i * 3 + 2];
    }

    avg[0] = sum[0] / 50;
    avg[1] = sum[1] / 50;
    avg[2] = sum[2] / 50;
    
    // 将均值发送到串口
    char buffer[50];
    sprintf(buffer, "Channel 0: %d, Channel 1: %d, Channel 2: %d\r\n", avg[0], avg[1], avg[2]);
    HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
  }
}

(三)启动ADC采样

在主函数中,启动ADC采样并启动DMA传输。

c 复制代码
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_DMA_Init();
  MX_USART1_UART_Init();

  // 启动DMA传输
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcBuffer, 150);

  while (1)
  {
    // 主循环中可以执行其他任务
  }
}

五、测试与验证

• 连接外部信号源:将模拟信号源连接到PA0、PA1和PA2引脚。

• 烧录程序:将编译好的程序烧录到STM32F103开发板中。

• 打开串口调试助手:设置波特率与程序中一致(例如115200)。

• 观察结果:观察串口调试助手的输出,查看每个通道的均值滤波结果。

六、总结

通过STM32CubeMX配置ADC和DMA,可以高效地实现多通道数据采集与处理。在本例中,我们成功实现了3个通道的DMA采样,并对每个通道的数据进行了均值滤波处理。这种方法不仅提高了数据采集的效率,还通过均值滤波降低了噪声的影响,使得采集到的数据更加稳定和可靠。希望本文能为你的STM32开发提供帮助!

相关推荐
Tandy12356_1 小时前
手写TCP/IP协议栈——数据包结构定义
c语言·网络·c++·计算机网络
沉在嵌入式的鱼1 小时前
STM32--HX711称重传感器
stm32·单片机·嵌入式硬件·hx711·称重传感器
小年糕是糕手1 小时前
【C++】类和对象(四) -- 取地址运算符重载、构造函数plus
c语言·开发语言·数据结构·c++·算法·leetcode·蓝桥杯
Geek__19922 小时前
记录FreeRtos消息调试问题
c语言·stm32·mcu
小琦QI2 小时前
STM32F407VET6+CCE4503学习笔记---IOLINK server
笔记·stm32·学习
无限进步_2 小时前
基于单向链表的C语言通讯录实现分析
c语言·开发语言·数据结构·c++·算法·链表·visual studio
Darken032 小时前
基于单片机STM32中的OLED显示屏
stm32·单片机·oled·显示屏
无限进步_2 小时前
C语言双向循环链表实现详解:哨兵位与循环结构
c语言·开发语言·数据结构·c++·后端·算法·链表
杨福瑞2 小时前
数据结构:栈
c语言·开发语言·数据结构