在嵌入式系统开发中,模拟信号采集是最基础也是最重要的功能之一。STM32G431作为STMicroelectronics推出的主流Cortex-M4 MCU,其内置的12位ADC模块支持多达19个外部通道,能够满足绝大多数工业控制、传感器监测等场景的需求。多通道ADC采集的典型应用包括:
与单通道采集相比,多通道采集需要特别注意通道切换时的稳定时间、采样率分配以及数据对齐等问题。STM32G431的ADC模块支持三种多通道工作模式:
STM32G431的ADC通道分布在以下GPIO上:
对于多通道采集的硬件设计,需注意:
关键提示:当使用PB0/PB1作为ADC输入时,需注意这些引脚默认是JTAG功能,需要先禁用JTAG才能作为ADC通道使用。
ADC性能与时钟和电源质量密切相关:
c复制// 典型时钟配置示例(使用HCLK/2作为ADC时钟)
RCC_PeriphCLKInitTypeDef adc_clock = {0};
adc_clock.PeriphClockSelection = RCC_PERIPHCLK_ADC12;
adc_clock.Adc12ClockSelection = RCC_ADC12CLKSOURCE_PLL;
HAL_RCCEx_PeriphCLKConfig(&adc_clock);
电源方面建议:
使用STM32CubeMX进行多通道ADC配置的步骤:
在"Analog"选项卡中启用ADC1
勾选需要使用的通道(如IN1, IN2, IN3)
参数配置:
设置每个通道的采样时间:
多通道ADC采集强烈建议使用DMA传输,避免CPU频繁中断。配置要点:
c复制// DMA配置示例(循环模式)
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
数据存储建议使用双缓冲技术:
c复制#define ADC_BUF_LEN 256
uint16_t adc_buf1[ADC_BUF_LEN];
uint16_t adc_buf2[ADC_BUF_LEN];
HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)adc_buf1, ADC_BUF_LEN);
完整的多通道采集初始化流程:
c复制// 1. ADC校准
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
// 2. 配置规则组通道序列
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
// 通道1配置
sConfig.Channel = ADC_CHANNEL_1;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// 通道2配置
sConfig.Rank = ADC_REGULAR_RANK_2;
sConfig.Channel = ADC_CHANNEL_2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// 3. 启动ADC
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, buffer_length);
多通道采集时,通道切换需要稳定的建立时间。关键参数关系:
code复制总采样时间 = (采样周期 + 转换周期) × 通道数
实际采样率 = ADC时钟 / 总采样时间
优化建议:
现象:一个通道的值会影响相邻通道的读数
解决方法:
现象:DMA缓冲区只有部分通道数据更新
排查步骤:
可能原因及对策:
在电池供电应用中:
STM32G431支持ADC1和ADC2的同步工作:
c复制// 配置同步模式
ADC_MultiModeTypeDef multimode;
multimode.Mode = ADC_DUALMODE_REGSIMULT;
multimode.DMAAccessMode = ADC_DMAACCESSMODE_12_10_BITS;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);
典型应用场景:
利用硬件过采样可提升有效分辨率:
c复制// 配置16倍过采样(提升2位分辨率)
hadc1.Init.OversamplingMode = ENABLE;
hadc1.Init.Oversampling.Ratio = ADC_OVERSAMPLING_RATIO_16;
hadc1.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_2;
hadc1.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
在FreeRTOS中的典型用法:
c复制// 创建ADC任务
xTaskCreate(adc_task, "ADC", 256, NULL, 3, NULL);
// ADC任务函数
void adc_task(void *arg)
{
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, N);
while(1) {
// 等待半缓冲中断
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// 处理数据
process_adc_data();
}
}
// DMA半传输/完成中断回调
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(adc_task_handle, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
在实际项目中,我发现STM32G431的ADC性能很大程度上取决于PCB布局和电源质量。曾经有一个项目因为VDDA走线过长导致ADC噪声比规格差10dB,重新设计PCB后问题解决。另一个常见误区是过度追求高采样率而忽视采样保持时间,导致实际精度远低于预期。建议在关键应用中,先用示波器检查模拟信号质量,再优化ADC参数。