STM32 HAL库 STM32CubeMX -- ADC

这篇具有很好参考价值的文章主要介绍了STM32 HAL库 STM32CubeMX -- ADC。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、ADC 简介

ADC(Analog-to-Digital Converter)指模/数转换器或者模拟/数字转换器。 是指将连续变量的模拟信号转换为离散的数字信号的器件。

也就是将模拟信号转化为数字信号

STM32f103 系列有3 个ADC,精度为12 位,每个ADC 最多有16 个外部通道和2个内部信号源。其中ADC1 和ADC2 都有16 个外部通道,ADC3 根据CPU 引脚的不同通道数也不同,一般都有8 个外部通道。

各通道的A/D转换可以单次、连续、扫描或间断模式执行。

ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。

二、ADC功能框图

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

电压输入范围

ADC 输入范围为:VREF- ≤ VIN ≤ VREF+。
由VREF-、VREF+ 、VDDA 、VSSA、这四个外部引脚决定。
一般把VSSA 和VREF- 接地,把VREF+ 和VDDA 接3V3,得到ADC 的输入电压范围为:0~3.3V。

如果想让输入的电压范围变宽,去到可以测试负电压或者更高的正电压,我们可以在外部加一个电压调理电路,把需要转换的电压抬升或者降压到0~3.3V,这样ADC 就可以测量了。

输入通道

STM32的ADC 多达18 个通道,其中外部的16 个通道就是框图中的ADCx_IN0、ADCx_IN1 ⋯ ADCx_IN5。

这16 个通道对应着不同的IO 口,具体是哪一个IO 口可以从手册查询到。

其中ADC1/2/3 还有内部通道
ADC1 的通道16 连接到了芯片内部的温度传感器,Vrefint 连接到了通道17。
ADC2 的模拟通道16 和17 连接到了内部的VSS。
ADC3 的模拟通道9、14、15、16 和17 连接到了内部的VSS。

STM32F103ZET6 ADC IO 分配 :

ADC1 IO ADC2 IO ADC3 IO
通道0 PA0 通道0 PA0 通道0 PA0
通道1 PA1 通道1 PA1 通道2 PA1
通道2 PA2 通道2 PA2 通道2 PA2
通道3 PA3 通道3 PA3 通道3 PA3
通道4 PA4 通道4 PA4 通道4 PF6
通道5 PA5 通道5 PA5 通道5 PF7
通道6 PA6 通道6 PA6 通道6 PF8
通道7 PA7 通道7 PA7 通道7 PF9
通道8 PB0 通道8 PB0 通道8 PF10
通道9 PB1 通道9 PB1 通道9 连接内部VSS
通道10 PC0 通道10 PC0 通道10 PC0
通道11 PC1 通道11 PC1 通道11 PC1
通道12 PC2 通道12 PC2 通道12 PC2
通道13 PC3 通道13 PC3 通道13 PC3
通道14 PC4 通道14 PC4 通道14 连接内部VSS
通道15 PC5 通道15 PC5 通道15 连接内部VSS
通道16 连接内部温度传感器 通道16 连接内部VSS 通道16 连接内部VSS
通道17 连接内部Vrefint 通道17 连接内部VSS 通道17 连接内部VSS

外部的16 个通道在转换的时候又分为规则通道注入通道,其中规则通道最多有16 路,注入通道最多有4 路。

规则通道
普通通道,大部分时候都用这个。

注入通道
注入,可以理解为插入,插队的意思。它是一种在规则通道转换的时候强行插入要转换的一种通道
如果在规则通道转换过程中,有注入通道插队,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程。

转换顺序

规则序列

规则序列寄存器有3 个,分别为SQR3、SQR2、SQR1。

SQR3 控制着规则序列中的第一个到第六个转换,对应的位为:SQ1[4:0] ~ SQ6[4:0],第一次转换的是位4:0 SQ1[4:0],如果通道16 想第一次转换,那么在SQ1[4:0] 写16 即可。

SQR2 控制着规则序列中的第7 到第12 个转换,对应的位为:SQ7[4:0] ~ SQ12[4:0],如果通道1 想第8 个转换,则SQ8[4:0] 写1 即可。

SQR1 控制着规则序列中的第13 到第16 个转换,对应位为:SQ13[4:0] ~ SQ16[4:0],如果通道6 想第10 个转换,则SQ10[4:0] 写6 即可。

具体使用多少个通道,由SQR1 的位L[3:0] 决定,最多16 个通道。

