1. 项目概述最近在做一个需要同时监测多路PWM信号电压的项目发现很多新手朋友对STM32的ADC多通道扫描模式不太熟悉。今天我就来分享一个实战案例如何使用STM32的ADC实现三路PWM信号的平均电压采集。这个方案特别适合需要同时监测多个模拟量的场景比如机器人关节位置反馈、电源管理系统等。2. 硬件设计2.1 硬件连接我们需要将三路PWM信号分别连接到STM32的三个ADC通道引脚上。以STM32F103C8T6为例可以选择以下引脚组合通道1PA0 (ADC1_IN0)通道2PA1 (ADC1_IN1)通道3PA2 (ADC1_IN2)注意ADC引脚不能与其他功能复用必须配置为纯模拟输入模式。2.2 信号调理电路由于PWM信号是数字脉冲我们需要先通过RC低通滤波器将其转换为模拟电压PWM信号 → 10kΩ电阻 → 100nF电容 → GND ↓ ADC输入这个简单的RC滤波器会输出PWM信号的平均电压时间常数τRC1ms适合频率在1kHz以下的PWM信号。3. 软件配置3.1 ADC初始化首先配置ADC工作在扫描模式ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode ENABLE; // 启用扫描模式 ADC_InitStructure.ADC_ContinuousConvMode ENABLE; // 连续转换 ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; // 软件触发 ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel 3; // 3个通道 ADC_Init(ADC1, ADC_InitStructure);3.2 通道配置设置三个通道的转换顺序和采样时间ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);3.3 DMA配置使用DMA自动搬运ADC转换结果DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_PeripheralBaseAddr (uint32_t)ADC1-DR; DMA_InitStructure.DMA_MemoryBaseAddr (uint32_t)adc_values; DMA_InitStructure.DMA_DIR DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize 3; 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);4. 数据处理4.1 读取原始数据DMA会将三个通道的ADC值自动存入数组uint16_t adc_values[3]; // 存放三个通道的ADC值4.2 计算平均电压将ADC值转换为实际电压float voltage1 adc_values[0] * 3.3f / 4095.0f; float voltage2 adc_values[1] * 3.3f / 4095.0f; float voltage3 adc_values[2] * 3.3f / 4095.0f;4.3 滤波处理为了得到更稳定的读数可以加入软件滤波#define FILTER_SIZE 10 float voltage1_buf[FILTER_SIZE]; float voltage1_filtered 0; // 移动平均滤波 for(int i0; iFILTER_SIZE-1; i){ voltage1_buf[i] voltage1_buf[i1]; } voltage1_buf[FILTER_SIZE-1] voltage1; for(int i0; iFILTER_SIZE; i){ voltage1_filtered voltage1_buf[i]; } voltage1_filtered / FILTER_SIZE;5. 常见问题与解决方案5.1 ADC读数不稳定可能原因电源噪声 - 确保ADC参考电压稳定信号干扰 - 缩短走线长度增加滤波电容采样时间不足 - 增加ADC_SampleTime参数5.2 通道间串扰解决方法在通道切换间增加延迟使用ADC的注入通道模式降低采样速率5.3 DMA数据错位检查点DMA内存地址递增设置是否正确DMA缓冲区大小是否匹配通道数是否启用了DMA循环模式6. 性能优化技巧对于高精度应用可以使用硬件过采样STM32的ADC支持最高256x过采样启用ADC的校准功能使用外部精密基准电压源对于高速应用减少采样时间使用双ADC交替采样模式提高系统时钟频率低功耗优化使用间断模式在不采样时关闭ADC降低采样频率这个方案我已经在多个项目中实际应用包括机器人舵机控制、电源监测等场景稳定性和精度都得到了验证。特别是在需要同时监测多个模拟量的场合这种多通道扫描DMA的方案可以大大减轻CPU负担。