一.概要

ADC(Analog to Digital Converter),即模数转换器,是将连续的模拟信号转换为离散的数字信号的单片机外设。典型的模拟数字转是将模拟信号转换为表示一定比例电压值的数字信号,比如温度传感器等一些传感器,输出的信号是0~3.3V的电压信号。
例如温度传感器输出电压0V代表采集到的温度是0­°C,输出电压3.3V代表温度是100­°C,温度跟电压成线性比例关系,如果单片机ADC外设采集的到电压是1.65V,那就代表温度是50­°C(100°C*1.65/3.3),如果单片机ADC外设采集到的电压是3.3V,那就代表温度是100­°C。
在这里插入图片描述

二.STM32G474RET6单片机ADC外设特点

STM32F407VET6含有5个12位的模拟/数字转换器(ADC1,ADC2,ADC3,ADC4,ADC5),12-bit逐次逼近型的模拟数字转换器,硬件过采样实现16-bit精度,总共多达26个外部通道,可以实现单次(singal)、连续(continuous)、扫描(scan)、不连续(discontinuous)、注入(injected),最快速度达4Mhz,也就是转换时间为0.25us,转换范围:0~3.6V,ADC供电要求:1.62V~3.6 V。ADC1同时含有3个内部通道:连接到芯片内部温度传感器,备用电池电压以及内部参考电压(VREFINT = 1.212V)

ADC外部通道对应的单片机上的引脚,在芯片手册,如下图
在这里插入图片描述

三.STM32G474单片机ADC内部结构图

ADC内部结构图如下
在这里插入图片描述

1.ADC相关引脚说明

(1)VDDA(Analog Supply Voltage)
ADC模块的模拟电源引脚,通常连接到MCU的模拟电源线路。VDDA提供ADC模块所需的模拟电源电压,确保ADC的正常工作和准确的模拟信号转换。

(2)VSSA(Analog Ground Voltage)
ADC模块的模拟地引脚,通常连接到MCU的模拟地线路。

(3)VREF+(Positive Voltage Reference)
ADC模块的正参考电压引脚,通常连接到外部提供的正参考电压源。VREF+确定了ADC转换过程中的上限电压参考点,通常对应于模拟输入信号的最大量程值。在ADC转换过程中,被测量的模拟信号会与VREF+进行比较,以确定其对应的数字量,STM32F103C8T6是没有这个引脚,64脚和小于64脚的STM32F103型号,其VREF+在芯片内部与VCC信号线相连,没有引到片外,这样AD的参考电压就是VCC上的电压。

2.ADC通道分类

在STM32的ADC模块中,分成了两种不同类型的通道类型:规则通道和注入通道,它们适应于不同的采集场景,在功能框图所示:
在这里插入图片描述

ADC规则通道
规则通道顾名思义就是,最平常的通道、也是最常用的通道,平时的ADC转换都是用规则通道模式的。它允许用户配置ADC以便按照预定的顺序对这些通道进行连续或单次采样。

ADC注入通道
注入通道是相对于规则通道的,注入通道可以在规则通道转换时,强行插入转换,相当于一个“中断通道”吧。当有注入通道需要转换时,规则通道的转换会停止,优先执行注入通道的转换,当注入通道的转换执行完毕后,再回到之前规则通道进行转换。这种功能使得注入通道特别适合于采集突发事件或需要高优先级响应的应用,比如实时监控或故障检测。

3.触发源

ADC转换的输入、通道、转换顺序都已经说明了,但ADC转换是怎么触发的呢?就像通信协议一样,都要规定一个起始信号才能传输信息,ADC也需要一个触发信号来实行模/数转换。
其一就是通过直接配置寄存器触发,通过配置控制寄存器ADC_CR的ADSTART位,写1时开始转换,写0时停止转换,如下图所示。在程序运行过程中只要调用库函数,将CR寄存器的ADSTART位置1就可以进行转换,比较好理解。
在这里插入图片描述

另外,还可以通过内部定时器或者外部IO触发转换,也就是说可以利用内部时钟让ADC进行周期性的转换,也可以利用外部IO使ADC在需要时转换,具体的触发由控制寄存器ADC_CFGR决定。

4.采样时间

可独立设置各通道采样时间ADC会在数个ADCCLK周期内对输入电压进行采样,可使用ADC_SMPR1和ADC_SMPR2寄存器中的SMP[2:0]位修改周期数,如下图所示,每个通道均可以使用不同的采样时间进行采样。
在这里插入图片描述

ADC完整过程分为采样阶段(sample time)与转换阶段(conversion time),采样阶段至少需要2.5 ADC 时钟周期,转换阶段需要12.5 ADC时钟周期(12-bit精度)。60 MHz ADC 时钟,15 ADC时钟周期,
ADC单通道采样速率最高达到4M samples/s。

