零基础STM32单片机编程入门(四)ADC详解及实战含源码视频

一.概要

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。
在这里插入图片描述

二.STM32F103C8T6单片机ADC外设特点

STM32F103C8T6含有2个12位的模拟/数字转换器(ADC1,ADC2),每个ADC共用多达10个外部通道,可以实现单次或连续转换,1MHz转换速率,转换范围:0~3.6V,ADC供电要求:2.4V~3.6 V。ADC1同时含有2个内部通道:连接到芯片内部温度传感器和内部参考电压(VREFINT = 1.2V)

10个外部通道对应的单片机上的引脚如下图
在这里插入图片描述

三.STM32单片机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上的电压。

(4)VREF-(Negative Voltage Reference)
ADC模块的负参考电压引脚,通常连接到外部提供的负参考电压源或地。VREF-确定了ADC转换过程中的下限电压参考点,通常对应于模拟输入信号的最小量程值。
STM32F103C8T6也没有这个引脚。

2.ADC通道分类

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

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

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

3.触发源

ADC转换的输入、通道、转换顺序都已经说明了,但ADC转换是怎么触发的呢?就像通信协议一样,都要规定一个起始信号才能传输信息,ADC也需要一个触发信号来实行模/数转换。
其一就是通过直接配置寄存器触发,通过配置控制寄存器CR2的ADON位,写1时开始转换,写0时停止转换。在程序运行过程中只要调用库函数,将CR2寄存器的ADON位置1就可以进行转换,比较好理解。
另外,还可以通过内部定时器或者外部IO触发转换,也就是说可以利用内部时钟让ADC进行周期性的转换,也可以利用外部IO使ADC在需要时转换,具体的触发由控制寄存器CR2决定。

4.转换周期

可独立设置各通道采样时间ADC会在数个ADCCLK周期内对输入电压进行采样,可使用ADC_SMPR1和ADC_SMPR2寄存器中的SMP[2:0]位修改周期数。每个通道均可以使用不同的采样时间进行采样。
总转换时间的计算公式如下:
Tconv=采样时间+12个周期
示例:
ADCCLK = 30 MHz且采样时间=3个周期时:
Tconv= 3+12=15个周期=0.5us (APB2为60MHz时)
最小采样时间0.42us(ADC时钟=36MHz,采样周期为3周期下得到)。

5.电压转换计算

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

6.更精确电压转换计算

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

四.规则通道ADC采集信号流向

在这里插入图片描述

1.单次转换模式

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

2.连续转换模式

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

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

在这里插入图片描述

STM32F103C8T6小系统板PA4 引脚上的进行 ADC 电压采集,杜邦线连接 PA4 引脚与 VDD(3.3V),应该能读到单片机供电的电压值。
打开STM32CubeMX软件,新建工程
在这里插入图片描述
Part Number处输入STM32F103C8,再双击就创建新的工程
在这里插入图片描述
配置下载口引脚
在这里插入图片描述
配置外部晶振引脚
在这里插入图片描述
配置PA4引脚为ADC1的通道4,进行电压采集
在这里插入图片描述

配置系统主频
在这里插入图片描述
配置工程文件名,保存路径,KEIL5工程输出方式
在这里插入图片描述
生成工程
在这里插入图片描述
用Keil5打开工程
在这里插入图片描述
Main.c中添加代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

STLINK连接好板子后,Keil 5进入调试,在Watch界面查看两个变量的值,ADC采样到的值是0xfff,转换成电压值就是3300mV。

在这里插入图片描述
main代码如下:

/* USER CODE BEGIN 0 */
int ADCData;
uint16_t VolDta;
/* USER CODE END 0 */

/**
  * @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();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();//外部8M晶振,系统72M主频

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC1_Init();//PA4引脚配置成ADC1 Channel4输入
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
 
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		if(HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)//启动校准
  {
    Error_Handler();
  }
	HAL_ADC_Start(&hadc1);//启动ADC

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	  ADCData=HAL_ADC_GetValue(&hadc1);//获取ADC采集值
		VolDta=ADCData*3300/4095;//ADC采集值转换成电压值,单位mV
		HAL_Delay(200);//等待200ms
		HAL_ADC_Start(&hadc1);//再次启动ADC	
		HAL_Delay(200);
    /* USER CODE BEGIN 3 */
  }
  
  /* USER CODE END 3 */
}


六.CubeMX工程源代码下载

在这里插入图片描述
链接:https://pan.baidu.com/s/1A3tst65eeeLbxwtFvOe0iA
提取码:7wht

如果链接失效,可以联系博主给最新链接
程序下载下来之后解压就行

七.讲解视频链接地址

ADC外设视频讲解

八.小结

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

  • 45
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103C8T6 是一款基于 ARM Cortex-M3 内核的微控制器,它具有多个模拟输入通道,可以用于ADC(模数转换器)采集电压。以下是使用STM32F103C8T6的ADC模块进行电压采集的步骤: 1. 配置ADC模块时钟,使能ADC模块。 2. 配置GPIO引脚为模拟输入模式。 3. 配置ADC采样时间和转换时间。 4. 配置ADC参考电压。 5. 配置ADC通道,选择采样通道。 6. 启动ADC转换。 7. 等待转换完成,读取采样结果。 以下是一个简单的示例代码,实现对ADC通道0进行采样,并将采样结果通过串口输出: ```c #include "stm32f10x.h" #include <stdio.h> void ADC_Config(void) { // 1. 配置ADC模块时钟,使能ADC模块 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 2. 配置GPIO引脚为模拟输入模式 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // 3. 配置ADC采样时间和转换时间 ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_28Cycles5); // 4. 配置ADC参考电压 ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } void UART_Config(void) { // 配置USART1,波特率为115200 USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); } int main(void) { ADC_Config(); UART_Config(); while(1) { // 6. 启动ADC转换 ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 7. 等待转换完成,读取采样结果 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); uint16_t value = ADC_GetConversionValue(ADC1); printf("ADC value: %d\r\n", value); } } ``` 上述代码中,ADC采样时间为28.5个时钟周期,参考电压使用默认的内部参考电压2.5V。通过USART1将采样结果输出到串口。你可以根据需要修改采样时间、参考电压等参数,以及输出方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值