当前位置: 首页 > news >正文

ADC模数转换器详解(基于STM32)

一、ADC的作用
STM32的ADC是12位的,所以AD结果最大值是4095,也就是2^12-1,对应的电压是3.3V,那对于GPIO来说,它只能读取引脚的高低电平,要么是高电平,要么是低电平,只有两个值,而使用了ADC之后,我们就可以对这个高电平和低电平之间的任意电压进行量化,最终用一个变量来表示,读取这个变量,就可以知道引脚的具体电压到底是多少了,所以ADC其实就是一个电压表,把引脚的电压值测出来,放在一个变量里,这就是ADC的作用。

二、ADC简介
1、ADC(Analog-Digital Converter)模拟-数字转换器
2、ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。
(ADC读取引脚上的模拟电压,转换为一个数据,存在寄存器里,我们再把这个数据读取到变量里来,就可以进行显示、判断、记录等等操作了)
3、12位逐次逼近型ADC,1us转换时间
4、输入电压范围:03.3V,转换结果范围:04095
(ADC的输入电压,一般要求都是要在芯片供电的负极和正极之间变化的,最低电压就是负极0V,最高电压是正极3.3V)
5、18个输入通道,可测量16个外部和2个内部信号源
(外部信号源就是16个GPIO口,在引脚上直接接模拟信号就行了,不需要任何额外的电路,引脚就直接能测电压)
(两个内部信号源是内部温度传感器和内部参考电压,温度传感器可以测量CPU的温度,比如你电脑可以显示一个CPU温度,就可以用ADC读取这个温度传感器来测量,内部参考电压是一个1.2V左右的基准电压,这个基准电压(见附录1)是不随外部供电电压变化而变化的,所以如果你芯片的供电不是标准的3.3V,那测量外部引脚的电压可能就不对,这时就可以读取这个基准电压进行校准,这样就能得到正确的电压值了)

三、ADC的组成结构
1、规则组和注入组两个转换单元
STM32 ADC的增强功能,普通的AD转换流程是,启动一次转换、读一次值,然后再启动、再读值,但是STM32的ADC就比较高级,可以列一个组,一次性启动一个组,连续转换多个值,并且有两个组,一个是用于常规使用的规则组,一个是用于突发事件的注入组
2、模拟看门狗自动监测输入电压范围
这个ADC,一般可以用于测量光线强度、温度这些值,并且经常会有个需求,就是如果光线高于某个阈值、低于某个阈值,或者温度高于某个阈值、低于某个阈值时,执行一些操作,这个高于某个阈值、低于某个阈值的判断,就可以用模拟看门狗来自动执行,模拟看门狗可以监测指定的某些通道,当AD值高于它设定的上阈值或者低于下阈值时,它就会申请中断,你就可以在中断函数里执行相应的操作,这样你就不用不断地手动读值,再用if进行判断了
3、STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道
本单片机的型号最多只能测量10个外部引脚的模拟信号,之前说的16个外部信号源,是这个系列最多有16个外部信号源,但是我们这个芯片引脚比较少,有很多引脚没有引出来,所以就只有10个外部信号源

四、ADC的两个关键参数
1、 分辨率,一般用多少位来表示,12位AD值,它的表示范围就是02^12-1,也就是04095,位数越高,量化结果就越精细,对应分辨率就越高。
2、 转换时间,就是转换频率。AD转换是需要花一小段时间的,这里的1微秒就表示从AD转换开始到产生结果,需要花1微秒(0.000001秒)的时间,对应AD转换的频率就是1MHz(1000000Hz),这个就是STM32 ADC的最快转换频率,如果你需要转换一个频率非常高的信号,那就要考虑这个转换频率是不是够用,如果你的信号频率比较低,那这个最大1MHz的转换频率也完全够用了

五、逐次逼近型ADC原理详解

  了解这个结构对学习STM32的ADC有很大帮助,因为STM32的ADC原理和这个是一样的,但是STM32只画了一个框表示ADC,并没有描述内部结构。
