STM32F411 ADC+DMA扫描连续模式仅执行一次转换问题求助
问题分析与解决方案
你的代码中导致ADC仅执行一次序列转换的核心问题有两处,以下是具体分析和修复方案:
1. 未启用ADC的DMA连续请求模式
当DMA工作在循环模式(DMA_SxCR_CIRC)时,必须配置ADC的DDS位(DMA Disable Selection),否则当DMA第一次完成4次传输后,ADC会停止产生DMA请求,导致后续转换无法触发DMA传输。
需要在ADC配置中添加:
ADC1->CR2 |= ADC_CR2_DDS; // 开启DMA连续请求,即使NDTR归零仍持续产生请求
2. 缺失ADC校准步骤(可选但推荐)
STM32 ADC上电后执行校准可以提升转换精度,避免因未校准导致的异常行为,建议在开启ADC前添加校准流程:
ADC1->CR2 |= ADC_CR2_ADON; // 第一次开启ADC,准备校准 while(!(ADC1->SR & ADC_SR_ADRDY)); // 等待ADC就绪 ADC1->CR2 |= ADC_CR2_CAL; // 启动校准 while(ADC1->CR2 & ADC_CR2_CAL); // 等待校准完成
3. 明确DMA通道选择(可选但更稳妥)
虽然复位后DMA2 Stream0默认选择Channel 0(对应ADC1请求),但明确配置通道可以避免潜在的配置冲突:
DMA2_Stream0->CR &= ~DMA_SxCR_CHSEL_Msk; // 清除通道选择位 DMA2_Stream0->CR |= 0 << DMA_SxCR_CHSEL_Pos; // 选择Channel 0(ADC1请求)
修改后的完整代码
#include "stm32f411xe.h" int16_t adc_ch[4]; int main() { // Enabling peripheral clocks RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; // Enable DMA2 clock // Pin A0-A3 as analog inputs GPIOA->MODER |= GPIO_MODER_MODE0 | GPIO_MODER_MODE1 | GPIO_MODER_MODE2 | GPIO_MODER_MODE3; // Configuring sequence for analog reading ADC1->SQR1 |= 3 << 20; // Sequence length: 4 channels ADC1->SQR3 |= 0 << 0; // A0 first ADC1->SQR3 |= 1 << 5; // A1 second ADC1->SQR3 |= 2 << 10; // A2 third ADC1->SQR3 |= 3 << 15; // A3 fourth // Setting ADC1 ADC1->CR1 |= ADC_CR1_SCAN; // Enable scanning mode ADC1->CR2 |= ADC_CR2_DMA; // Enable DMA mode ADC1->CR2 |= ADC_CR2_DDS; // Enable continuous DMA requests // ADC calibration (recommended) ADC1->CR2 |= ADC_CR2_ADON; while(!(ADC1->SR & ADC_SR_ADRDY)); ADC1->CR2 |= ADC_CR2_CAL; while(ADC1->CR2 & ADC_CR2_CAL); // Setting DMA channel DMA2_Stream0->PAR = (uint32_t)(&(ADC1->DR)); // DMA source address (ADC DR) DMA2_Stream0->M0AR = (uint32_t)(&(adc_ch[0])); // DMA destination address (array) DMA2_Stream0->NDTR = 4; // Number of data items to transfer DMA2_Stream0->CR &= ~DMA_SxCR_CHSEL_Msk; DMA2_Stream0->CR |= 0 << DMA_SxCR_CHSEL_Pos; // Select Channel 0 (ADC1) DMA2_Stream0->CR |= DMA_SxCR_CIRC // Enable circular mode | DMA_SxCR_MINC // Enable memory address increment | DMA_SxCR_PSIZE_0 // Peripheral data size: 16 bits | DMA_SxCR_MSIZE_0; // Memory data size: 16 bits DMA2_Stream0->CR |= DMA_SxCR_EN; // Enable DMA stream // Start continuous ADC conversion ADC1->CR2 |= ADC_CR2_CONT; ADC1->CR2 |= ADC_CR2_ADON; ADC1->CR2 |= ADC_CR2_SWSTART; while(1) { // 可在此添加调试代码,比如读取adc_ch数组的值验证转换状态 } }
验证说明
修改后,DMA会在循环模式下持续将ADC转换结果传输到adc_ch数组,配合ADC的连续转换模式(ADC_CR2_CONT),实现4个通道的连续扫描读取。你可以在while(1)循环中添加调试代码,观察adc_ch数组的值是否持续更新,确认功能正常。
内容的提问来源于stack exchange,提问作者JPgiq
相关产品推荐
相关产品推荐

