STM32CubeMX教程15 ADC - 多重ADC转换

STM32CubeMX教程:配置多重ADC(二重/三重)与DMA数据传输
本文详细介绍了如何使用STM32CubeMX软件配置STM32F407开发板的ADC实现二重和三重ADC采集,包括配置步骤、DMA模式选择、数据处理以及烧录验证。重点讲解了如何通过CubeMX配置DMA传输,以及不同ADC模式下的数据结构和传输过程。

目录

1、准备材料

2、实验目标

3、二重ADC转换

3.0、前提知识

3.1、CubeMX相关配置

3.1.0、工程基本配置

3.1.1、时钟树配置

3.1.2、外设参数配置

3.1.3、外设中断配置

3.2、生成代码

3.2.0、配置Project Manager页面

3.2.1、外设初始化调用流程

3.2.2、外设中断调用流程

3.2.3、添加其他必要代码

4、常用函数

5、烧录验证

6、三重ADC转换

6.1、CubeMX相关配置

6.2、添加其他必要代码

6.3、实验现象

7、注释详解

8、参考资料


读者可访问 GitHub - lc-guo/STM32CubeMX-Series-Tutorial 获取原始工程代码


1、准备材料

开发板(正点原子stm32f407探索者开发板V2.4

STM32CubeMX软件(Version 6.10.0

野火DAP仿真器

keil µVision5 IDE(MDK-Arm

CH340G Windows系统驱动程序(CH341SER.EXE

XCOM V2.6串口助手

三个滑动变阻器

2、实验目标

使用STM32CubeMX软件配置STM32F407开发板的ADC实现多重ADC采集,具体为使用ADC1_IN5、ADC2_IN6实现二重ADC采集,使用ADC1_IN5、ADC2_IN6和ADC3_IN5实现三重ADC采集

3、二重ADC转换

3.0、前提知识

STM32F407的三个ADC可以组合实现多重ADC采集,当仅仅开启一个ADC时,该ADC只能工作在独立模式;当同时启动ADC1和ADC2,则以ADC1为主器件,ADC2为从器件可以工作在双重ADC采集模式下;当同时启动ADC1/2/3,则以ADC1为主器件,ADC2/3为从器件可以工作在三重ADC采集模式下;

在多重 ADC 模式下可实现① 二/三重注入同时模式 + 规则同时模式、② 二/三重规则同时模式 + 交替触发模式、③ 二/三重注入同时模式、④ 二/三重规则同时模式、⑤ 二/三重交替模式和⑥ 二/三重交替触发模式共6种模式

本实验我们只介绍二/三重规则同时模式,如下图所示为CubeMX配置中可选的所有模式

工作在多重ADC模式下的DMA请求拥有三种DMA模式,这里只介绍DMA access mode 1/2,不会涉及DMA access mode 3

二重规则同时模式ADC采集时只能选择DMA access mode 2,三重规则同时模式ADC采集时只能选择DMA access mode 1

下面请读者重点理解采集完成的数据是如何通过DMA存入用户定义好的数组中的!

当ADC工作在二重规则同时模式下,此时DMA模式为DMA access mode 2,在ADC1或ADC2转换事件结束时,会生成一个32位DMA传输请求,此请求会将存储在 ADC_CDR 32 位寄存器高位半字中的 ADC2 转换数据传输到SRAM,然后将存储在ADC_CCR低位半字中的ADC1转换数据传输到 SRAM,也就是说我们只需定义一个包含一个元素的uint32_t DataBuffer[1]数组,以DMA方式启动ADC转换后,只需每次从高16位读取ADC2采集的数据,从低16位读取ADC1采集的数据即可

当ADC工作在三重规则同时模式下,此时DMA模式为DMA access mode 1,在ADC1、ADC2或ADC3转换事件结束时,会生成三个32位DMA传输请求,之后会发生三次从 ADC_CDR 32 位寄存器到SRAM的传输:首先传输 ADC1 转换数据,然后是 ADC2 转换数据,最后是 ADC3 转换数据,也就是说我们需定义一个包含三个元素的uint32_t DataBuffer[3]数组,其中第一个元素DataBuffer[0]表示ADC1采集的数据,第二个元素DataBuffer[1]表示ADC2采集的数据,第三个元素DataBuffer[2]表示ADC3采集的数据

上述描述如下图所示(注释1)

如下图所示为多重ADC框图,当工作在二重ADC时不存在ADC3,ADC1/2/3三个ADC只有ADC1为主ADC,当以多重ADC工作时,只需要配置主ADC的DMA传输,从ADC无需设置,在启动多重ADC采集时也只能以DMA方式启动主ADC,从ADC以普通方式启动即可,不能将从ADC也以DMA方式启动,多重ADC采集的数据均会存入32位的通用规则数据寄存器中

3.1、CubeMX相关配置

3.1.0、工程基本配置

打开STM32CubeMX软件,单击ACCESS TO MCU SELECTOR选择开发板MCU(选择你使用开发板的主控MCU型号),选中MCU型号后单击页面右上角Start Project开始工程,具体如下图所示

开始工程之后在配置主页面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具体如下图所示

详细工程建立内容读者可以阅读“STM32CubeMX教程1 工程建立

3.1.1、时钟树配置

系统时钟使用8MHz外部高速时钟HSE,HCLK、PCLK1和PCLK2均设置为STM32F407能达到的最高时钟频率,具体如下图所示

3.1.2、外设参数配置

本实验需要需要初始化USART1作为输出信息渠道,具体配置步骤请阅读“STM32CubeMX教程9 USART/UART 异步通信

设置TIM3通用定时器溢出时间100ms,外部触发事件选择更新事件,参数详解请阅读“STM32CubeMX教程6 TIM 通用定时器 - 生成PWM波”实验,具体配置如下图所示

在Pinout & Configuration页面左边功能分类栏目Analog中单击其中ADC1,勾选IN5通道

 Mode (ADC模式):修改为Dual regular simultaneous mode only(需要启用ADC2通道才可以选择二重ADC采集模式)

 DMA Access Mode (DMA模式):选择DMA access mode 2

 DMA Continuous Requests (DMA连续转化请求):使能(需要先增加DMA请求才可以使能)

其他参数与“STM32CubeMX教程13 ADC - 单通道转换”实验均保持一致,具体配置如下图所示

单击Configuration中的DMA Settings选项卡对ADC1的DMA请求进行设置,所有配置均与“STM32CubeMX教程14 ADC - 多通道DMA转换”实验保持一致,具体配置如下图所示

在Pinout & Configuration页面左边功能分类栏目Analog中单击其中ADC2,勾选IN6通道,注意除 Rank  DMA Continuous Requests 参数外所有参数配置必须与ADC1保持一致,否则ADC采集将出现错误,具体配置如下图所示

3.1.3、外设中断配置

在Pinout & Configuration页面左边System Core/NVIC中勾选DMA2 Stream0 全局中断,然后选择合适的中断优先级即可,具体配置如下图所示

3.2、生成代码

3.2.0、配置Project Manager页面

单击进入Project Manager页面,在左边Project分栏中修改工程名称、工程目录和工具链,然后在Code Generator中勾选“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后单击页面右上角GENERATE CODE生成工程,具体如下图所示

详细Project Manager配置内容读者可以阅读“STM32CubeMX教程1 工程建立”实验3.4.3小节

3.2.1、外设初始化调用流程

请阅读“STM32CubeMX教程14 ADC - 多通道DMA转换”实验“3.2.1、外设初始化调用流程”小节

3.2.2、外设中断调用流程

请阅读“STM32CubeMX教程14 ADC - 多通道DMA转换”实验“3.2.2、外设中断调用流程”小节

3.2.3、添加其他必要代码

在adc.c中重新实现ADC转换完成回调函数HAL_ADC_ConvCpltCallback(),具体代码如下所示

源代码如下

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    /*定时器中断启动DMA二重ADC转换*/
    uint32_t Volt1,Volt2;
    uint32_t adcValue=DataBuffer[0];	

    /*从低16位取出ADC1采集数据*/
    uint32_t ADC1_val=adcValue & 0x0000FFFF;	
    Volt1=3300*ADC1_val;	
    Volt1=Volt1>>12;		
	
    /*从高16位取出ADC2采集数据*/
    uint32_t ADC2_val=adcValue & 0xFFFF0000;
    ADC2_val= ADC2_val>>16;
    Volt2=3300*ADC2_val;
    Volt2=Volt2>>12;		
    
    printf("Volt1:%d, Volt2:%d\r\n",Volt1,Volt2);
}

在主函数main中启动二重ADC转化,一些全局变量定义及启动源代码如下

/*main.c全局变量定义*/
uint32_t DataBuffer[BATCH_DATA_LEN];

/*main.h变量声明*/
#define BATCH_DATA_LEN 1
extern uint32_t DataBuffer[BATCH_DATA_LEN];

/*ADC启动代码*/
HAL_ADC_Start(&hadc2);
HAL_ADCEx_MultiModeStart_DMA(&hadc1,DataBuffer,BATCH_DATA_LEN);
HAL_TIM_Base_Start(&htim3);

为什么二重ADC转化下DMA要将数据传输到uint32 DataBuffer[1]?

二重ADC转化下DMA模式为DMA access mode 2,在该模式下ADC1转换完成的数据会传输到32位的 DataBuffer[0] 的低16位,而ADC2转换完成的数据会传输到32位的 DataBuffer[0] 的高16位

4、常用函数

/*多重ADC以DMA方式启动*/
HAL_StatusTypeDef HAL_ADCEx_MultiModeStart_DMA(ADC_HandleTypeDef *hadc, uint32_t *pData, uint32_t Length)

5、烧录验证

烧录程序,单片机上电之后,串口不断的输出ADC1_IN5、ADC2_IN6的采集值转化为的电压值,笔者将两个滑动变阻器按照ADC1_IN5、ADC2_IN6的顺序,分别从一端缓慢拧到另一端,可以从串口输出的数据看到,三个通道采集到的电压值从最小值0慢慢变到最大3300

6、三重ADC转换

6.1、CubeMX相关配置

在Pinout & Configuration页面左边功能分类栏目Analog中单击其中ADC3,勾选IN5通道,所有参数与二重ADC转换ADC2参数一致,在配置ADC1为三重ADC规则通道采集时ADC3的触发源参数会消失,因此无需理会,具体ADC3参数配置如下图所示

在Pinout & Configuration页面左边功能分类栏目Analog中单击其中ADC1,将其模式修改为Triple regular simultaneous mode only,DMA模式修改为DMA access mode 1

ADC1的其他参数与二重ADC转换时的参数一致,ADC2的配置、ADC1 DMA的配置和NVIC的设置均与二重ADC采集一致,具体ADC1参数配置如下图所示

6.2、添加其他必要代码

/*main.c全局变量定义*/
uint32_t DataBuffer[BATCH_DATA_LEN];

/*main.h变量声明*/
#define BATCH_DATA_LEN 3
extern uint32_t DataBuffer[BATCH_DATA_LEN];

/*主函数中ADC启动代码*/
HAL_ADC_Start(&hadc2);
HAL_ADC_Start(&hadc3);
HAL_ADCEx_MultiModeStart_DMA(&hadc1,DataBuffer,BATCH_DATA_LEN);
HAL_TIM_Base_Start(&htim3);

/*adc.c中重新实现转换完成中断回调*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    /*定时器中断启动DMA三重ADC转换*/
    uint32_t val=0,Volt=0;
    for(uint8_t i=0;i<BATCH_DATA_LEN;i++)
    {
        val=DataBuffer[i];
        Volt=(3300*val)>>12;
        printf("ADC%d, val:%d, Volt:%d\r\n",i,val,Volt);
    }
    printf("\r\n");
}

为什么三重ADC转化下DMA要将数据传输到uint32 DataBuffer[3]?

二重ADC转化下DMA模式为DMA access mode 1,在该模式下ADC1转换完成的数据会传输到32位的 DataBuffer[0],ADC2转换完成的数据会传输到32位的 DataBuffer[1],ADC3转换完成的数据会传输到32位的 DataBuffer[2]

6.3、实验现象

烧录程序,单片机上电之后,串口不断的输出ADC1_IN5、ADC2_IN6和ADC3_IN5的采集值,笔者将三个滑动变阻器按照ADC1_IN5、ADC2_IN6和ADC3_IN5的顺序,分别从一端缓慢拧到另一端,可以从串口输出的数据看到,三个通道采集到的ADC数据从最小值0慢慢变到最大4095

7、注释详解

注释1:图片来源STM32F4xx中文参考手册

8、参考资料

主要参考STM32Cube高效开发教程(基础篇)320页14.6小节实验

笔者认为该章节提到一个BUG其实是错误的,从ADC不应该以DMA方式启动,也无需在STM32CubeMX生成的工程代码中手动修改DMAContinuousRequests为ENABLE

<think>首先,用户的问题是基于系统级指令和之前的上下文。系统级指令要求: - 所有行内数学表达式使用 `$...$` 格式。 - 独立公式使用 `$$...$$` 格式并单独成段。 - LaTeX 语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如 `[^1]`。 用户的问题是:“我想查找使用STM32H7 HAL库进行ADC多通道采集的相关资料 请问STM32H7 HAL库实现ADC多通道采集的方法和示例” 用户提供了引用: - 引用 [1] 提到了野火开源学习资料、Bilibili视频、优快云博客等资源,涉及ADC多通道采集的阻塞模式、DMA模式CubeMX配置等。 - 引用 [2] 讨论了STM32F407的ADC多重工作模式ADC同步触发,DMA数据传输等。 - 引用 [3] 是基于STM32F407的adc-tim-dma配置,使用HAL库。 - 引用 [4] 展示了一个HAL_ADC_Start_DMA的使用示例,处理ADC结果。 用户指定了“参考站内引用”,所以我需要在回答中整合这些引用。引用不是用户真正的需求,只是参考资料;用户真正的问题是查找STM32H7 HAL库ADC多通道采集的方法和示例。 我的回答结构需要: 1. 回答清晰,逐步解决问题。 2. 使用中文。 3. 生成相关问题。 4. 在引用段落末尾添加引用标识。 回答应该包括: - 简介STM32H7 HAL库ADC多通道采集的基本概念。 - 方法和步骤:基于引用,描述如何配置和使用,包括CubeMX设置、HAL库函数调用。 - 示例代码:提供一个简单的示例,使用HAL库实现ADC多通道采集。 - 添加上引用标识。 最后,生成相关问题。 关键点: - STM32H7和引用中的STM32F407类似,但可能有差异。我应该基于通用HAL库方法,但指定STM32H7。 - 引用[4]提供了一个示例代码片段:使用HAL_ADC_Start_DMA处理结果。 - 引用[1]提到CubeMX配置、阻塞模式和DMA模式- 引用[2]讨论多重ADC模式,但用户指定STM32H7,我需要适配。 方法步骤: 1. **CubeMX配置**:配置ADC、DMA(如果使用DMA)、定时器(如果需要触发)。 2. **HAL库函数调用**:初始化ADC,启动采集,使用DMA传输数据。 3. **数据处理**:转换ADC结果到电压值。 示例代码:基于引用[4],扩展为一个多通道采集的简单示例。 生成相关问题:例如,关于ADC校准、DMA中断处理、实时应用等。 回答结构: - 开头简要介绍。 - 分步骤解释方法。 - 提供示例代码。 - 添加引用标识。 - 生成相关问题。 确保LaTeX使用正确:如果有数学表达式,如计算电压值 `$value = \frac{result}{4096} \times 3.3$`,用于12位ADC,但STM32H7可能不同,需指定。 STM32H7 ADC通常16位或更高分辨率,但具体看配置。 </think>### STM32H7 HAL库实现ADC多通道采集的方法与示例 STM32H7微控制器支持高级模拟数字转换器(ADC),通过HAL库可以轻松实现多通道采集。ADC多通道采集允许同时读取多个模拟信号源(如传感器输入),这在实时数据采集系统中非常实用。实现方式主要包括阻塞模式(轮询)和DMA模式(直接内存访问),其中DMA模式更高效,减少CPU负载。下面我将基于HAL库,结合STM32CubeMX配置和代码示例,逐步说明方法和实现步骤。相关引用资源已整合,确保内容可靠。 #### 步骤1: STM32CubeMX配置 使用STM32CubeMX工具配置ADC和DMA是关键的第一步。STM32H7的ADC模块支持多通道扫描模式,且通过DMA实现数据异步传输。 - **ADC配置**:开启ADC(如ADC1),设置多通道扫描模式。在“Analog”标签下,选择ADC通道(如CH0、CH1、CH2),配置采样时间(例如15个时钟周期)、分辨率(STM32H7支持16位,但通常设为12位以平衡速度与精度),并启用“Scan Conversion Mode”和“Continuous Conversion Mode”[^1][^4]。 - **DMA配置**:在“DMA Settings”标签下,添加DMA请求。选择ADC通道对应的DMA流(如DMA1或DMA2),设置工作模式为“Circular”(循环模式)以确保连续采集,数据宽度设为“Word”(32位,适用于多通道数据),优先级设为“High”[^1][^2][^4]。 - **时钟与触发源**:如果需要定时器触发(如用于同步采样),在“TIM”标签配置定时器(如TIM1),并在ADC设置中选择“Timer Trigger”作为外部触发源。STM32H7的时钟配置需确保ADC工作在合适频率(例如ADC时钟设为PLL2时钟分频)[^1][^3]。 - **生成代码**:完成配置后,生成HAL库初始化代码(使用LLVM/Keil IDE)。CubeMX自动生成`adc.c`和`dma.c`文件,包含初始化函数(如`MX_ADC1_Init()`)[^1][^4]。 > **注意**:STM32H7的ADCSTM32F407类似,但H7系列支持更高分辨率和更多通道。重或三重ADC模式可进一步同步采集多个信号,但本示例简化为主ADC多通道DMA模式[^2]。 #### 步骤2: HAL库函数调用与代码实现 在生成的代码基础上,编写主程序逻辑。主要包括ADC初始化、启动DMA传输、以及数据处理回调函数。以下是关键HAL库函数: - **初始化**:调用`HAL_ADC_Start_DMA()`启动ADC和DMA。 - **数据处理**:使用DMA传输完成后中断(或轮询)读取数据。STM32H7的ADC结果寄存器为16位,但DMA传输通常以32位字形式处理多通道数据。 - **电压转换**:将ADC原始值转换为电压:`$value = \frac{result \times V_{ref}}{2^{resolution} - 1}$`,其中`$V_{ref}$`是参考电压(通常3.3V),resolution是ADC分辨率(例如12位时为4096)[^4]。 下面是一个完整的STM32H7 HAL库ADC多通道采集示例(基于DMA模式),适用于3个通道(CH0、CH1、CH2): ```c #include "main.h" #include "adc.h" #include "dma.h" // 定义全局变量 ADC_HandleTypeDef hadc1; // CubeMX生成的ADC句柄 DMA_HandleTypeDef hdma_adc1; // CubeMX生成的DMA句柄 volatile uint32_t adc_buffer[3]; // 存储3个通道的ADC结果数组(每个通道一个值) // ADC和DMA初始化(CubeMX自动生成,一般不需修改) void SystemInit(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); MX_ADC1_Init(); // 初始化ADC1 } // 启动ADC采集 void Start_ADC_Conversion(void) { // 启动DMA传输:hadc1为ADC句柄,adc_buffer为数据缓冲区,3表示采集3个通道 if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, 3) != HAL_OK) { Error_Handler(); // 错误处理 } } // DMA传输完成中断回调函数(CubeMX配置DMA中断后自动调用) void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if (hadc->Instance == ADC1) { // 处理ADC数据:转换为电压值 float voltage_ch0 = (float)(adc_buffer[0] & 0xFFF) * 3.3f / 4095.0f; // 假设resolution=12位 float voltage_ch1 = (float)(adc_buffer[1] & 0xFFF) * 3.3f / 4095.0f; float voltage_ch2 = (float)(adc_buffer[2] & 0xFFF) * 3.3f / 4095.0f; // 此处可添加数据处理逻辑(如通过UART输出) } } // 主函数 int main(void) { SystemInit(); Start_ADC_Conversion(); // 启动采集 while (1) { // 主循环可执行其他任务,DMA在后台自动更新adc_buffer HAL_Delay(100); // 示例:每100ms执行其他操作 } } ``` **代码说明**: - **DMA模式**:`HAL_ADC_Start_DMA()`函数启动异步传输,ADC结果直接存入`adc_buffer`缓冲区,无需CPU干预。通道顺序需与CubeMX配置一致(如索引0对应CH0)[^4]。 - **中断处理**:`HAL_ADC_ConvCpltCallback()`在DMA传输完成后触发,用于实时处理数据。STM32H7支持高优先级中断,确保低延迟[^1][^3]。 - **电压计算**:公式 `$value = \frac{result \times 3.3}{4095}$` 将12位ADC原始值转换为电压(单位为V)。如果设置分辨率不同,需调整分母(例如16位时为65535)[^4]。 - **优化**:使用循环缓冲区可处理更多数据点;若需定时器触发ADC,在CubeMX中添加TIM配置并调用`HAL_TIM_Base_Start()`[^1][^3]。 #### 常见问题与调试建议 - **校准**:ADC精度受温度影响,建议在初始化后调用`HAL_ADCEx_Calibration_Start()`进行校准,参考STM32H7参考手册[^1][^4]。 - **性能优化**:STM32H7的ADC支持过采样和硬件平均,可提升信噪比。在CubeMX中启用“Oversampling”选项[^2]。 - **错误处理**:检查`HAL_ADC_Start_DMA()`返回值,确保DMA和ADC时钟配置正确(例如STM32H7的ADC时钟最大频率为60MHz)[^1][^3]。 #### 参考资源总结 本方法基于HAL库通用实现,STM32H7与STM32F407类似,但H7系列提供更高性能。详细配置可参考优快云博客和视频教程- CubeMX配置步骤:参见引用[1]中的操作详解,特别是针对ADC多通道的DMA模式[^1]。 - DMA数据传输逻辑:引用[2]解释了ADC模式下DMA工作方式(模式2),可直接适配STM32H7[^2]。 - 完整项目示例:引用[3]和[4]提供了adc-tim-dma的HAL库实现,包括代码片段和数据处理[^3][^4]。 ### 相关问题 1. 如何在STM32H7中使用定时器触发ADC采集以实现同步采样? 2. STM32H7的ADC校准有哪些注意事项和方法? 3. ADC多通道采集时,如何处理DMA中断冲突或数据溢出问题? [^1]: 参见野火开源学习资料和优快云博客,专注于CubeMX配置和ADC多通道模式。 [^2]: 参考STM32F407 ADC多重工作模式描述,适用STM32H7模式。 [^3]: 基于STM32F407的adc-tim-dma教程,可拓展到STM32H7。 [^4]: HAL_ADC_Start_DMA函数使用示例。
评论 13
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OSnotes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值