STM32-ADC介绍(基本原理)

本文详细介绍了如何在STM32中使用ADC将模拟信号转换为数字信号,包括ADC的关键参数如分辨率、转换时间和输入范围,以及不同工作模式、触发源和校准过程。特别关注了STM32F103C8T6的12位逐次逼近型ADC及其配置方法。
摘要由CSDN通过智能技术生成

我们在利用传感器测量的时候,一般是利用电阻电容等受的外界测量的物理量,导致测量电路电压发生变化,产生模拟信号,而单片机只能读取数字信号,所以就需要我们把模拟信号转变为数字信号方法:

1.可以通过ADC直接读取;

2.经过比较放大电路转变为高低电平的数字信号(抽样,保持,量化,编码)

然后把数字信号传递给单片机寄存器,进行相应操作。

今天我主要介绍

ADC(Analog-Digital Converter)模拟-数字转换器;

作用:ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁

STM32-ADC:12位逐次逼近型(工作模式)ADC,1us转换时间;

ADC关键参数:

1.分辨率:一般是用多少位表示,12位AD值表示量化结果范围就是0~2^12 -1(0~4095);

位数越多结果越精细;

2.转换时间:也就是转换频率,就是从AD转换到产生结果最少要1us,也就是1MHZ(STM32最快转换频率)

注意:当你需要采样一个特别高的频率的模拟信号需要考虑,转换频率够不够用;

输入电压范围:0~3.3v(注意一般要求,输入电压要在芯片供电范围内变化),转换结果为0~4095;与输入电压范围一一对应。可以根据比例换算

输入通道:18个输入通道,可测量16个外部(f系列最多)和2个内部信号源(内部传感器和内部参考电压)

我使用的STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道(最多测量10个);

下面介绍一个经典的一个8位逐次逼近型的ADC:

具体的每一个地方的作用我标注在下图:

过程:

首先我们开启时钟CLOCK,START给予一个脉冲信号,让ADC开始转换。我们可能有多路的输入,这时候可以根据,地址所存译码器,选择对应通道,输入电压A,然后SAR给DAC数据,DAC根据SAR的数据输出对应的电压B,比较器比较B和A的大小关系。然后SAR采用二分法的方法输出数据给DAC,使得DAC输出的电压B,不断和A的缩小差距近似相等。当近似相等时候,SAR将数据传递给8位锁存器并将EOC置0,标志着转换完成,我们就可以根据8位地址锁存器的数据,DAC参考电压,与255~0的对应关系进行转换就可以得到数据,这里电压我以3.3举例(具体以实际为准)。

理解了ADC0809的模型我们理解32的ADC模型就不难了:

看一下数据手册,找到32的ADC结构图:

上半部分:

32ADC触发的方式是软件触发和硬件触发;

介绍一下半部分图:

定时器触发就是利用定时器每个一段时间进入中断,触发一次转换,但是由于每次都要进入中断,会打断主程序的进。并且由于优先级的不同,不同中断之间会产生拥挤和打断导致某些事件得不到及时处理。我们可以选择事件触发,有中断信号以后选择触发一个事件,这样就不会频繁打断主程序。

接下来还有一点也就是上面例子当中介绍的ADC0809当中的CLOCK时钟信号,在32当中也就是ADDCLK用于驱动内部比较的时钟,从图上不难看出,来自于RCC。

我们打开时钟树看一看。

RCCAPB2最大为72MHZ,经过预分频处理以后,得到ADC所需要的ADCCLK,但是时钟树规定,CLOCK最大不能超过14MHZ,意思很明确,经过分频以后的频率不能超过14MHZ,我们对72MHZ可以进行2,4,6,8分频,但是不能超过14MHZ。所以只能选择6或8分频,72/6=12MHZ或者,72/8=9MHZ,其他的就会超过。

这里补充介绍一下这里的模拟看门狗,可以存测量阈值,上限和下限,一旦输入超过阈值,模拟看门狗就会狗叫,发送看门狗请求中断。


以上就是绝大部分ADC结构图的介绍。

对于配置看门狗就可以按照以下框图配置:

首先介绍一下输入资源GPIO:总共18个

规则组四种转换模式:主要分为(连续)单次转换和(非)扫描转换;

单次转换非扫描:每次执行一次adc转换执行完以后停下来,需要手动再启动,不扫描列表只执行第一个;

连续转换非扫描:连续执行adc转换,不扫描列表只执行第一个;

单次转换扫描模式:执行一次adc转换执行完以后停止,扫描执行列表ADC转换,需要借助DMA数据转运否则会被覆盖;