这个图是ADC0809的内部结构图,它是一个独立的8位逐次逼近型ADC芯片,在以前的时候,单片机的性能还不是很强,所以需要外挂一个ADC芯片才能进行AD转换,这个ADC0809就是一款比较经典的ADC芯片,现在单片机的性能和集成度都有很大的提升,很多单片机内部就已经集成了ADC外设,这样就不用外挂芯片了,引脚可以直接测电压。
左边IN0~IN7是8路输入通道,通过通道选择开关,选中一路,输入到这个点进行转换,下面是地址锁存和译码,就是你想选中哪个通道,就把通道号放在这三个脚上(ADDA、ADDB、ADDC),然后给一个锁存信号(ALE),上面这里对应的通路开关就可以自动拨好了,这部分就相当于一个可以通过模拟信号的数据选择器,因为ADC转换是一个很快的过程,你给个开始信号,过个几微秒就转换完成了,所以说如果你想转换多路信号,那不必设计多个AD转换器,只需要一个AD转换器,然后加一个多路选择开关,想转换哪一路,就先拨一下开关,选中对应通道,然后再开始转换就行了,这就是这个输入通道选择的部分,这个ADC0809只有8个输入通道。
输入信号选好了,怎么才能知道这个电压对应的编码数据是多少呢,这就需要我们用逐次逼近的方法来一一比较了,首先输入信号进入电压比较器,电压比较器可以判断两个输入信号电压的大小关系,输出一个高低电平指示谁大谁小,它的两个输入端,一个是待测的电压,另一个是DAC的电压输出端,DAC是数模转换器,给它一个数据,它就可以输出数据对应的电压,DAC内部是使用加权电阻网络来实现的转换。
现在,我们有了一个外部通道输入的未知编码的电压,和一个DAC输出的,已知编码的电压,它俩同时输入到电压比较器,进行大小判断,如果DAC输出的电压比较大,我就调小DAC数据,如果DAC输出的电压比较小,我就增大DAC数据,直到DAC输出的电压和外部通道输入的电压近似相等,这样DAC输入的数据就是外部电压的编码数据了,这就是DAC的实现原理,这个电压调节过程就是这个逐次逼近寄存器SAR来完成的,为了最快找到未知电压的编码,通常我们会使用二分法进行寻找,比如这里是8位的ADC,那编码就是从0~255,第一次比较的时候,我们就给DAC输入255的一半,进行比较,那就是128,然后看谁大谁小,如果DAC电压大了,第二次比较的时候,再就给128的一半,64,如果还大,第三次比较的时候就给32,如果这次DAC电压小了,那第四次就给32到64中间的值,然后继续,这样依次进行下去,就能最快地找到未知电压的编码,并且这个过程,如果你用二进制来表示的话,你会发现,128、64、32这些数据,正好是二进制每一位的位权,这个判断过程就相当于是,对二进制从高位到低位依次判断是1还是0的过程,这就是逐次逼近型名字的来源,那对于8位的ADC,从高位到低位依次判断8次就能找到未知电压的编码了,对于12位的ADC,就需要依次判断12次,这就是逐次逼近的过程。
那然后,AD转换结束后,DAC的输入数据,就是未知电压的编码了,然后输出到8位三态锁存缓冲器,8位就有8根线,12位就有12根线,最后上面EOC就是End Of Convert,转换结束信号,START是开始转换,给一个输入脉冲,开始转换,CLOCK是ADC时钟,因为ADC内部是一步一步进行判断的,所以需要时钟来推动这个过程,下面,VREF+和VREF-是DAC的参考电压,比如你给一个数据255,是对应5V还是3.3V呢,就由这个参考电压决定,这个DAC的参考电压也决定了ADC的输入范围,所以它也是ADC参考电压,最后左边是整个芯片电路的供电VCC和GND,通常参考电压的正极和VCC是一样的,会接在一起,参考电压的负极和GND也是一样的,也接在一起,所以一般情况下,ADC的输入电压的范围就和ADC的供电是一样的。

六、STM32的ADC结构图详解