寄存器 寄存器位 功能 取值
SQR3 SQ1[4:0] 设置第1个转换的通道 通道1 ~ 16
SQR3 SQ2[4:0] 设置第2个转换的通道 通道1 ~ 16
SQR3 SQ3[4:0] 设置第3个转换的通道 通道1 ~ 16
SQR3 SQ4[4:0] 设置第4个转换的通道 通道1 ~ 16
SQR3 SQ5[4:0] 设置第5个转换的通道 通道1 ~ 16
SQR3 SQ6[4:0] 设置第6个转换的通道 通道1 ~ 16
SQR2 SQ7[4:0] 设置第7个转换的通道 通道1 ~ 16
SQR2 SQ8[4:0] 设置第8个转换的通道 通道1 ~ 16
SQR2 SQ9[4:0] 设置第9个转换的通道 通道1 ~ 16
SQR2 SQ10[4:0] 设置第10个转换的通道 通道1 ~ 16
SQR2 SQ11[4:0] 设置第11个转换的通道 通道1 ~ 16
SQR2 SQ12[4:0] 设置第12个转换的通道 通道1 ~ 16
SQR1 SQ13[4:0] 设置第13个转换的通道 通道1 ~ 16
SQR1 SQ14[4:0] 设置第14个转换的通道 通道1 ~ 16
SQR1 SQ15[4:0] 设置第15个转换的通道 通道1 ~ 16
SQR1 SQ16[4:0] 设置第16个转换的通道 通道1 ~ 16
SQR1 SQL[3:0] 需要转换多少个通道 通道1 ~ 16

注入序列

注入序列寄存器JSQR 只有一个,最多支持4 个通道,具体多少个由JSQR 的JL[2:0] 决定。

如果JL 的值小于4 的话,则JSQR 跟SQR 决定转换顺序的设置不一样,第一次转换的不是JSQR1[4:0],而是JCQRx[4:0] ,x = (4-JL),跟SQR 刚好相反。

如果JL=00(1 个转换),那么转换的顺序是从JSQR4[4:0] 开始,而不是从JSQR1[4:0] 开始,这个要注意,编程的时候不要搞错。当JL 等于4 时,跟SQR 一样。

寄存器 寄存器位 功能 取值
JSQR JSQ1[4:0] 设置第1个转换的通道 通道 1 ~ 4
JSQR JSQ2[4:0] 设置第2个转换的通道 通道 1 ~ 4
JSQR JSQ3[4:0] 设置第3个转换的通道 通道 1 ~ 4
JSQR JSQ4[4:0] 设置第4个转换的通道 通道 1 ~ 4
JSQR JL[1:0] 需要转换多少个通道 通道 1 ~ 4

触发源

ADC 转换可以由ADC 控制寄存器2: ADC_CR2 的ADON 这个位来控制,写1 的时候开始转换,写0 的时候停止转换;

ADC 还支持触发转换,内部定时器触发和外部IO 触发
触发源有很多,具体选择哪一种触发源,由ADC 控制寄存器2:ADC_CR2 的EXTSEL[2:0] 和JEXTSEL[2:0] 位来控制。
EXTSEL[2:0] 用于选择规则通道的触发源,JEXTSEL[2:0] 用于选择注入通道的触发源。

选定好触发源之后,由ADC 控制寄存器2:ADC_CR2 的EXTTRIG 和JEXTTRIG 这两位来激活ADC。

其中ADC3 的规则转换和注入转换的触发源与ADC1/2的有所不同。

转换时间

ADC 时钟

ADC 输入时钟ADC_CLK 由PCLK2 经过分频产生,最大是14M,分频因子由RCC 时钟配置寄存器RCC_CFGR 的位15:14 ADCPRE[1:0] 设置,可以是2/4/6/8 分频,注意这里没有1 分频。一般我们设置PCLK2=HCLK=72M

采样时间

ADC 使用若干个ADC_CLK 周期对输入的电压进行采样,采样的周期数可通过ADC 采样时间寄存器ADC_SMPR1 和ADC_SMPR2 中的SMP[2:0] 位设置,ADC_SMPR2 控制的是通道0 ~ 9,ADC_SMPR1 控制的是通道10~17。
每个通道可以分别用不同的时间采样。其中采样周期最小是1.5 个,即如果我们要达到最快的采样,那么应该设置采样周期为1.5 个周期,这里说的周期就是1/ADC_CLK。

