stm32hal库多路adc采样
时间: 2025-03-14 10:02:11 浏览: 37
### STM32 HAL库多路ADC采样配置教程
#### 1. 宏定义与全局变量初始化
为了支持多通道ADC采样并利用DMA进行数据传输,需先定义宏参数以及声明必要的全局变量。以下是基于引用中的代码片段:
```c
#define ADC1_CHANNEL_CNT 3 // 采样通道数
#define ADC1_CHANNEL_FRE 5 // 单个通道采样次数,用于取平均值
uint16_t adc1_val_buf[ADC1_CHANNEL_CNT * ADC1_CHANNEL_FRE]; // 存储原始采样数据
uint32_t adc1_aver_val[ADC1_CHANNEL_CNT]; // 计算后的平均采样值
uint16_t value[ADC1_CHANNEL_CNT]; // 最终处理结果
uint16_t dma_i = 0; // DMA索引计数器
```
上述代码通过`adc1_val_buf`存储每次DMA传输的数据,并通过`adc1_aver_val`保存每一路ADC的平均值。
---
#### 2. 初始化函数设置
在`MX_ADC_Init()`中完成ADC外设的基本配置,包括时钟源、分辨率、对齐方式等。具体如下:
```c
static void MX_ADC1_Init(void)
{
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; // 设置时钟分频
hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 设置分辨率为12位
hadc1.Init.ScanConvMode = ENABLE; // 启用扫描模式
hadc1.Init.ContinuousConvMode = DISABLE; // 禁用连续转换模式
hadc1.Init.DiscontinuousConvMode = DISABLE; // 禁用不连续转换模式
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; // 上升沿触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐
hadc1.Init.NbrOfConversion = ADC1_CHANNEL_CNT; // 转换序列长度等于通道数量
if (HAL_ADC_Init(&hadc1) != HAL_OK) {
Error_Handler();
}
}
```
此部分设置了ADC的工作模式为扫描模式[^1],并通过外部触发信号启动一次性的多通道采样过程。
---
#### 3. 配置DMA控制器
DMA负责将ADC采集到的数据自动转移到指定内存区域。以下是对DMA的具体配置:
```c
static void MX_DMA_Init(void)
{
__HAL_RCC_DMA2_CLK_ENABLE();
hdma_adc1.Instance = DMA2_Channel1;
hdma_adc1.Init.Request = DMA_REQUEST_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_HALFWORD; // 半字节对齐
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; // 半字节对齐
hdma_adc1.Init.Mode = DMA_CIRCULAR; // 循环模式
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH; // 高优先级
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK) {
Error_Handler();
}
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
for(uint8_t i=0;i<ADC1_CHANNEL_CNT;i++) {
adc1_aver_val[i] = 0;
for(uint8_t j=0;j<ADC1_CHANNEL_FRE;j++) {
adc1_aver_val[i] += adc1_val_buf[j + i * ADC1_CHANNEL_FRE];
}
adc1_aver_val[i] /= ADC1_CHANNEL_FRE; // 取平均值
value[i] = adc1_aver_val[i]; // 将最终结果存入value数组
}
dma_i++;
}
```
在此过程中,DMA被配置为循环模式以持续接收来自ADC的数据流[^2]。当DMA传输完成后,回调函数会计算各通道的平均值并将结果存储至`value[]`数组中。
---
#### 4. 主程序逻辑
最后,在主循环中调用相关功能模块来执行周期性操作:
```c
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
HAL_ADCEx_Calibration_Start(&hadc1); // 校准ADC
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc1_val_buf, ADC1_CHANNEL_CNT * ADC1_CHANNEL_FRE);
while (1){
OLED_Showdecimal(0,6,value[Rank5]*1000/4096*3.3/1000,1,3,16); // 显示第一个通道电压
OLED_Showdecimal(60,6,value[Rank6]*1000/4096*3.3/1000,1,3,16); // 显示第二个通道电压
HAL_Delay(1000);
}
}
```
以上代码实现了定时更新OLED显示屏上的实时电压数值。
---
###
阅读全文
相关推荐


















