当前位置:   article > 正文

STM32-ADC_stm32 adc vref

stm32 adc vref

一、ADC理论知识

在这里插入图片描述
ADC读取引脚上的模拟电压,转换为一个数据,存在寄存器里,就可以进行显示、判断、记录等操作。(PWM就是一个等效模拟量相当于DAC,数模转换,通过脉宽调节来控制LED的亮度、电机的速度。DAC的应用主要在波形生成这些领域,比如信号发生器,音频解码芯片)
在这里插入图片描述
电压读取范围和转换结果范围0~3.3V、0-4095都是一一对应的线性关系。

1、模拟看门狗

如果电压、光线、温度等高于某个阈值或低于某个阈值时,需要执行一些操作,这个高于某个阈值、低于某个阈值的判断,就可以用模拟看门狗来自动执行,模拟看门狗可以监测指定的某些通道。当AD值高于它设定上的阈值或低于阈值时,它就会申请中断,就可以在中断函数里执行相应的操作,这样就不需要不断的手动读值再用if判断了。

2、逐次逼近型ADC

在这里插入图片描述
一个外部通道输入端输入的未知编码电压与 一个DAC输出的已知电压,它俩同时输入到电压比较器,进行大小判断。如果DAC输出电压比较大,那么就调小DAC输出,反之增大,直到DAC输出的电压和外部通道输入的电压近视相等,这样DAC输入的数据就是外部电压的编码数据了。
这个电压调节的过程就是逐次逼近寄存器SAR来完成的。为了最快的找到未知的电压编码,通常我们会使用二分法进行寻找,对于8位的ADC,从高位到地位依次判断8次就能找到未知电压的编码,对于12位的ADC,就需要判断12次。
AD转换结束后,DAC的输入数据,就是未知电压的编码,然后输出到8位三态锁存缓冲器。
EOC:转换结束信号。
START:开始信号,给一个输入脉冲,开始转换。
CLOCK:ADC时钟。
Vref(+)、Vref(-):DAC的参考电压(也是整个ADC的参考电压)。
ADC0809:ADC芯片。

3、STM32ADC内部结构图

在这里插入图片描述
GPIO:外部输入。
温度、Vref:内部通道。
触发控制:提供了开始转换这个START信号,触发控制可以选择软件触发和硬件触发。硬件触发主要来自定时器,当然也可以选择外部中断的引脚。
RCC:ADC时钟CLOCK,ADC逐次比较的过程就是由这个时钟推动的。
模拟看门狗:用于监测转换结果的范围,如果超出设定的阈值,就通过中断控制向NVIC申请中断
EOC:AD转换完成后会有个EOC信号,它会置一个标志位,当然也可以通向NVIC。
开关控制:再库函数中,就是ADC_Cmd函数,用于给ADC上电的。

4、转换模式

单次转换、非扫描模式
在这里插入图片描述
图中的表就是规则组里的菜单,在非扫描的模式下只有第一个序列1的位置有效,在这里我们可以在序列1的位置指定我们想转换的通道。比如图中的通道2写到序列1,然后我们就可以触发转换,ADC就会对这个通道2进行模数转换,过一小段时间后转换完成,转换结果放在数据寄存器里,同时给EOC标志位直1,整个转换过程就结束了,我们判断这个EOC标志位,如果转换完了,那我们就可以在数据寄存器里读取结果了。如果我们想在启动一次转换,那就需要在触发一次。果如想要换一个通道转换,那就再转换之前,把第一个位置的通道2改成其他通道,然后再启动转换。
连续转换、非扫描模式
在这里插入图片描述
它与上一种单次转换不同的是,它在一次转换结束后不会停止,而是立刻开始下一轮的转换,然后一直持续下去。这样就只需要开始触发一次,之后就可以一直转换了,也不用判断是否结束,想要读AD值的时候,直接从数据寄存器取。
单次转换、扫描模式
在这里插入图片描述
这个模式也是单次触发,所以每触发一次都需要手动开启。扫描模式就是可以在不同的序列号里选择不同的通道进行转换。选择通道数目,然后每次触发之后,它依次在选择的通道前进行AD转换,转换结果都放在数据寄存器里,这里为了防止数据被覆盖,就需要用DMA即时将数据挪走,所有通道转换完成之后,产生EOC信号,转换结束。
连续转换、扫描模式
在这里插入图片描述
结合了连续转换与多通道转换。

5、硬件电路(ADC的外围电路)

在这里插入图片描述
这里是电位器产生一个可调的电位器,滑动端就可以输出一个0~3.3V的可调电压输出,PA0接ADC的输入通道。
在这里插入图片描述
N1:传感器(可等效为一个可变电阻)。
通过和一个固定电阻串联分压,来得到一个反应传感器电阻值电压的电路。传感器阻值变小时,下拉作用变强,输出端电压就下降;传感器阻值变大时,下拉作用变弱,输出端电压就上升。这个固定电阻一般选择和传感器电阻相近的电阻,这样可以得到一个位于中间电压区域比较好的输出。当然传感器电阻也可以和固定电阻位置换过来,这样输出电压的极性就反过来了,这就是分压方法来输出传感器电阻的电路。
在这里插入图片描述
电压转换电路。比如想要测量一个0~5V的VIN电压,但ADC只能接收0-3.3V的电压,在这里使用电阻进行分压,根据分压公式,中间的电压就是VIN/50K×33K ,最后得到的电压范围就是0-3.3V,就可以进入ADC转换。