ADC 的转换时间跟ADC 的输入时钟和采样时间有关,公式为:Tconv = 采样时间+ 12.5 个周期

当ADCLK = 14MHZ(最高),采样时间设置为1.5 周期(最快),那么总的转换时间(最短)Tconv = 1.5 周期+ 12.5 周期= 14 周期= 1us。
一般我们设置PCLK2=72M,经过ADC 预分频器能分频到最大的时钟只能是12M,采样周期设置为1.5 个周期,算出最短的转换时间为1.17us,这个才是最常用的。

数据寄存器

一切准备就绪后,ADC 转换后的数据根据转换组的不同,规则组的数据放在ADC_DR 寄存器,注入组的数据放在JDRx。

规则数据寄存器
ADC 规则组数据寄存器ADC_DR 只有一个,是一个32 位的寄存器,低16 位在单ADC 时使用,高16 位是在ADC1 中双模式下保存ADC2 转换的规则数据,双模式就是ADC1 和ADC2 同时使用。

在单模式下,ADC1/2/3 都不使用高16 位。因为ADC 的精度是12 位,无论ADC_DR 的高16 或者低16 位都放不满,只能左对齐或者右对齐,具体是以哪一种方式存放,由ADC_CR2 的11 位ALIGN 设置。

规则通道可以有16 个这么多,可规则数据寄存器只有一个,如果使用多通道转换,那转换的数据就全部都挤在了DR 里面,前一个时间点转换的通道数据,就会被下一个时间点的另外一个通道转换的数据覆盖掉,所以当通道转换完成后就应该把数据取走,或者开启DMA 模式,把数据传输到内存里面,不然就会造成数据的覆盖。

对于多通道采集这里提出三个解决办法:
(1)使用间断模式,采集一个存储一个
(2)使用中断,采集到一个数据,进入中断,把这个数据保存
(3)使用DMA,直接将采集到的数据搬运到内存

注入数据寄存器

ADC 注入组最多有4 个通道,刚好注入数据寄存器也有4 个,每个通道对应着自己的寄存器,不会跟规则寄存器那样产生数据覆盖的问题。ADC_JDRx 是32 位的,低16 位有效,高16 位保留,数据同样分为左对齐和右对齐,具体是以哪一种方式存放,由ADC_CR2 的11 位ALIGN 设置。

中断

转换结束中断

数据转换结束后,可以产生中断,中断分为三种:规则通道转换结束中断,注入转换通道转换结束中断,模拟看门狗中断。

其中转换结束中断很好理解,跟我们平时接触的中断一样,有相应的中断标志位和中断使能位,我们还可以根据中断类型写相应配套的中断服务程序。

模拟看门狗中断

当被ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断,前提是我们开启了模拟看门狗中断,其中低阈值和高阈值由ADC_LTR 和ADC_HTR 设置。

例如我们设置高阈值是2.5V,那么模拟电压超过2.5V 的时候,就会产生模拟看门狗中断,反之低阈值也一样。

DMA 请求

规则和注入通道转换结束后,除了产生中断外,还可以产生DMA 请求,把转换好的数据直接存储在内存里面。

要注意的是只有ADC1 和ADC3 可以产生DMA 请求。

一般我们在使用ADC 的时候都会开启DMA 传输。

电压转换

模拟电压经过ADC 转换后,是一个12 位的数字值,如果通过串口以16 进制打印出来的话,可读性比较差,那么有时候我们就需要把数字电压转换成模拟电压,也可以跟实际的模拟电压(用万用表测)对比,看看转换是否准确。

我们一般在设计原理图的时候会把ADC 的输入电压范围设定在:0~3.3v,因为ADC 是12 位的,那么12 位满量程对应的就是3.3V,12 位满量程对应的数字值是:2^12。数值0 对应的就是0V。

如果转换后的数值为X ,X 对应的模拟电压为Y,那么会有这么一个等式成立: 2^12 / 3.3 = X/ Y,=> Y = (3.3 * X ) / 2^12。

三、STM32Cube MX配置

基础STM32Cube MX的配置可以参考这篇博客:STM32 CubeMx教程 – 基础知识及配置使用教程

配置RCC,选择使用外部晶振模式

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

配置SYS,debug配置为Serial Wire

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

配置一个串口,使用异步通信模式

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

ADC界面:

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

IN0~IN15: 16路12位ADC采样通道,外部模拟量信号输入

Temperature Sensor Channel: MCU内置温度传感器采样通道,用来测量器件周围的温度。在MCU内部与ADC1_IN16通道相连