5.电压转换计算

转换后的数据是一个12位的二进制数,我们需要把这个二进制数代表的模拟量(电压)用数字表示出来。比如测量的电压范围是0~3.3V,ADC转换后的寄存器读到的数是x,因为12位ADC在转换时将电压的范围大小(也就是3.3)分为4096(2^12)份,所以真实电压的计算方法就是: y=3.3* x / 4096(V)

6.更精确电压转换计算

STM32G474RET6有时候是VDD 3.3V做参考电压,但是这种方法在供电电压有可能随外部一些其他用电器工作使用的大电流而导致电压不稳定,内部参考电压能更加精确计算采样到的电压,具体方法是在测量某个通道的电压值之前,先读出参照电压的ADC测量数值(Vrefint Channel),记为ADrefint;再读出要测量通道的ADC转换数值,记为ADchx;则要测量的电压为:
Vchx = VREFINT * (ADchx/ADrefint)

一般高精度场合需要VREF+用高精度参考电压供电,比如REF3033,精度能到0.2%,温漂50ppm/°C。

7.硬件过采样

STM32G474单片机支持过采样可提升精度,每4倍采样率可提升1bit的精度,最高16-bit精度。主要原理是求平均, 降低数据率, 改善信噪比与基本滤波。
在这里插入图片描述

四.ADC采集信号流向

在这里插入图片描述
规则换数据存储于16-bit 数据寄存器ADCx_DR中,软件轮询,中断或是DMA请求可用于进行数据搬移。

1.单次转换模式

配置为单次模式使能,扫描模式不使能。这样ADC的这个通道,转换一次后,就停止转换,需要下一次启动才可以。

2.连续转换模式

配置为连续模式使能,扫描模式不使能。这样ADC的这个通道,转换一次后,接着进行下一次转换,不断连续。

在这里插入图片描述

五.CubeMX配置一个ADC采集例程

硬件准备:

STLINK接STM32G474RET6开发板,STLINK接电脑USB口。
在这里插入图片描述

STM32G474RET6开发板PA1引脚上的进行 ADC 电压采集,杜邦线连接 PA1引脚与 VDD(3.3V),应该能读到单片机供电的电压值。

如下图所示,打开STM32CubeMX软件,新建工程。
在这里插入图片描述
如下图所示,Part Number处输入STM32G474RE,再双击就创建新的工程。
在这里插入图片描述

如下图所示,配置下载口引脚,PA13为SWD的SWDIO脚,PA14为SWD的SWCLK脚。
在这里插入图片描述

如下图所示,配置ADC1通道2,PA1引脚。
在这里插入图片描述

如下图所示,配置系统主频170Mhz,使用内部16MHZ晶振。
在这里插入图片描述

配置工程文件名,保存路径,KEIL5工程输出方式,生成工程。
在这里插入图片描述
在这里插入图片描述

用Keil5打开工程,Main.c中添加代码。
在这里插入图片描述

STLINK连接好板子后,Keil 5进入调试,在Watch界面查看两个变量的值,ADC采样到的值,读取ADC_DR的值是0xFFB,转换成电压值就是3295mV,如下图所示。
在这里插入图片描述

主要代码如下:

/* USER CODE BEGIN PFP */
uint16_t AD_Value,Vol_Value;//AD_Value:ADC寄存器的采样值,Vol_Value:ADC转换成电压值
/* USER CODE END PFP */
/**
  * @brief  The application entry point.
  * @retval int
  */
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();//SysTick配置成1ms中断
  /* USER CODE BEGIN Init */
  /* USER CODE END Init */
  /* Configure the system clock */
  SystemClock_Config();//内部16MHZ晶振,170MHZ系统主频
  /* USER CODE BEGIN SysInit */
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC1_Init();//PA1引脚作为ADC采样引脚,ADC1的通道2
  /* USER CODE BEGIN 2 */
	if(HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED) != HAL_OK)//ADC1启动一次校准,主要作用是补偿ADC模块的内部误差,提高转换精度
  {
    Error_Handler();
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	HAL_ADC_Start(&hadc1);//启动adc1转换
	HAL_ADC_PollForConversion(&hadc1, 100);//等待100ms或者转换完成
	if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))//查询是否转换完成
	{
		AD_Value = HAL_ADC_GetValue(&hadc1);//转换完成,就读取ADC1数据寄存器值
		Vol_Value=(AD_Value*3300)/4096;//把数据寄存器值转换成电压值,12bit的ADC,ADC分辨率为12位(即12bit)的设备,其最大输出值为4096
	}
	HAL_Delay(100);//等待100ms
  }
  /* USER CODE END 3 */
}

六.小结

ADC外设是STM32单片机开发中的最基本操作,学会了ADC,可以采集外部的一些传感器的模拟信号,适应更多模块的驱动。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