STM32的ADC结构图
在这里,左边是ADC的输入通道,包括16个GPIO口,IN0~IN15,和两个内部的通道,一个是内部温度传感器,另一个是VREFINT(V Reference Internal),内部参照电压,总共18个输入通道,然后到达这里,这是一个模拟多路开关,可以指定我们想要选择的通道,右边是多路开关的输出,进入到模数转换器,这里模数转换器就是执行的我们刚才讲过的逐次比较的过程,转换结果会直接放在这个数据寄存器里,我们读取寄存器就能知道ADC转换的结果了,然后在这里,对于普通的ADC,多路开关一般都是只选中一个的,就是选中某一个通道、开始转换、等待转换完成、取出结果,这是普通的流程,但是这里就比较高级了,它可以同时选中多个,而且在转换的时候,还分成了两个组,规则通道组和注入通道组,其中规则组可以一次性最多选中16个通道,注入组最多可以选中4个通道,这有什么作用呢,举个例子,这就像是你去餐厅点菜,普通的ADC是,你指定一个菜,老板给你做,然后做好了送给你,这里就是,你指定一个菜单,这个菜单最多可以填16个菜,然后你直接递个菜单给老板,老板就按照菜单的顺序依次做好,一次性给你端上来,这样的话就可以大大提高效率,当然,你的菜单也可以只写一个菜,这样这个菜单就简化成了普通的模式了,那对于这个菜单呢,也有两种,一种是规则组菜单,可以同时上16个菜,但是它有个尴尬的地方,就是在这里,这个规则组只有一个数据寄存器,就是这个桌子比较小,最多只能放一个菜,你如果上16个菜,那不好意思,前15个菜都会被挤掉,你只能得到第16个菜,所以对于规则组转换来说,如果使用这个菜单的话,最好配合DMA来实现,DMA是一个数据转运小帮手,它可以在每上一个菜之后,把这个菜挪到其他地方去,防止被覆盖。那现在我们就知道了,这个规则组虽然可以同时转换16个通道,但是数据寄存器只能存一个结果,如果不想之前的结果被覆盖,那在转换完成之后,就要尽快把结果拿走。
接着我们看一下注入组,这个组就比较高级了,它相当于是餐厅的VIP座位,在这个座位上,一次性最多可以点4个菜,并且这里数据寄存器有4个,是可以同时上4个菜的,对于注入组而言,就不用担心数据覆盖的问题了,这就是规则组和注入组的介绍,一般情况下,我们使用规则组就完全足够了,如果要使用规则组的菜单,那就再配合DMA转运数据,这样就不用担心数据覆盖的问题了。所以接下来只谈规则组的操作
继续看模数转换器外围的一些线路,首先,左下角这里是触发转换的部分,对于STM32的ADC,触发ADC开始转换的信号有两种,一种是软件触发,就是你在程序中手动调用一条代码,就可以启动转换了,另一种是硬件触发,就是方框图右下角的这些触发源,上面是注入组的触发源,下面这些是规则组的触发源,这些触发源主要是来自于定时器,由定时器的各个通道,还有TRGO定时器主模式的输出,定时器可以通向ADC、DAC这些外设,用于触发转换,那因为ADC经常需要过一个固定时间段转换一次,比如每隔1ms转换一次,正常的思路就是,用定时器,每隔1ms申请一个中断,在中断里手动开始一次转换,这样也是可以的,但是频繁进中断对我们的程序是有一定影响的,比如你有很多中断都需要频繁进入,那肯定会影响主程序的执行,并且不同中断之间,由于优先级的不同,也会导致某些中断不能及时得到响应,如果触发ADC的中断不能及时响应,那我们ADC的转换频率就肯定会产生影响了,所以对于这种需要频繁进中断,并且在中断里只完成了简单工作的情况,一般都会有硬件的支持,比如这里,就可以给TIM3定个1ms的时间,并且把TIM3的更新事件选择为TRGO输出,然后在ADC这里,选择开始触发信号为TIM3的TRGO,这样TIM3的更新事件就能通过硬件自动触发ADC转换了,整个过程不需要进中断,节省了中断资源,这就是这里定时器触发的作用,当然这里还可以选择外部中断引脚来触发转换,都可以在程序中配置,这就是触发转换的部分。
左上角这里是VREF+、VREF-、VDDA和VSSA。VREF+和VREF-是ADC的参考电压,决定了ADC输入电压的范围,VDDA和VSSA是ADC的供电引脚,一般情况下,VREF+要接VDDA,VREF-要接VSSA,在我们这个芯片上,没有VREF+和VREF-的引脚,它在内部就已经和VDDA和VSSA接在一起了。VDDA和VSSA是内部模拟部分的电源,比如ADC、RC振荡器、锁相环等,在这里VDDA接3.3V,VSSA接GND,所以ADC的输入电压范围就是0~3.3V。
右边这里ADCCLK是ADC的时钟,是用于驱动内部逐次比较的时钟,来自ADC预分频器,这个ADC预分频器是来源于RCC的
DMA请求,用于触发DMA进行数据转运,然后是两个数据寄存器,用于存放转换结果的,上面还有模拟看门狗,它里面可以存一个阈值高限和阈值低限,如果启动了模拟看门狗,并指定了看门的通道,那这个看门狗就会关注它看门的通道,一旦超过这个阈值范围,就会在上面,申请一个模拟看门狗的中断,最后通向NVIC,然后对于规则组和注入组而言,它们转换完成之后,也会有一个EOC转换完成的信号,在这里,EOC是规则组的完成信号,JEOC是注入组完成的信号,这两个信号会在状态寄存器里置一个标志位,我们读取这个标志位,就能知道是不是转换结束了,同时这两个标志位也可以去到NVIC,申请中断,如果开启了NVIC对应的通道,它们就会触发中断