Vrefint Channel: 内部参考电压检测通道,ADC 的参考电压都是通过 Vref+ 引脚提供的并作为ADC转换器的基准电压,当Vref+直接取自VDD电压时,易受VDD波动而影响,因此可以该通道对参考电压进行校准,以提升ADC计算精度。在MCU内部与ADC1_IN17通道相连

EXTI Conversion Trigger: 外部触发转换。
ADC转换可由外部事件触发,EXTSEL[2:0]和JEXTSEL[2:0]控制位允许应用程序选择8个可能的事件中的某一个,触发规则通道组合注入通道组的采样。这里若选择Disable,则可以在6个来自片上定时器的内部信号中选择一个作为触发源;
若选择Injected Trigger/Regular Trigger/Injected and Regular Trigger,表示由外部引脚信号触发相应的通道组。

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

ADCs_Common_Settings:(ADC模式设置)

Mode:Independent mode
独立模式。此模式中,双ADC同步不工作,ADC1和ADC2相互独立工作。
如果不需要ADC同步或者只是用了一个ADC的时候,应该设成独立模式,多个ADC同时使用时会有其他模式,如双重ADC同步模式,两个ADC同时采集一个或多个通道,可以提高采样率。对应ADC控制寄存器1(ADC_CR1)中的DUALMOD[3:0]位。

ADC_Settings:(ADC设置)

Data Alignment:(数据对齐方式)
数据左对齐/右对齐,一般选择使用右对齐。

Scan Conversion Mode:(扫描模式)
扫描模式使能。对应ADC控制寄存器1(ADC_CR1)中的SCAN位。
如果只是用了一个通道的话,设置为DISABLE;
如果使用了多个通道的话,可以选择设置ENABLE或者DISABLE;(后面结合具体场景介绍)

Continuous Conversion Mode:(连续转换模式)
数据的连续转换,对应ADC控制寄存器2(ADC_CR2)中的CONT位。
设置为ENABLE,即使能连续转换;设置为DISABLE,则是单次转换。
两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以进行转换

Discontinuous Conversion Mode:(间断模式)
间断模式,对应ADC控制寄存器1(ADC_CR1)中的DISCEN位。
如果单通道不需要采用间断,多通道具体分析,后面示例中具体介绍

ADC_Regular_ConversionMode:规则通道组采样设置

Enable Regular Conversions:(常规转换模式)
使能规则通道组转换。

Number of Conversion:(转换通道数量)
规则通道组序列长度为3,即包含3个采样通道。

External Trigger Conversion Source:(外部触发转换源)
选择外部触发源,
Regular Conversion launched by software 规则的软件触发 调用函数触发
Timer X Capture Compare X event 外部引脚触发,
Timer X Trigger Out event 定时器通道输出触发
stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

Rank:ADC转换通道顺序
当使用多通道采集的时候,可以在这里设置每个通道采集的先后顺序

ADC_Injected_ConversionMode:注入通道设置
参数和上面的规则通道一样;
需要注意的是,注入通道的功能和规则通道的一样,但是注入通道的优先级要比规则通道的高;

WatchDog: 模拟看门狗中断

四、应用示例

涉及到的HAL库函数


开启ADC 3种模式 ( 轮询模式 中断模式 DMA模式 )

• HAL_ADC_Start(&hadcx);       //轮询模式开启ADCHAL_ADC_Start_IT(&hadcx);       //中断轮询模式开启ADCHAL_ADC_Start_DMA(&hadcx);       //DMA模式开启ADC

关闭ADC 3种模式 ( 轮询模式 中断模式 DMA模式 )

• HAL_ADC_Stop()HAL_ADC_Stop_IT()HAL_ADC_Stop_DMA()

ADC校准函数 :

• HAL_ADCEx_Calibration_Start(&hadcx);      //F4系列不支持

读取ADC转换值

• HAL_ADC_GetValue()

等待转换结束函数

• HAL_ADC_PollForConversion(&hadc1, 50);

第一个参数为那个ADC,第二个参数为最大等待时间

ADC中断回调函数
• HAL_ADC_ConvCpltCallback()

转换完成后回调,DMA模式下DMA传输完成后和中断中调用

规则通道及看门狗配置

