STM32F407 HAL 库 ADC_DMA3 通道:参考电压切换代码示例

以下是基于STM32F407 HAL库的ADC_DMA三通道采集(含参考电压切换)的代码示例。代码实现了三个ADC通道的DMA传输,并包含参考电压切换逻辑(使用内部基准或外部基准):

#include "stm32f4xx_hal.h"

// 定义ADC句柄和DMA句柄
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

// ADC缓冲区(三通道)
#define ADC_CHANNELS 3
uint32_t adcBuffer[ADC_CHANNELS] = {0};

// 初始化ADC配置
void ADC_Init(void) {
  ADC_ChannelConfTypeDef sConfig = {0};
  
  // 基本ADC配置
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = ADC_CHANNELS;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  HAL_ADC_Init(&hadc1);
  
  // 配置通道0(PA0)
  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);
  
  // 配置通道1(PA1)
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = 2;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);
  
  // 配置通道2(PA2)
  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = 3;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

// 切换参考电压源
void ADC_Switch_Vref(ADC_VrefType mode) {
  HAL_ADC_DeInit(&hadc1);  // 先停用ADC
  
  // 设置新参考电压
  #if defined(STM32F407xx)
  ADC->CCR &= ~(ADC_CCR_VBATE | ADC_CCR_TSVREFE);  // 清除原有配置
  if(mode == INTERNAL_VREF) {
    ADC->CCR |= ADC_CCR_TSVREFE;  // 启用内部基准
  } 
  else if(mode == VBAT_VREF) {
    ADC->CCR |= ADC_CCR_VBATE;    // 启用VBAT通道
  }
  // 外部基准默认无需额外配置
  #endif
  
  ADC_Init();  // 重新初始化ADC
  HAL_ADC_Start_DMA(&hadc1, adcBuffer, ADC_CHANNELS);  // 重启DMA
}

// DMA初始化
void DMA_Init(void) {
  __HAL_RCC_DMA2_CLK_ENABLE();
  
  hdma_adc1.Instance = DMA2_Stream0;
  hdma_adc1.Init.Channel = DMA_CHANNEL_0;
  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_WORD;
  hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
  hdma_adc1.Init.Mode = DMA_CIRCULAR;
  hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
  hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
  HAL_DMA_Init(&hdma_adc1);
  
  __HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
}

// 主函数
int main(void) {
  HAL_Init();
  SystemClock_Config();
  
  // 初始化外设
  __HAL_RCC_ADC1_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  
  // 配置GPIO
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  DMA_Init();
  ADC_Init();
  
  // 启动ADC(默认外部参考电压)
  HAL_ADC_Start_DMA(&hadc1, adcBuffer, ADC_CHANNELS);
  
  while(1) {
    // 示例:每10秒切换参考电压源
    HAL_Delay(10000);
    ADC_Switch_Vref(INTERNAL_VREF);  // 切换到内部基准
    
    HAL_Delay(10000);
    ADC_Switch_Vref(EXTERNAL_VREF);  // 切换回外部基准
  }
}

// DMA中断处理
void DMA2_Stream0_IRQHandler(void) {
  HAL_DMA_IRQHandler(&hdma_adc1);
}

关键点说明:

  1. 参考电压切换原理

    • 通过修改ADC->CCR寄存器的TSVREFE(内部基准)和VBATE(电池电压)位
    • 切换前需先停用ADC(HAL_ADC_DeInit
    • 重新初始化后恢复DMA传输
  2. 三通道配置

    • 使用PA0(通道0), PA1(通道1), PA2(通道2)
    • 扫描模式按顺序转换
    • DMA循环模式自动更新数据
  3. 电压模式枚举

typedef enum {
  EXTERNAL_VREF = 0,  // 使用外部参考电压
  INTERNAL_VREF = 1,  // 使用内部1.2V基准
  VBAT_VREF = 2       // 使用VBAT通道
} ADC_VrefType;

  1. 数据处理
    • 转换结果存储在adcBuffer数组
    • 索引0: 通道0数据
    • 索引1: 通道1数据
    • 索引2: 通道2数据

使用注意事项:

  1. 基准电压选择

    • 内部基准精度约±10mV,适合相对测量
    • 外部基准需保证稳定(推荐使用REF3030等专用基准源)
  2. 转换时间计算: 总转换时间 = $T_{\text{sample}} + T_{\text{conv}}$
    其中$T_{\text{sample}}=56$周期,$T_{\text{conv}}=12$周期(12位分辨率)

  3. 校准建议

// 在初始化后添加校准
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);

  1. 数据读取: 在DMA传输完成中断中或主循环直接访问adcBuffer获取最新值,无需手动触发转换。

实际应用时,请根据硬件连接修改通道配置(如使用PC0-PC2需改为ADC_CHANNEL_10-12),并确保参考电压引脚(VREF+)的硬件设计符合所选模式。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值