二、STM32ADC

1、触发控制

在这里插入图片描述

2、数据对齐

在这里插入图片描述
数据多出来的补0。一般采用右对齐,读取这个16位寄存器就是转换的结果。

3、转换时间

在这里插入图片描述

4、校准

在这里插入图片描述

三、ADC代码

在这里插入图片描述
第一步:开启RCC时钟,包括ADC和GPIO的时钟,另外这里ADCCLK的分频器也需要配置一下。
第二部:配置GPIO,把需要用的GPIO配置成模拟输入的模式。
第三步:配置多路开关,把左边的通道接收到右边的规则组列表里。
第四步:配置ADC转换器(在库函数里,用结构体来配置,可以配置一大块电路的参数,包括ADC是单次转换还是连续转换、扫描还是非扫描、有几个通道、触发源、数据对齐)
*如果需要配置模拟开门狗,那会有几个函数来配置阈值和监测通道。如果想要开启中断,那就再中断输出控制里用ITConfing函数开启对应的中断输出,然后在NVIC里配置一下优先级,这样就能触发中断了。
最后就是开关控制,调用ADC_Cmd函数开启ADC。

1、初始化配置

以下是函数说明:

RCC_APB2PeriphClockCmd (RCC_APB2Periph_ADC1,ENABLE);//开启ADC1的时钟
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);//ADCCLK分频器,可以对APB2的72MHz时钟选择2
468分频,输入到ADCCLK。在RCC库函数。

void ADC_DeInit(ADC_TypeDef* ADCx);//恢复缺省配置
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);//Init初始化
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);//结构体初始化
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);//用于给ADC上电
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);//开启DMA,使用DMA转运数据
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);//中断输出控制
//校准函数,在ADC初始化完成后依次调用
void ADC_ResetCalibration(ADC_TypeDef* ADCx);//复位校准
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);//获取复位校准状态
void ADC_StartCalibration(ADC_TypeDef* ADCx);//开始校准
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);//获取开始校准状态
//开始ADC转换,获取标志位判断转换结束
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//ADC软件开始转换控制
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);//ADC获取软件开始转换状态
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);//获取标志位
//间断模式
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);//每隔几个通道间断一次
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//是否开启间断

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);//ADC规则组通道配置
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//ADC外部触发转换控制
//ADC获取转换值
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);//ADC获取转换值,用来读取结果
uint32_t ADC_GetDualModeConversionValue(void);//ADC获取双模式转换值
//模拟看门狗
void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);//是否启动看门狗
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);//配置高低阈值
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);//配置看门的通道
void ADC_TempSensorVrefintCmd(FunctionalState NewState);//ADC温度传感器、内部电压控制
//重要~
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);//获取标志位状态
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);//清除标志位
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);//获取中断状态
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);//清除中断挂起位
//对ADC注入组进行配置 jected
void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv);
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);
uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

开始初始化

void AD_Init(void)
{
		//开启ADC1、GPIOA的时钟
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
		//ADCCLK分频,72MHz6分频
	  RCC_ADCCLKConfig(RCC_PCLK2_Div6);
		//初始化PGPIO,把A0设置为模拟输入
		GPIO_InitTypeDef GPIO_InitStructre;//定义一个结构体变量
		GPIO_InitStructre.GPIO_Mode=GPIO_Mode_AIN;
		GPIO_InitStructre.GPIO_Pin=GPIO_Pin_0;
		GPIO_InitStructre.GPIO_Speed=GPIO_Speed_50MHz;
		GPIO_Init(GPIOA,&GPIO_InitStructre);
	  //选择规则组的输入通道
	  ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
		//初始化ADC
	  ADC_InitTypeDef ADC_InitStructre;
	  ADC_InitStructre.ADC_DataAlign=ADC_DataAlign_Right;//对齐
	  ADC_InitStructre.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//触发方式
	  ADC_InitStructre.ADC_Mode=ADC_Mode_Independent;//工作模式
	  ADC_InitStructre.ADC_ContinuousConvMode=DISABLE;//连续转换模式
	  ADC_InitStructre.ADC_ScanConvMode=DISABLE;//扫描转换模式
  	ADC_InitStructre.ADC_NbrOfChannel=1;//通道数目
		ADC_Init(ADC1,&ADC_InitStructre);
		
		//中断或看门口需要就在后面继续配置
		
		//开启ADC电源
		ADC_Cmd(ADC1,ENABLE);
		//校准
		ADC_ResetCalibration(ADC1);
		while (ADC_GetResetCalibrationStatus(ADC1) ==SET);
		ADC_StartCalibration(ADC1);
		while (ADC_GetCalibrationStatus(ADC1) ==SET);
}
    //读取ADC返还值
uint16_t AD_GetValue(void)
{
	  ADC_SoftwareStartConvCmd(ADC1,ENABLE);//启动
	  while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) ==RESET);//等待
	  return ADC_GetConversionValue(ADC1);//读取
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

初始化完成就可以在主函数定义一个常量赋予返还值AD_GetValue()。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/805820
推荐阅读
相关标签
  

闽ICP备14008679号