• HAL_ADC_ConfigChannel() 配置规则组通道
• HAL_ADC_AnalogWDGConfig(

结合ADC的不同传输办法;
这里给出六个例子

(1)单通道数据采集
(2)多通道间断模式轮询采集
(3)多通道中断采集
(4)多通道定时器中断采集
(5)多通道DMA采集
(6)多通道定时器MDA采集

如果使用串口打印数据,要记得串口重定向,参考这两篇博客:
STM32 HAL库 STM32CubeMx – 串口的使用(USART/UART)
STM32 HAL库 使用printf函数 Use MicroLIB配置

(1)单通道数据采集

在STM32 Cube MX里面配置一个通道IN1;
ADC采集模式设置为独立模式;
数据设置为右对齐模式;
由于只有单通道,数据都是一个通道的,设置为连续转换模式;
由于只有一个通道,下面的规则通道设置,rank顺序设置可以不用管;

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
	/* 单通道 数据定义 */
	uint16_t ADC_value;		//ADC采集到的数据	
	float  volt_value;	//电压值
	
/* USER CODE END PD */
/* USER CODE BEGIN 1 */

/* 自定义的数据采集函数,需要在.h 函数里面声明 */
/* 自定义了一个数据采集函数,我放到了adc.c 里面,放到main.c里面也行*/
uint16_t ADC_X_Get()
	{
		HAL_ADC_Start(&hadc1);     //启动ADC转换
		HAL_ADC_PollForConversion(&hadc1, 50);   //等待转换完成,50为最大等待时间,单位为ms
 
		if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
		{
			return(HAL_ADC_GetValue(&hadc1));	//返回ADC的值
		}
		return 0;
	}

/* USER CODE END 1 */
  while (1)
  {
		
		/* 单通道数据采集 + 连续转换模式 */
		/* 在主函数中采集数据,并且输出数据 */		
		ADC_value = ADC_X_Get();
		volt_value = ADC_value*3.3f/4096; //内部电压转换公式
		
		printf("ADC read value : %d \r\n",ADC_value);
		printf("change voltage value : %.4f \r\n",volt_value);
		HAL_Delay(1000);
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

(2)多通道间断模式轮询采集

STM32Cube MX里面配置了五个通道;
设置为独立模式;
在规则通道设置里面,设置5个通道;
可以在Rank里面设置每个通道采集的顺序;
由于是多通道数据采集,必须使能扫描模式

如果不使用中断 DMA,要想采集到多通道的数据,可以采用间断模式
所以使能间断模式;
stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件
stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */	
	/* 多通道 间断 轮询模式 数据定义 */
	#define ADC_value_max 5 	//五通道数据
	uint16_t ADC_value[ADC_value_max] = {0};		//ADC采集数值
	float  volt_value;		//电压值
	float  tem_value;		//温度值
/* USER CODE END PD */
/* USER CODE BEGIN 1 */

/* 自定义的数据采集函数,需要在.h 函数里面声明 */
/* 自定义了一个数据采集函数,我放到了adc.c 里面,放到main.c里面也行*/
uint16_t ADC_X_Get()
	{
		HAL_ADC_Start(&hadc1);     //启动ADC转换
		HAL_ADC_PollForConversion(&hadc1, 50);   //等待转换完成,50为最大等待时间,单位为ms
 
		if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
		{
			return(HAL_ADC_GetValue(&hadc1));	//返回ADC的值
		}
		return 0;
	}

/* USER CODE END 1 */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	HAL_ADCEx_Calibration_Start(&hadc1);    //ADC校准
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {		
		/* 多通道数据采集 + 扫描模式 + 间断模式 */
		for(uint8_t i=0;i<5;i++)
		{
		ADC_value[i] = ADC_X_Get();			//获取ADC采集到的值
		}
		volt_value = ADC_value[3]*3.3f/4096; //内部电压转化公式
		tem_value = (1.43 - ADC_value[4]*3.3f/4096) / 0.0043 + 25;		//内部温度转换公式
		
		printf("ADC value 0 : %d \r\n",ADC_value[0]);
		printf("volt  : %.4f \r\n",volt_value);
		printf("tem : %.2f \r\n",tem_value);
		HAL_Delay(1000);
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

(3)多通道中断采集

STM32Cube MX里面配置了五个通道;
设置为独立模式;
在规则通道设置里面,设置5个通道;
可以在Rank里面设置每个通道采集的顺序;
由于是多通道数据采集,必须使能扫描模式

为了采集到多通道的数据,这里使用的办法是使用中断
配置使能连续转换模式,配置打开ADC中断;
这里触发中断的方式是软件触发,也就是ADC每转化一次触发一次中断;(这样会很浪费资源)

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件
stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件
打开中断
stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
	/* 多通道 中断 数据定义 */
	/* 用到全局变量,所以在main.h里面声明 */
	uint16_t ADC_value[ADC_value_max] = {0};		//ADC采集数值
	uint8_t ADC_value_flag = 0;		//ADC标志位
	float  volt_value;	//电压值
	float  tem_value;		//温度值
/* USER CODE END PD */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
#define ADC_value_max 5 //3组ADC,每组最多存储5个值

extern uint16_t ADC_value[ADC_value_max];		//ADC采集数值
extern uint8_t ADC_value_flag;		//ADC标志位
/* USER CODE END ET */
/* USER CODE BEGIN 1 */

/* ADC转换完成之后,触发ADC中断 */
/* 为了方便归类,这里我把ADC处理函数放在了adc.c里面 */
/* 如果要更改一些数值,需要将变量设置为全局变量 */	
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{    
   ADC_value[ADC_value_flag++]=HAL_ADC_GetValue(hadc);		 //获取值并存储
 
   if(ADC_value_flag == ADC_value_max) //最大值的下一位
    {
         ADC_value_flag=0;//清零下标
    } 
}

/* USER CODE END 1 */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	HAL_ADCEx_Calibration_Start(&hadc1);    //ADC校准
	
	HAL_ADC_Start_IT(&hadc1);		//开启ADC中断
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		/* 多通道采集 + 扫描模式 + 连续转换模式 + 中断 */
		volt_value = ADC_value[3]*3.3f/4096;
		tem_value = (1.43 - ADC_value[4]*3.3f/4096) / 0.0043 + 25;
		
		printf("tem : %.2f \r\n",tem_value);
		printf("demo1 : %d \r\n",ADC_value[4]);
		printf("volt  : %.4f \r\n",volt_value);
		HAL_Delay(1000);
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

(4)多通道定时器中断采集

由于直接使用中断,每采集一次数据,就会进入中断一次,比较浪费资源,所以这里介绍,定时器触发中断采集数据;

STM32Cube MX里面配置了五个通道;
设置为独立模式;
在规则通道设置里面,设置5个通道;
可以在Rank里面设置每个通道采集的顺序;
由于是多通道数据采集,必须使能扫描模式

为了采集到多通道的数据,这里使用的办法是使用中断
配置使能连续转换模式,配置打开ADC中断;
这里触发中断的方式是定时器触发,也就是定时器没溢出一次触发一次中断;

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

配置一个定时器,使用内部时钟,自动重装载值,配置为触发事件更新

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

设置为定时器3 外部事件触发

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件
打开定时器的中断

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
	/* 多通道 中断 数据定义 */
	/* 用到全局变量,所以在main.h里面声明 */
	uint16_t ADC_value[ADC_value_max] = {0};		//ADC采集数值
	uint8_t ADC_value_flag = 0;		//ADC标志位
	float  volt_value;	//电压值
	float  tem_value;		//温度值
/* USER CODE END PD */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
#define ADC_value_max 5 //3组ADC,每组最多存储5个值

extern uint16_t ADC_value[ADC_value_max];		//ADC采集数值
extern uint8_t ADC_value_flag;		//ADC标志位
/* USER CODE END ET */
/* USER CODE BEGIN 1 */

/* 定时器回调函数,定时器溢出以后触发回调函数 */
/* 在定时器里面开启ADC中断转换 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    HAL_ADC_Start_IT(&hadc1); //定时器中断里面开启ADC中断转换,1s开启一次采集    
}


/* ADC转换完成回调函数,在回调函数里面,关闭中断,保存数据 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    HAL_ADC_Stop_IT(&hadc1);			//关闭ADC中断
    HAL_TIM_Base_Stop_IT(&htim3);	//关闭定时器
    ADC_value[ADC_value_flag++]=HAL_ADC_GetValue(hadc);		 //获取值并存储
 
   if(ADC_value_flag == ADC_value_max) //最大值的下一位
    {
         ADC_value_flag=0;//清零下标
    } 
    HAL_TIM_Base_Start_IT(&htim3); //开启定时器
}


/* USER CODE END 1 */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
	HAL_ADCEx_Calibration_Start(&hadc1);    //ADC校准
	
	HAL_TIM_Base_Start_IT(&htim3);	//开启定时器中断
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		
		/* 多通道采集 + 扫描模式 + 连续转换模式 + 中断 */
		volt_value = ADC_value[3]*3.3f/4096;
		tem_value = (1.43 - ADC_value[4]*3.3f/4096) / 0.0043 + 25;
		
		printf("tem : %.2f \r\n",tem_value);
		printf("demo1 : %d \r\n",ADC_value[4]);
		printf("volt  : %.4f \r\n",volt_value);
		HAL_Delay(1000);
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

(5)多通道DMA采集

STM32Cube MX里面配置了五个通道;
设置为独立模式;
在规则通道设置里面,设置5个通道;
可以在Rank里面设置每个通道采集的顺序;
由于是多通道数据采集,必须使能扫描模式

为了采集到多通道的数据,这里使用的办法是DMA

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

配置DMA ,设置为循环模式

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
	/* DMA 数据定义 */
	uint16_t ADC_value[ADC_value_max] = {0};		//ADC采集数值
	float  volt_value;	//电压值
	float  tem_value;		//温度值
/* USER CODE END PD */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
	HAL_ADCEx_Calibration_Start(&hadc1);    //ADC校准
	HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_value,sizeof(ADC_value) / sizeof(ADC_value[0]));  //开启DMA

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		/* 多通道采集 + 扫描模式 + DMA */
		HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_value,sizeof(ADC_value) / sizeof(ADC_value[0]));

		volt_value = ADC_value[3]*3.3f/4096;
		tem_value = (1.43 - ADC_value[4]*3.3f/4096) / 0.0043 + 25;
		
		printf("tem : %.2f \r\n",tem_value);
		printf("demo1 : %d \r\n",ADC_value[4]);
		printf("volt  : %.4f \r\n",volt_value);
		HAL_Delay(1000);	
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

(6)多通道定时器MDA采集

STM32Cube MX里面配置了五个通道;
设置为独立模式;
在规则通道设置里面,设置5个通道;
可以在Rank里面设置每个通道采集的顺序;
由于是多通道数据采集,必须使能扫描模式

为了采集到多通道的数据,这里使用的办法是DMA
为了减少资源占用,选择又定时器驱动DMA

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

配置一个定时器,使用内部时钟,自动重装载值,配置为触发事件更新

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

打开定时器的中断

stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件
配置ADC参数,配置为定时器3触发
stm32cube 定时器触发adc,stm32,单片机,嵌入式硬件

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
	/* DMA 数据定义 */
	uint16_t ADC_value[ADC_value_max] = {0};		//ADC采集数值
	float  volt_value;	//电压值
	float  tem_value;		//温度值
/* USER CODE END PD */

/* 定时器 DMA */
/* 定时器回调函数,定时器溢出以后触发回调函数 */
/* 在定时器里面开启ADC DMA采集 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_value,sizeof(ADC_value) / sizeof(ADC_value[0]));
	//定时器中断里面开启ADC DMA 转换,1s开启一次采集    
}
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
	HAL_ADCEx_Calibration_Start(&hadc1);    //ADC校准
	HAL_TIM_Base_Start_IT(&htim3);	//开启定时器
	HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_value,sizeof(ADC_value) / sizeof(ADC_value[0]));  //开启DMA

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		/* 多通道采集 + 扫描模式 + DMA + 定时器*/
		
		volt_value = ADC_value[3]*3.3f/4096;
		tem_value = (1.43 - ADC_value[4]*3.3f/4096) / 0.0043 + 25;
		
		printf("tem : %.2f \r\n",tem_value);
		printf("demo1 : %d \r\n",ADC_value[4]);
		printf("volt  : %.4f \r\n",volt_value);
		HAL_Delay(1000);	
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

附录

本文涉及到的程序:STM32 HAL库 ADC数据采集(设置的0积分,无法下载,留言发给你)文章来源地址https://www.toymoban.com/news/detail-617523.html

到了这里,关于STM32 HAL库 STM32CubeMX -- ADC的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【HAL库】STM32CubeMX开发----非阻塞延时实验----SysTick(滴答定时器)中断

    STM32CubeMX 下载和安装 详细教程 【HAL库】STM32CubeMX开发----STM32F103/F207/F407----目录 HAL库 有自带的 ms级 延时函数: HAL_Delay(); 缺点: 这是 阻塞延时 方式,就是延时期间,什么都不能干,这样很浪费资源。 这篇文章主要介绍,利用 SysTick(滴答定时器)中断 实现 非阻塞延时 的实验

    2024年02月16日
    浏览(42)
  • 基于CubeMX(hal库)stm32中hrtim高分辨率定时器的基本使用(自存)

    1、选通道 单通道输出or双通道输出 2、Timer A~F配置 (Master Timer不用管) 比较值Compare 个人感觉跟CCR差不多的意思, 注意不要大于上面的Period就行 设置上升沿和下降沿时间: 若想让上设Compare=CCR 如图设置 即可 即在 计数到Compare1时拉低,计数溢出时拉高 所以上图输出频率10kHz占

    2024年02月04日
    浏览(48)
  • 2.基于正点原子STM32F103的定时器中断实验(HAL库实现)(cubeMX)

      基本上每一款MCU都会配备定时器这个外设,STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。 同样,STM32F1系列的定时器功能也很强大,包括: TIM1和TIM8两个高级定时器; TIM2~TIM5是个通用寄存器; TIM7,TIM8,两个基本定时器。 由于本次实验适用于新手入门

    2023年04月26日
    浏览(153)
  • STM32 HAL库 CubeMX配置 定时器学习 F103C8T6

    开发板: STM32F103C8T6最小系统板 编译环境: Keil5 MDK 辅助软件: STM32 CubeMX 课程教学: 基于正点原子HAL库学习教程 其余配件: 江科大STM32配件包 和 示波器一台 备注:  因为这块开发板没有基本定时器,所以本文也 没有基本定时器的内容             本文1.3和2.1部分的

    2024年04月26日
    浏览(34)
  • STM32 HAL库 通用定时器介绍及相关应用例程 定时器中断 输出PWM (点亮LED呼吸灯、输出PWM、输入捕获) CubeMX

    (部分图引自于ATK) 前情提要(基本定时器) 点此进入 通用定时器类别 通用定时器和基本定时器相比大致的工作方式是相似的,不过通用定时器比基本定时器多了一些很好用的功能,比如: 外部输入捕获 输出比较 输出PWM 时钟源 CubeMX为我们提供了配置时钟的非常方便的工

    2024年04月15日
    浏览(74)
  • 【STM32笔记】STM32的定时器开发基础(二)(基于STM32CubeMX实现定时器中断)

      传统STM32外部中断 的设计步骤:  (1)将GPIO初始化为输入端口。  (2)配置相关I/O引脚与中断线的映射关系。  (3)设置该I/O引脚对印的中断触发条件。  (4)配置NVIC,并使能中断。  (5)编写中断服务函数。   基于STM32CubeMX的外部中断 设计步骤  (1)在STM3

    2024年02月20日
    浏览(44)
  • STM32CubeMX——定时器配置

    本文将会以STM32F103C8T6为例配置定时器2定时5 ms SMT32F1系列共有8个定时器: 基本定时器(TIM6、TIM7) 通用定时器(TIM2、TIM3、TIM4、TIM5) 高级定时器(TIM1、TIM8) 16位向上、向下、向上/下自动装载计数器 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为 1~6553

    2023年04月10日
    浏览(49)
  • 最详细STM32,cubeMX 定时器

    这篇文章将详细介绍 STM32,cubeMX 定时器的配置和使用。 实验开发板:STM32F103C8T6。 所需软件:keil5 , cubeMX 。 实验目的:了解 cubeMX 定时器 的配置和使用。 实验:使用定时器控制 led 闪烁。 STM32的定时器是用于时间测量和事件生成的复杂工具。可以使用内部或外部时钟源。时

    2024年02月07日
    浏览(40)
  • STM32CubeMX教程5 TIM 定时器概述及基本定时器

    开发板(STM32F407G-DISC1) STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 逻辑分析仪nanoDLA 使用STM32CubeMX软件配置STM32F407开发板 使用基本定时器TIM6实现每500ms控制绿灯状态变化一次,基本定时器TIM7实现每1s控制红灯状态变化一次 STM32F407拥有2个基础定时器、

    2024年02月03日
    浏览(79)
  • STM32CubeMX系列06——定时器(定时、PWM、输入捕获)

    ==== 文章汇总(有代码汇总) ==== 正点原子Mini板,主控 STM32F103RCT6. 定时器简介 这里主要讨论通用定时器(系统嘀嗒定时器、看门狗定时器、RTC定时器不考虑在内) 对于STM32F103RCT6 单片机: 2个基本定时器。分别是 TIM6 、 TIM7 。只能16位向上计数、没有IO口,没有捕获和比较通

    2024年02月01日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包