连续转换扫描模式:连续执行adc转换,扫描执行列表ADC转换,需要借助DMA数据转运否则会被覆盖;

触发源:

确定IO使用时,需要引脚重映射。

数据对齐:由于我们的ADC是12位的,所以要进行补位的操作。

一般选择右对齐,因为左对齐会放大ADC所测得数据。

接下来介绍一下采样时间的计算:

STM32 ADC的总转换时间为:TCONV = 采样时间 + 12.5个ADC周期

例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期     TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs;具体参考实际。

校准:

ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差 建议在每次上电后执行一次校准 启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期。在HAL库中,ADC启动后添加四个函数。

总结一下步骤:1.开启RCC时钟,包括ADC,GPIO

                          包括ADC预分频ADCCLK也要配置(RCC库函数中);

                          2.GPIO配置,为模拟输入;

                          3.配置多路选择开关;

                          4.配置ADC结构体;

                           5.配置校准(复位校准和开始校准);

下面是我写的一些函数不使用DMA

单次非扫描:

#include "stm32f10x.h"                  // Device header
void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIO时钟;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC时钟
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//开启ADC时钟CLOCK,这里选择6分频。72/6=12MHZ,在RCC头文件找
	
	//GPIO配置
	GPIO_InitTypeDef  GPIOA_InitStructure;
	GPIOA_InitStructure.GPIO_Mode=GPIO_Mode_AIN ;//模拟输入
	GPIOA_InitStructure.GPIO_Pin= GPIO_Pin_0;
	GPIOA_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init( GPIOA, &GPIOA_InitStructure);
	
	
	//选择规则组通道
	 ADC_RegularChannelConfig(ADC1,ADC_Channel_0,0, ADC_SampleTime_55Cycles5);
	//ADC,ADC通道0,ADC序列,ADC采样时间为:55.5个ADCCLOCK。
	
	
  //初始化ADC
	/*模式为:
	独立ADC;
	数据为右对齐;
	触发源为软件触发;
	单次非扫描模式
	扫描一个通道
    */
	 ADC_InitTypeDef ADC_InitStructure;
	 ADC_InitStructure.ADC_Mode=ADC_Mode_Independent  ;//   独立模式|ADC工作模式配置独立ADC工作模式和双ADC工作模式
	 ADC_InitStructure. ADC_DataAlign=ADC_DataAlign_Right ;//右对齐|ADC数据对齐方式左对齐和右对齐
	 ADC_InitStructure. ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//不选择外部触发源,软件触发|触发源选择;
	 ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//单次模式|连续转换模式/单次模式
	 ADC_InitStructure.ADC_ScanConvMode=DISABLE;//非扫描模式|扫描模式/不扫描模式
   ADC_InitStructure.ADC_NbrOfChannel=1;//指定扫描模式下扫描几个通道序列
	 
	 ADC_Init(ADC1,&ADC_InitStructure);
	 
	 
	 //开启ADC电源
	 ADC_Cmd(ADC1,ENABLE);
	 
	 //ADC校准
	 ADC_ResetCalibration(ADC1);  //复位校准
	 while(ADC_GetResetCalibrationStatus(ADC1)==SET)
		 ;  //复位校准完成
   ADC_StartCalibration(ADC1);//ADC开始校准
   while(ADC_GetCalibrationStatus(ADC1)==SET);//ADC开始校准完成
}

uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
	//等待时间采样时间55.5,转换周期12.5固定=68
	//12mhz/68=5.6us
	return ADC_GetConversionValue(ADC1);//获取AD转换值;
	
}


连续非扫描:

