一、ADC扫描模式与DMA传输原理
STM32的ADC支持多通道扫描模式,可自动按预设顺序转换多个通道。规则通道组最多16个通道,注入通道组最多4个通道。扫描模式下,ADC依次转换序列中的每个通道,每次转换结果存入对应的数据寄存器。若启用DMA,则每次转换完成触发DMA请求,将数据搬运到内存数组,避免CPU干预。
- 规则通道序列:由SQR1/SQR2/SQR3寄存器配置,决定转换顺序。
- 注入通道序列:由JSQR寄存器配置,可打断规则转换,常用于紧急事件采样。
- DMA循环模式:适合连续采样,自动覆盖旧数据。
二、采样顺序配置要点
采样顺序由序列寄存器中的SQx字段决定,编号从1到16。HAL库通过ADC_ChannelConfTypeDef的Rank成员设置顺序。注意:
- Rank必须连续且从1开始,不可跳跃。
- 规则组和注入组独立配置,互不影响。
- 注入通道可配置触发源(如定时器),实现与规则通道的异步采样。
三、CubeMX配置步骤
- 启用ADC1,选择多通道扫描模式。
- 在“Rank”中依次添加通道,设置采样时间。
- 使能DMA连续请求,模式设为Circular。
- 若使用注入通道,在“Injected”选项卡配置通道和触发源。
- 生成代码,HAL会自动初始化ADC和DMA。
四、完整代码示例
#include "main.h"
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
#define ADC_BUF_SIZE 3
uint16_t adc_buf[ADC_BUF_SIZE]; // 规则通道数据
volatile uint16_t inj_buf[2]; // 注入通道数据
void ADC_Init(void) {
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_adc1.Instance = DMA1_Channel1;
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;
HAL_DMA_Init(&hdma_adc1);
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 3;
HAL_ADC_Init(&hadc1);
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = 3;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// 注入通道配置(可选)
sConfig.Channel = ADC_CHANNEL_3;
sConfig.Rank = ADC_INJECTED_RANK_1;
sConfig.InjectedSamplingTime = ADC_SAMPLETIME_28CYCLES;
sConfig.InjectedOffset = 0;
sConfig.InjectedNbrOfConversion = 1;
sConfig.AutoInjectedConv = DISABLE;
sConfig.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;
HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfig);
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, ADC_BUF_SIZE);
}
// 注入通道转换完成回调
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* hadc) {
inj_buf[0] = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_1);
}
五、注意事项
-
DMA缓冲区对齐:确保内存地址与数据宽度匹配,使用
__attribute__((aligned(4)))避免对齐错误。 - 注入通道触发:若使用外部触发,需配置触发源并启动注入转换,否则不会自动执行。
- 采样时间:根据信号源阻抗调整采样时间,避免转换误差。
- 规则与注入优先级:注入通道可打断规则转换,但需注意数据一致性,建议在规则DMA传输完成回调中处理注入数据。
- HAL库版本差异:不同系列(如F1/F4/H7)的注入通道配置函数可能不同,请参考对应HAL文档。
通过合理配置扫描序列与DMA,结合注入通道的灵活触发,可构建高效、可靠的多通道数据采集系统。
暂无评论,来抢沙发~