ADC数模转换器

ADC Analog-Digital Converter )模拟 - 数字转换器
ADC 可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
12 位逐次逼近型 ADC 1us 转换时间
输入电压范围: 0~3.3V ,转换结果范围: 0~4095
18 个输入通道,可测量 16 个外部和 2 个内部信号源
规则组和注入组两个转换单元
模拟看门狗自动监测输入电压范围
STM32F103C8T6 ADC 资源: ADC1 ADC2 10 个外部输入通道

电位器:滑动变阻器

ADC的两个关键参数,第一个是分辨率,一般用多少位来表示,12位AD值,它的表示范围就是0~2^12-1,量化结果的范围是0~4095,位数越高,量化结果就越精细,对应分辨率就越高;第二个是转换时间,就是转换频率,AD转换是需要花一小段时间的,这里1us就表示从AD转换开始到产生结果,需要花1us的时间,对应AD转换的频率就是1MHz,这个就是STM32 ADC的最快转换频率。如果你需要转换一个频率比较高的信号,那就要考虑这个转换频率是不是够用。

输入电压一般要求都是要在芯片供电的负极和正极之间变化的

外部信号就是16个GPIO口,在引脚上直接接模拟信号就行了,不需要任何额外的电路,引脚就直接能测电压;2个内部信号源是内部温度传感器和内部参考电压。温度传感器可以测量CPU的温度,比如你电脑可以显示一个CPU温度,就可以用ADC读取这个温度传感器来测量。内部参考电压是一个1.2V左右的基准电压,这个基准电压是不随外部供电电压变化而变化的。读取基准电压进行校准,可以得到正确的电压值。

规则组和注入组是STM32 ADC的增强功能,普通的AD转换流程是,启动一次转换、读一次值,然后再启动,再读值。STM32 ADC的增强功能就是可以列一个组,一次性启动一个组,连续转换多个值,并且有两个组,一个是用于常规使用的规则组,一个是用于突发事件的注入组。

模拟看门狗可以自动根据模拟量阈值进行监测指定的某些通道,当AD值高于它设定的上阈值或者低于下阈值时,它就会申请中断,你就可以在中断函数里执行相应的操作。

这个图是ADC0809的内部结构图,它是一个独立的8位逐次逼近型ADC芯片。

IN0~IN7是8路输入通道,ADDA~ADDC就是选择通道号(数据选择器),ALE是所存信号,这样上面的通道选择开关就自动拨好了,这部分相当于一个可以通过模拟信号的数据选择器

电压比较器,可以判断两个输入信号电压的大小关系,输出一个高低电平指示谁大谁小,它的两个输入端,一个是待测的电压,另一个是DAC的电压输出端,DAC内部是使用加权电阻网络来实现的转换。为了最快找到未知电压的编码,通常我们会使用二分法进行寻找,在二进制上其实就是对二进制从高位到地位依次判断是1还是0的过程,这就是逐次逼近型名字的来源。对于8位的ADC,从高位到低位依次判断8次就能找到未知电压的编码了。那然后,AD转换结束后,DAC的输入数据,就是未知电压的编码,通过8位三态锁存缓冲器输出。

EOC是End Of Convert,转换结束信号,START是开始转换,给一个输入脉冲,开始转换;CLOCK是ADC时钟,因为ADC内部是一步一步进行判断的,所以需要时钟来推动这个过程。

VREF+和VREF-是DAC的参考电压,这个DAC的参考电压也决定了ADC的输入范围,所以它也是ADC参考电压。

 

 规则组菜单,可以同时上16个菜,但是只有一个数据寄存器,桌子比较小,最多只能放一个菜,如果上16个菜,那前15个菜都会被挤掉,只能得到第16个菜,所以对于规则组来说,如果使用这个菜单的话,最好配合DMA来实现。

注入组相当于是餐厅的VIP座位,在这个座位上,一次性最多可以点4个菜,并且这里数据寄存器有4个,是可以同时上4个菜的。