#include "stm32f10x.h"                  // Device header
void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIO时钟;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC时钟
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//开启ADC时钟CLOCK,这里选择6分频。72/6=12MHZ,在RCC头文件找
	
	//GPIO配置
	GPIO_InitTypeDef  GPIOA_InitStructure;
	GPIOA_InitStructure.GPIO_Mode=GPIO_Mode_AIN ;//模拟输入
	GPIOA_InitStructure.GPIO_Pin= GPIO_Pin_0;
	GPIOA_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init( GPIOA, &GPIOA_InitStructure);
	
	
	//选择规则组通道
	 ADC_RegularChannelConfig(ADC1,ADC_Channel_0,0, ADC_SampleTime_55Cycles5);
	//ADC,ADC通道0,ADC序列,ADC采样时间为:55.5个ADCCLOCK。
	
	
  //初始化ADC
	/*模式为:
	独立ADC;
	数据为右对齐;
	触发源为软件触发;
	连续非扫描模式
	扫描一个通道
    */
	 ADC_InitTypeDef ADC_InitStructure;
	 ADC_InitStructure.ADC_Mode=ADC_Mode_Independent  ;//   独立模式|ADC工作模式配置独立ADC工作模式和双ADC工作模式
	 ADC_InitStructure. ADC_DataAlign=ADC_DataAlign_Right ;//右对齐|ADC数据对齐方式左对齐和右对齐
	 ADC_InitStructure. ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//不选择外部触发源,软件触发|触发源选择;
	 ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续模式|连续转换模式/单次模式
	 ADC_InitStructure.ADC_ScanConvMode=DISABLE;//非扫描模式|扫描模式/非扫描模式
   ADC_InitStructure.ADC_NbrOfChannel=1;//指定扫描模式下扫描几个通道序列
	 
	 ADC_Init(ADC1,&ADC_InitStructure);
	 
	 
	 //开启ADC电源
	 ADC_Cmd(ADC1,ENABLE);
	 
	 //ADC校准
	 ADC_ResetCalibration(ADC1);  //复位校准
	 while(ADC_GetResetCalibrationStatus(ADC1)==SET)
		 ;  //复位校准完成
   ADC_StartCalibration(ADC1);//ADC开始校准
   while(ADC_GetCalibrationStatus(ADC1)==SET);//ADC开始校准完成
	 
	 ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换,连续只需要触发一次就会一直转换
}

uint16_t AD_GetValue(void)
{
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
	//等待时间采样时间55.5,转换周期12.5固定=68
	//12mhz/68=5.6us
	return ADC_GetConversionValue(ADC1);//获取AD转换值;
	
}


以及通过改通道实现多序列测量:

#include "stm32f10x.h"                  // Device header
void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIO时钟;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC时钟
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//开启ADC时钟CLOCK,这里选择6分频。72/6=12MHZ,在RCC头文件找
	
	//GPIO配置
	GPIO_InitTypeDef  GPIOA_InitStructure;
	GPIOA_InitStructure.GPIO_Mode=GPIO_Mode_AIN ;//模拟输入
	GPIOA_InitStructure.GPIO_Pin= GPIO_Pin_0| GPIO_Pin_1| GPIO_Pin_2| GPIO_Pin_3;
	GPIOA_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init( GPIOA, &GPIOA_InitStructure);
	
	
  //初始化ADC
	/*模式为:
	独立ADC;
	数据为右对齐;
	触发源为软件触发;
	单次非扫描模式
	扫描一个通道
    */
	 ADC_InitTypeDef ADC_InitStructure;
	 ADC_InitStructure.ADC_Mode=ADC_Mode_Independent  ;//   独立模式|ADC工作模式配置独立ADC工作模式和双ADC工作模式
	 ADC_InitStructure. ADC_DataAlign=ADC_DataAlign_Right ;//右对齐|ADC数据对齐方式左对齐和右对齐
	 ADC_InitStructure. ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//不选择外部触发源,软件触发|触发源选择;
	 ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//单次模式|连续转换模式/单次模式
	 ADC_InitStructure.ADC_ScanConvMode=DISABLE;//非扫描模式|扫描模式/非扫描模式
   ADC_InitStructure.ADC_NbrOfChannel=1;//指定扫描模式下扫描几个通道序列
	 
	 ADC_Init(ADC1,&ADC_InitStructure);
	 
	 
	 //开启ADC电源
	 ADC_Cmd(ADC1,ENABLE);
	 
	 //ADC校准
	 ADC_ResetCalibration(ADC1);  //复位校准
	 while(ADC_GetResetCalibrationStatus(ADC1)==SET)
		 ;  //复位校准完成
   ADC_StartCalibration(ADC1);//ADC开始校准
   while(ADC_GetCalibrationStatus(ADC1)==SET);//ADC开始校准完成
	 
	
}

uint16_t AD_GetValue(uint8_t ADC_Channel)
{
		
	//选择规则组通道
	 ADC_RegularChannelConfig(ADC1,ADC_Channel,1, ADC_SampleTime_55Cycles5);
	//ADC,ADC通道0,ADC序列,ADC采样时间为:55.5个ADCCLOCK。
	 ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换,连续只需要触发一次就会一直转换
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
	//等待时间采样时间55.5,转换周期12.5固定=68
	//12mhz/68=5.6us
	return ADC_GetConversionValue(ADC1);//获取AD转换值;
	
}


此为ADC封装好可以直接使用,下面是测量四个的实际情况:

以上就是对于单个ADC,不使用DMA的一些介绍,接下来会结合DMA数据转运继续介绍,有错误地方欢迎指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值