STM32 HAL库实战:用ADC+DMA同时采集3路传感器数据(附完整代码)

张开发
2026/4/16 13:02:11 15 分钟阅读

分享文章

STM32 HAL库实战:用ADC+DMA同时采集3路传感器数据(附完整代码)
STM32 HAL库实战用ADCDMA同时采集3路传感器数据附完整代码在环境监测、工业控制等物联网应用中经常需要同时采集多个传感器的模拟信号。传统轮询方式会导致CPU负载过高而STM32的ADC配合DMA功能可以实现多通道数据自动采集将CPU解放出来处理更重要的任务。本文将手把手教你如何用HAL库实现三路传感器同步采集包含完整的工程代码和数据处理技巧。1. 硬件设计与配置要点1.1 引脚分配与传感器连接我们选择STM32F103系列作为硬件平台使用ADC1的三个通道PC1(ADC1_IN11)连接温度传感器PA2(ADC1_IN2)连接光照传感器PA3(ADC1_IN3)连接电压检测电路注意不同STM32型号的ADC通道对应引脚可能不同需查阅对应芯片的数据手册。1.2 ADC关键参数配置通过CubeMX或手动初始化时需要特别关注以下参数参数配置值说明ScanConvModeENABLE启用多通道扫描ContinuousConvModeENABLE连续转换模式NbrOfConversion3转换通道数量DataAlignRIGHT数据右对齐SamplingTime239.5周期根据信号源阻抗调整ADC_HandleTypeDef hadc1; hadc1.Instance ADC1; hadc1.Init.ScanConvMode ADC_SCAN_ENABLE; hadc1.Init.ContinuousConvMode ENABLE; hadc1.Init.NbrOfConversion 3; hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT; hadc1.Init.DiscontinuousConvMode DISABLE;2. DMA配置与数据流控制2.1 DMA初始化关键步骤DMA配置需要特别注意内存和外围地址的增量设置DMA_HandleTypeDef hdma_adc; hdma_adc.Instance DMA1_Channel1; hdma_adc.Init.Direction DMA_PERIPH_TO_MEMORY; hdma_adc.Init.PeriphInc DMA_PINC_DISABLE; // 外设地址固定 hdma_adc.Init.MemInc DMA_MINC_ENABLE; // 内存地址递增 hdma_adc.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD; hdma_adc.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD; hdma_adc.Init.Mode DMA_CIRCULAR; // 循环模式 hdma_adc.Init.Priority DMA_PRIORITY_HIGH; HAL_DMA_Init(hdma_adc); // 连接ADC和DMA __HAL_LINKDMA(hadc1, DMA_Handle, hdma_adc);2.2 双缓冲技术实现为避免数据处理时的竞争条件建议使用双缓冲技术定义两个缓冲区交替使用DMA传输完成中断中切换缓冲区主循环处理非活动缓冲区数据#define BUF_SIZE 150 // 50次×3通道 uint16_t adc_buf1[BUF_SIZE], adc_buf2[BUF_SIZE]; volatile uint8_t active_buf 0; // 当前活动缓冲区标志 // DMA传输完成回调函数 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { active_buf ^ 1; // 切换缓冲区 if(active_buf) { HAL_ADC_Start_DMA(hadc1, (uint32_t*)adc_buf1, BUF_SIZE); } else { HAL_ADC_Start_DMA(hadc1, (uint32_t*)adc_buf2, BUF_SIZE); } }3. 数据解析与校准技巧3.1 多通道数据分离算法采集到的数据是按通道顺序交替存储的需要正确分离各通道数据void process_adc_data(uint16_t *buf) { float ch1_sum 0, ch2_sum 0, ch3_sum 0; for(int i0; i50; i) { ch1_sum buf[i*3 0]; // 通道1数据 ch2_sum buf[i*3 1]; // 通道2数据 ch3_sum buf[i*3 2]; // 通道3数据 } float ch1_avg ch1_sum / 50.0f; float ch2_avg ch2_sum / 50.0f; float ch3_avg ch3_sum / 50.0f; // 转换为实际物理量 float temp (ch1_avg * 3.3f / 4095.0f - 0.76f) / 0.0025f; // 假设温度传感器 float light ch2_avg * 100.0f / 4095.0f; // 光照百分比 float voltage ch3_avg * 3.3f * 11.0f / 4095.0f; // 11:1分压电路 }3.2 校准与滤波处理为提高数据精度推荐采用以下方法硬件校准上电时执行HAL_ADCEx_Calibration_Start()软件滤波移动平均滤波中值滤波卡尔曼滤波对动态信号// 移动平均滤波实现 #define FILTER_WINDOW 5 typedef struct { float buffer[FILTER_WINDOW]; uint8_t index; } filter_t; float moving_average(filter_t *f, float new_val) { f-buffer[f-index] new_val; f-index (f-index 1) % FILTER_WINDOW; float sum 0; for(int i0; iFILTER_WINDOW; i) { sum f-buffer[i]; } return sum / FILTER_WINDOW; }4. 工程优化与调试技巧4.1 低功耗设计当不需要连续采集时可以采用触发模式降低功耗配置ADC为单次转换模式使用定时器触发ADC采样DMA传输完成后进入低功耗模式// 定时器触发配置 hadc1.Init.ContinuousConvMode DISABLE; hadc1.Init.ExternalTrigConv ADC_EXTERNALTRIGCONV_T3_TRGO; // 定时器配置 TIM_HandleTypeDef htim3; htim3.Instance TIM3; htim3.Init.Prescaler 7200-1; // 10kHz htim3.Init.CounterMode TIM_COUNTERMODE_UP; htim3.Init.Period 100-1; // 100Hz采样率 HAL_TIM_Base_Init(htim3); HAL_TIM_Base_Start(htim3);4.2 常见问题排查数据错位检查DMA内存地址增量设置采样值跳动增加采样时间添加RC滤波电路检查电源稳定性DMA不触发确认DMA和ADC时钟使能检查__HAL_LINKDMA调用在项目开发中我习惯先用逻辑分析仪抓取ADC的触发信号和DMA传输时序这样可以快速定位是配置问题还是硬件问题。当遇到异常数据时先断开传感器直接用已知电压测试可以排除传感器端的问题。

更多文章