ADC多通道采集,开启DMA

 

硬件配置思路

使用DMA进行多通道ADC采集的主要优势:

  • 无需CPU干预,自动传输数据

  • 高效的数据流处理

  • 可实现连续转换模式

// adc_dma.h
#ifndef __ADC_DMA_H
#define __ADC_DMA_H

#include "main.h"

#define ADC_CHANNEL_COUNT  3     // 通道数量
#define ADC_BUFFER_SIZE    100   // 每个通道的采样点数

extern ADC_HandleTypeDef hadc1;
extern DMA_HandleTypeDef hdma_adc1;

extern uint16_t adc_buffer[ADC_CHANNEL_COUNT * ADC_BUFFER_SIZE];

void ADC_DMA_Init(void);
void ADC_Start_DMA_Conversion(void);
uint16_t ADC_Get_Channel_Value(uint8_t channel, uint16_t sample_index);

#endif


// adc_dma.c
#include "adc_dma.h"

// ADC DMA缓冲区定义
// 数据排列: [CH0_S0, CH1_S0, CH2_S0, CH0_S1, CH1_S1, CH2_S1, ...]
__ALIGN_BEGIN uint16_t adc_buffer[ADC_CHANNEL_COUNT * ADC_BUFFER_SIZE] __ALIGN_END;

void ADC_DMA_Init(void)
{
    // 初始化ADC
    if (HAL_ADC_Init(&hadc1) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 配置ADC通道
    ADC_ChannelConfTypeDef sConfig = {0};
    
    // 通道0配置
    sConfig.Channel = ADC_CHANNEL_0;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
    
    // 通道1配置
    sConfig.Channel = ADC_CHANNEL_1;
    sConfig.Rank = 2;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
    
    // 通道2配置
    sConfig.Channel = ADC_CHANNEL_2;
    sConfig.Rank = 3;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

void ADC_Start_DMA_Conversion(void)
{
    // 启动ADC DMA转换
    if (HAL_ADC_Start_DMA(&hadc1, 
                         (uint32_t*)adc_buffer, 
                         ADC_CHANNEL_COUNT * ADC_BUFFER_SIZE) != HAL_OK)
    {
        Error_Handler();
    }
}

// 获取指定通道的采样值
uint16_t ADC_Get_Channel_Value(uint8_t channel, uint16_t sample_index)
{
    if (channel >= ADC_CHANNEL_COUNT || sample_index >= ADC_BUFFER_SIZE)
    {
        return 0;
    }
    
    // 计算数据在缓冲区中的位置
    uint32_t index = sample_index * ADC_CHANNEL_COUNT + channel;
    return adc_buffer[index];
}

// 获取指定通道的平均值(用于滤波)
uint16_t ADC_Get_Channel_Average(uint8_t channel)
{
    if (channel >= ADC_CHANNEL_COUNT)
    {
        return 0;
    }
    
    uint32_t sum = 0;
    for (uint16_t i = 0; i < ADC_BUFFER_SIZE; i++)
    {
        sum += ADC_Get_Channel_Value(channel, i);
    }
    
    return (uint16_t)(sum / ADC_BUFFER_SIZE);
}

// DMA传输完成回调函数(可选)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    // 这里可以处理转换完成事件
    // 例如:设置标志位、数据处理等
    if (hadc->Instance == ADC1)
    {
        // ADC1转换完成处理
        // 可以在这里进行数据后处理或通知其他任务
    }
}

  

 

数据缓冲区结构说明

缓冲区数据排列方式:

 

adc_buffer[] = {
    CH0_sample0, CH1_sample0, CH2_sample0,  // 第一次扫描
    CH0_sample1, CH1_sample1, CH2_sample1,  // 第二次扫描
    CH0_sample2, CH1_sample2, CH2_sample2,  // 第三次扫描
    ...
}

  

关键注意事项

  1. DMA模式选择:

    • DMA_CIRCULAR:循环模式,自动重新开始转换

    • DMA_NORMAL:普通模式,需要手动重启

  2. 数据对齐:确保ADC和DMA的数据对齐方式一致

  3. 缓冲区大小:根据应用需求合理设置,避免内存浪费

  4. 中断使用:可以根据需要启用DMA传输完成中断

  5. 电压校准:如需精确测量,建议使用内部参考电压进行校准

这种配置方式可以实现高效的多通道ADC数据采集,特别适合需要实时监控多个模拟信号的应用场景。

 
 
 
posted @ 2025-09-26 16:18  多多和羊羊  阅读(27)  评论(0)    收藏  举报