七、ADC的转换模式
1、单次转换、非扫描模式

  单次转换,非扫描模式,这个是最简单的,这里我画了一个列表,这个表就是规则组里的菜单,有16个空位,分别是序列1到序列16,你可以在这里“点菜”,就是写入你要转换的通道,在非扫描的模式下,这个菜单就只有第一个序列1的位置有效,这时,菜单同时选中一组的方式就退化为简单地选中一个的方式了,在这里我们可以在序列1的位置指定我们想转换的通道,比如通道2,写到这个位置,然后我们就可以触发转换,ADC就会对这个通道2进行模数转换,过一小段时间后,转换完成,转换结果放在数据寄存器里,同时给EOC标志位置1,整个转换过程就结束了,我们判断这个EOC标志位,如果转换完了,那我们就可以在数据寄存器里读取结果了,如果我们想再启动一次转换,那就需要再触发一次,转换结束,置EOC标志位,读结果。如果想换一个通道,那在转换之前,把第一个位置的通道2改成其他通道,然后再启动转换,这就是单次转换,非扫描模式。没有用到这个菜单列表,也是比较简单的一种模式。

2、连续转换,非扫描模式

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

3、单次转换,扫描模式

  单次转换,扫描模式,这个模式也是单次转换,所以每触发一次,转换结束后,就会停下来,下次转换就得再触发才能开始,然后它是扫描模式,这就会用到这个菜单列表了,你可以在这个菜单里点菜,比如第一个菜是通道2,第二个菜是通道5,等等,这里每个位置是通道几可以任意指定,并且也是可以重复的,然后初始化结构体里还会有个参数,就是通道数目,因为这16个位置你可以不用完,只用前几个,那你就需要再给一个通道数目的参数,告诉它,我有几个通道,比如这里指定通道数目为7,那它就只看前7个位置,然后每次触发之后,它就依次对这前7个位置进行AD转换,转换结果都放在数据寄存器里,这里为了防止数据被覆盖,就需要用DMA及时将数据挪走,那7个通道转换完成之后,产生EOC信号,转换结束,然后再触发下一次,就又开始新一轮的转换,这就是单次转换,扫描模式的工作流程。

4、连续转换,扫描模式

  那最后再看一下连续转换,扫描模式,这个模式就是在上一个模式的基础上,变了一点,就是一次转换完成后,立刻开始下一次的转换,和上面这里非扫描模式的单次和连续是一个套路,当然在扫描模式的情况下,还可以有一种模式,叫间断模式,它的作用是,在扫描的过程中,每隔几个转换,就暂停一次,需要再次触发,才能继续,这个模式我没有列出来,要不然模式太多了,了解即可,暂时不需要掌握

八、ADC的转换时间

  为什么需要采样保持呢?这是因为,我们的AD转换,就是后面的量化编码,是需要一小段时间的,如果在这一小段时间里,输入的电压还在不断变化,那就没法定位输入电压到底在哪了,所以在量化编码之前,我们需要设置一个采样开关,先打开采样开关,收集一下外部的电压,比如可以用一个小容量的电容存储一下这个电压,存储好了之后,断开采样开关,再进行后面的AD转换,这样在量化编码的期间,电压始终保持不变,这样才能精确地定位未知电压的位置,这就是采样保持电路,那采样保持的过程中,需要闭合采样开关,过一段时间再断开,这里就会产生一个采样时间。
采样时间是采样保持花费的时间,这个可以在程序中进行配置,采样时间越大,越能避免一些毛刺信号的干扰,不过转换时间也会相应延长,12.5个ADC周期是量化编码花费的时间,因为是12位的ADC,所以需要花费12个周期,这里多了半个周期,可能是做其他一些东西花的时间,ADC周期就是从RCC分频过来的ADCCLK,这个ADCCLK最大是14MHz。
所以下面有个例子,这里就是最快的转换时间
当ADCCLK=14MHz,采样时间为1.5个ADC周期。Tconv = 1.5 + 12.5 = 14个ADC周期,在14MHz ADCCLK的情况下就 = 1微秒,这就是1微秒时间的来源