触发转换部分

 

 也就是START信号,开始转换。对于STM32 ADC,触发ADC开始转换的信号有两种,一种是软件触发,就是你在程序中手动调用一条代码,就可以启动转换了;另一种是硬件触发,通过触发源,主要来自于定时器,正常思路就是,用定时器,每隔1ms申请一次中断,在中断里手动开始一次转换,这个思路比较浪费软件资源。于是,可以通过硬件,把TIM3定1ms的时间,并且把TIM3的更新事件选择为TRGO输出,然后在ADC这里选择开始触发信号为TIM3的TRGO,这样TIM3的更新事件就能通过硬件自动触发ADC转换了。当然也可以选择外部中断引脚来触发转换。

VDDA、VSSA是ADC的供电引脚,一般情况下,VREF+接VDDA,VREF-接VSSA,是内部模拟部分的电源,比如ADC、RC振荡器、锁相环等。

ADCCLK是ADC的时钟,也就是CLOCK,是用于驱动内部逐次比较的时钟,ADC预分频器来源于RCC,ADCCLK最大是14MHz,只能选择6分频12M以及8分频9M。

如果启动了模拟看门狗,并指定了看门的通道,看门狗就会关注它看门的通道,一但超过这个阈值范围了,它就会乱叫,申请一个模拟看门狗的中断,最后通向NVIC。对于规则组和注入组而言,他们转换完成之后,也会有一个EOC转换完成的信号,在这里,EOC是规则组或注入组的完成信号,JEOC是注入组完成的信号,这两个信号会在状态寄存器里置一个标志位,我们读取这个标志位,就能知道是不是转换结束了。同时这两个标志位也可以去到NVIC,申请中断。如果开启了NVIC对应的通道,他们就会触发中断。

开关控制就是ADC_Cmd函数,用于给ADC上电

 ADC12_IN0的意思是,ADC1和ADC2的IN0都是在PA0上的。双ADC模式,就是ADC1和ADC2一起工作,他俩可以配合组成同步模式、交叉模式等等模式,比如交叉模式,ADC1和ADC2交叉地对一个通道进行采样,这样可以进一步提高采样率。

ADC结构体有两个参数,一个是选择单次转换还是连续转换的,另一个是选择扫描模式还是非扫描模式的,这两个参数组合起来,就有4种转换方式。

规则组菜单,在非扫描模式下,这个菜单只有第一个序列1的位置有效,这时,菜单同时选中一组的方式就退化为简单的选中一个的方式了。

 

首先还是非扫描模式,所以菜单列表就只用第一个,然后它与上一种单次转换不同的是,它在一次转换结束后不会停止,而是立刻开始下一轮的转换,然后一直持续下去,这样就只需要最开始触发一次,之后就可以一直转换了。这个模式的好处就是,开始转换之后不需要等待一段时间,因为它一直都在转换,所以就不需要手动开始转换了,也不用判断是否结束的,想要读AD值的时候,直接从数据寄存器取就是了。

 

扫描模式就是对菜单扫描,每个位置是通道几是可以任意指定的,并且也是可以重复的,然后初始化结构体里还会有一个参数,就是通道数目,每次触发之后,它就依次对这前7个位置进行AD转换,转换结果都放在数据寄存器里。这里为了防止数据被覆盖,就需要用DMA及时将数据拿走。所有通道转换完成之后,产生EOC信号,转换结束。

 

 在扫描模式的情况下,还可以有一种模式,叫间断模式,它的作用是,在扫描的过程中,每隔几个转换,就暂停一次,需要再次触发才能继续。

外部引脚或来自片上定时器的内部信号,具体需要用AFIO重映射来确定。

 

ADC是12位的,转换结果就是一个12位的数据,但是数据寄存器是16位的,所以就存在一个数据对齐的问题

 

两大步:采样保持,量化编码

量化编码:ADC逐次比较的过程,一般位数越多,花的时间就越长

