STM32中ADC + DMA自动采集系统
一、系统原理概述
“ADC + DMA 自动采集系统”是一种高效的数据采集架构,适用于需要高频率采样且要求CPU占用率低的应用场景(如传感器采集、音频处理、电压监控等)。
系统由以下三个核心模块组成:
- ADC(模数转换器):将连续变化的模拟电压信号转换为数字信号;
- DMA(直接存储器访问):将ADC转换的结果自动传输到内存中;
- CPU(中央处理单元):仅负责初始化配置和处理数据,不参与中间搬运过程。
类比理解:
- ADC 相当于“扫描仪”,负责采集外部信号;
- DMA 相当于“传送带”,负责将采样结果送达内存;
- CPU 相当于“指挥者”,只在需要时查看结果并进行处理,不负责搬运数据。
二、工作流程
数据采集的完整工作流程如下:
- CPU初始化配置ADC与DMA;
- 启动ADC采样;
- ADC完成一次采样后,自动触发DMA传输;
- DMA将数据搬运至预设内存数组中;
- 当采样达到设定数量后,DMA触发中断通知CPU;
- 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通道0GPIO_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(); // 配置DMAADC_Config(); // 配置ADCStart_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或定时任务:实现更复杂的多任务处理结构。