附录1:参考电压和参照电压
每个STM32芯片都有一个内部的参照电压,相当于一个标准电压测量点,在芯片内部连接到ADC1的通道17。
根据数据手册中的数据,这个参照电压的典型值是1.20V,最小值是1.16V,最大值是1.24V。这个电压基本不随外部供电电压的变化而变化。
不少人把这个参照电压与ADC的参考电压混淆。ADC的参考电压都是通过Vref+提供的。100脚以上的型号,Vref+引到了片外,引脚名称为Vref+;64脚和小于64脚的型号,Vref+在芯片内部与VCC信号线相连,没有引到片外,这样AD的参考电压就是VCC上的电压。
在ADC的外部参考电压波动,或因为Vref+在芯片内部与VCC相连而VCC变化的情况下,如果对于ADC测量的准确性要求不高时,可以使用这个内部参照电压得到ADC测量的电压值。
具体方法是在测量某个通道的电压值之前,先读出参照电压的ADC测量数值,记为ADrefint;再读出要测量通道的ADC转换数值,记为ADchx;则要测量的电压为:
Vchx = Vrefint * (ADchx/ADrefint)

 
附录2:电源电压符号
VCC:C=circuit表示电路的意思,即接入电路的电压
VDD:D=device表示器件的意思,即器件内部的工作电压
VSS:S=series表示公共连接的意思,通常指电路公共接地端电压


文章转载自:

http://L8S7AGSQ.qLhwy.cn
http://y3Zoo9a8.qLhwy.cn
http://HZ1G4a42.qLhwy.cn
http://vurrbB8L.qLhwy.cn
http://zPgtk7PY.qLhwy.cn
http://4ID6LA9G.qLhwy.cn
http://2pkh0iBy.qLhwy.cn
http://HF3NanWz.qLhwy.cn
http://9SUGbpaV.qLhwy.cn
http://PCd8NTfO.qLhwy.cn
http://9z5fbTFb.qLhwy.cn
http://GmpVLVpp.qLhwy.cn
http://xl2dIxN5.qLhwy.cn
http://NFToaFno.qLhwy.cn
http://eHYllDCT.qLhwy.cn
http://E7cSqZis.qLhwy.cn
http://8nKD4aOK.qLhwy.cn
http://vNRi6u9E.qLhwy.cn
http://UyMYzakn.qLhwy.cn
http://lKG1k0mN.qLhwy.cn
http://wtV3ROTV.qLhwy.cn
http://pJvjDW6e.qLhwy.cn
http://2W2ZfGMX.qLhwy.cn
http://KwinGzza.qLhwy.cn
http://x7vIbfMj.qLhwy.cn
http://QbjJxMvC.qLhwy.cn
http://V6IEMj2o.qLhwy.cn
http://YeCCAQel.qLhwy.cn
http://cc6M1ZAr.qLhwy.cn
http://K0P312PE.qLhwy.cn
http://www.dtcms.com/a/376612.html

相关文章:

  • 深入理解网络浏览器运行原理
  • 线扫相机不出图原因总结
  • 【Linux系统】日志与策略模式
  • 物联网时序数据库IoTDB是什么?
  • Rust:系统编程的革新者
  • 【postMan / apifox 文件上传】
  • 使用 javax.net.ssl.HttpsURLConnection 发送 HTTP 请求_以及为了JWT通信选用OSS的Jar的【坑】
  • 9.10 Swiper-layer-laydate
  • 基于代理模式:深入了解静态代理和动态代理
  • 崔传波教授:以科技与人文之光,点亮近视患者的清晰视界‌
  • java 代理模式实现
  • 2025最新的软件测试面试八股文(800+道题)
  • 深入浅出LVS负载均衡群集:原理、分类与NAT模式实战部署
  • Nginx 配置 SSL/TLS 全指南:从安装到安全强化
  • 整体设计 之 绪 思维导图引擎 之 引 认知系统 之8 之 序 认知元架构 之4 统筹:范畴/分类/目录/条目 之2 (豆包助手 之6)
  • Android应用添加日历提醒功能
  • 【游戏开发】- 摄像机
  • B站 韩顺平 笔记 (Day 29)
  • Typescript入门-JSDoc注释及tsconfig讲解
  • Python快速入门专业版(十八):Python比较运算符深度解析:从基础判断到对象身份识别(附避坑指南)
  • 微服务网关实战:从三次灾难性故障到路由与权限的体系化防御
  • 从C++开始的编程生活(8)——内部类、匿名对象、对象拷贝时的编译器优化和内存管理
  • 【AI时代速通QT】第六节:Qt Creator从添加新窗口到项目构建运行配置
  • 【CVPR 2022】面向2020年代的卷积神经网络
  • 图神经网络介绍
  • FPGA入门到进阶:可编程逻辑器件的魅力
  • 【解决问题】Ubuntu18上无法运行arm-linux-gcc
  • 嵌入式学习day47-硬件-imx6ull-LED
  • 深入体验—Windows从零到一安装KingbaseES数据库
  • 力扣习题——电话号码的字母组合