采样保持:AD转换的量化编码需要一小段时间,如果在这一小段时间里,输入的电压还在不断变化,那就没法定位输入电压到底在哪了,所以在量化编码之前,需要设置一个采样开关,先打开采样开关,收集一下外部的电压,比如可以用一个小容量的电容存储一下这个电压,存储好了之后,断开采样开关,再进行后面的AD转换,这样在量化编码的期间,电压始终保持不变,这样才能精确地定位电压的位置,这就是采样保持电路。那采样保持的过程,需要闭合采样开关,过一段时间再断开,这里就会产生一个采样时间。采样时间越大,越能避免一些毛刺信号的干扰 

 

 只需要在ADC初始化之后加几行代码就行了

外围电路设计

电位器:左右两边的两个引脚接的是电阻的两个固定端,中间引脚接的是滑动抽头,电位器外边有个十字形状的槽可以拧,往左拧,抽头就往左靠,往右拧,抽头就往右靠 

 第一步,开启RCC时钟,包括ADC和GPIO的时钟,ADCCLK的分频器也需要配置一下

第二步,配置GPIO,把需要用的GPIO配置成模拟输入的模式

第三步,配置多路开关,把左边通道接入到右边的规则组列表里

第四步,配置ADC转换器,在库函数里用结构体配置,包括ADC是单次转换还是连续转换、扫描还是非扫描、有几个通道,触发源是什么,数据对齐是左对齐还是右对齐;如果需要用到看门狗,会有几个函数用来配置阈值和监测通道的,如果想开启中断,那就在中断输出控制里用ITConfig函数开启对应的中断输出,然后再在NVIC里,配置一下优先级,这样就能触发中断了。

第五步,调用ADC_Cmd开启ADC(开关控制),进行校准来减小误差,如果想要软件触发转换,会有函数可以触发,如果想读取转换结果,那也会有函数可以读取结果。

//用来配置ADCCLK分频器的
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);

//配置的老朋友
void ADC_DeInit(ADC_TypeDef* ADCx);
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);

//用于给ADC上电
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//用于开启DMA输出信号的,如果使用DMA转运数据,那就得调用这个函数
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//中断输出控制,用于控制某个中断能不能通往NVIC
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);

//复位校准
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获取软件开始转换状态,用来获取CR2的SWSTART位,这一位的作用是开始转换规则通道,由软件设置该位以启动转换,转换开始后硬件马上清除此位
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);

//获取标志位状态,然后参数给EOC的标志位可以判断其是否置1,如果转换结束,EOC标志位置1,然后调用这个函数,判断标志位,用于判断转换是否结束    
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);

//ADC规则组通道配置,给序列的每个位置填写指定的通道
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获取转换值,获取AD转换的数据寄存器
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

//ADC获取双模式转换值,双ADC模式读取转换结果的函数
uint32_t ADC_GetDualModeConversionValue(void);

//Injected是注入组的意思,对ADC注入组进行配置
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);

//对模拟看门狗进行配置
//是否启动模拟看门狗
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);

//ADC温度传感器、内部参考电压控制,用来开启内部的两个通道
void ADC_TempSensorVrefintCmd(FunctionalState NewState);

//获取标志位状态、清除标志位、获取中断状态,清除中断挂起位
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);

模拟输入AIN模式下,GPIO口是无效的,断开GPIO,防止GPIO口的输入输出对我模拟电压造成干扰,所以AIN模式就是ADC的专属模式。

ADC_Mode---独立ADC还是双ADC

ADC_DataAligin---数据对齐

ADC_ExternalTrigConv---外部触发转换选择,就是触发控制的触发源,定义用于启动规则组转换的外部触发源,软件触发使用ADC_ExternalTrigConv_None

ADC_ContinuousConvMode---连续转换模式,可以选择是连续转换还是单次转换,ENABLE连续,DISABLE单次

ADC_ScanConvMode---扫描转换模式,这个可以选择是扫描模式还是非扫描模式,ENABLE扫描模式,DISABLE非扫描模式

ADC_NbrOfChannel---通道数目,指定在扫描模式下总共会用到几个通道

 EOC位可以由软件清除或者由读取ADC_DR时清除

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值