一、系统原理概述

ADC + DMA 自动采集系统”是一种高效的数据采集架构,适用于需要高频率采样且要求CPU占用率低的应用场景(如传感器采集、音频处理、电压监控等)。

系统由以下三个核心模块组成:

  • ADC(模数转换器):将连续变化的模拟电压信号转换为数字信号;
  • DMA(直接存储器访问):将ADC转换的结果自动传输到内存中;
  • CPU(中央处理单元):仅负责初始化配置和处理数据,不参与中间搬运过程。

类比理解:

  • ADC 相当于“扫描仪”,负责采集外部信号;
  • DMA 相当于“传送带”,负责将采样结果送达内存;
  • CPU 相当于“指挥者”,只在需要时查看结果并进行处理,不负责搬运数据。

二、工作流程

数据采集的完整工作流程如下:

  1. CPU初始化配置ADC与DMA
  2. 启动ADC采样
  3. ADC完成一次采样后,自动触发DMA传输
  4. DMA将数据搬运至预设内存数组中
  5. 当采样达到设定数量后,DMA触发中断通知CPU
  6. CPU响应中断,处理采集到的数据

这种机制实现了**“采集-传输-存储-处理”**的全自动化流程,使得CPU资源得到极大释放。


三、关键技术点

技术点 说明
ADC触发模式 可使用软件触发定时器触发;建议使用定时器触发以实现等间隔采样
DMA传输模式 采用循环模式(Circular),实现持续采样与回写
数据缓冲区 使用数组(如 uint16_t ADC_ConvertedValue[])存储采样结果
通道映射 以 STM32F1 为例,DMA1_Channel1 与 ADC1 配合使用
数据对齐与大小 ADC输出为 12-bit,建议使用 uint16_t 类型接收
中断处理 可选用 DMA 传输完成中断,实现数据处理触发机制

四、系统初始化步骤

Step 1:GPIO 配置为模拟输入

void ADC_GPIO_Config(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;  // ADC通道0
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

Step 2:ADC 配置

void ADC_Config(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

    ADC_InitTypeDef ADC_InitStructure;
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

    ADC_Cmd(ADC1, ENABLE);

    // 校准
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
}

Step 3:DMA 配置

#define ADC_BUFFER_SIZE 1000
uint16_t ADC_ConvertedValue[ADC_BUFFER_SIZE];

void DMA_Config(void)
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(DMA1_Channel1);

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = ADC_BUFFER_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_Init(DMA1_Channel1, &DMA_InitStructure);

    DMA_Cmd(DMA1_Channel1, ENABLE);
    ADC_DMACmd(ADC1, ENABLE);
}

Step 4:启动ADC

void Start_ADC(void)
{
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

五、主函数示例

int main(void)
{
    ADC_GPIO_Config();  // 配置GPIO为模拟输入
    DMA_Config();       // 配置DMA
    ADC_Config();       // 配置ADC
    Start_ADC();        // 启动ADC采样

    while (1)
    {
        // 在此处理 ADC_ConvertedValue[] 中的数据
        // 可加入滤波算法、数据上传、显示等功能
    }
}

六、运行效果

  • 系统可以持续、自动地采集模拟电压信号;
  • 采样数据实时存入内存数组,无需CPU干预;
  • CPU可以用于其他任务(如串口通信、数据显示、控制逻辑等);
  • 在 STM32F103 平台上,可实现 1Msps(百万次每秒)采样率,性能强大。

七、常见问题与调试技巧

问题 可能原因 解决方法
数据全为0 DMA未启用,ADC未启动 检查 DMA 与 ADC 启动顺序
数据偏移、错位 缓冲区大小或数据对齐错误 确保 uint16_t 类型匹配 ADC 输出
数据不连续 DMA未设置为 Circular 模式 DMA_Mode 设置为 DMA_Mode_Circular
中断不触发 未配置DMA中断或未清中断标志 配置中断并在中断服务函数内清除标志
数据过快丢失 缓冲区太小,处理不及时 增大数组或提高处理速度

八、知识总结

模块 功能 说明
ADC 模拟信号采样 将电压模拟信号转换为数字值
DMA 自动数据传输 自动将ADC转换结果搬运到内存
CPU 控制与数据处理 初始化配置,处理最终结果

九、扩展建议

  • 使用定时器触发ADC采样,实现精确周期采样;
  • 添加DMA中断处理函数,在采样完成时自动处理数据;
  • 多通道采样支持:开启 ScanConvMode 配合 DMA 多通道缓冲;
  • 滤波与均值算法:对采样值进行软件滤波,提升稳定性;
  • 结合RTOS或定时任务:实现更复杂的多任务处理结构。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