ADC 模数转换器
对于gpio来说,它只能读取引脚的高低电频,要么是高电平,要么是低电平,只有两个值,而使用了adc之后,就可以对这个高电平和低电平之间的任意电压进行量化,最终用一个变量来表示,读取这个变量就可以知道引角的具体电压到底是多少来,所以adc其实就是一个电压表,把引脚的电压值测出来,放在一个变量里,这就是adc的作用。
目录
一、ADC简介
对于gpio来说,它只能读取引脚的高低电频,要么是高电平,要么是低电平,只有两个值,
而使用了adc之后,就可以对这个高电平和低电平之间的任意电压进行量化,最终用一个变量来表示,读取这个变量就可以知道引角的具体电压到底是多少来,所以adc其实就是一个电压表,把引脚的电压值测出来,放在一个变量里,这就是adc的作用。
ADC(Analog-Digital Converter)模拟-数字转换器, ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁,stm32 主要是数字电路,数字电路只有高低电平,没有几伏电压的概念,所以如果想读取电压值,就需要借助adc模数转换器来实现了,adc读取引脚上的模拟电压转化为一个数据存放在寄存器里,我们再把这个数据读取到变量里来,就可以进行显示了,进行判断记录等操作了,adc可以将模拟信号转换为数字信号,是模拟电路到数字电路的桥梁,adc是模拟到数字的桥梁,那反过来有模拟到数字的桥梁,那肯定就有数字到模拟的桥梁,这就是dac数字模拟转换器,使用dac就可以将数字变量转化为模拟电压目前dac的应用主要是在波形生成这些领域,比如信号发生器,音频解码芯片等这些领域。
stm32 的adc是12位逐次逼近型的adc,1微秒的转换时间,逐次逼近型是这个adc的工作模式,然后12位和1微秒的转换时间就涉及到adc的两个关键参数了,第一个是分辨率一般用多少位来表示,即12位ad值它的表示范围就是0~2^12-1,就是量化结果的范围是0~4095位,数越大,量化结果就越精细对应分辨率就越高;第二个是转换时间,就是转换频率,ad转换是需要花一小段时间,这里1微秒就表示从ad转换开始到产生结果需要花1微秒的时间,对应ad转换的频率就是一兆赫兹,这个就是s t m32 adc的最快转换频率,如果需要转换一个频率非常高的信号,那就要考虑一下这个转换频率是不是够用,如果你的信号频率比较低,那这个最大一兆赫兹的转换频率也完全够用了,
输入电压范围0~3.3v,转换结果范围0~4095,这个abc的输入电压,一般要求都是要在芯片供电的负极和正极之间变化的,最低电压就是负极0伏,最高电压是正极3.3伏,经过adc转换之后,最小值就是零,最大值是4095,0V对应0,3.3V对应4095。中间都是一一对应的线性关系,这个计算起来就非常简单了,直接乘除一个系数就行了。
adc有18个输入通道,可测量16个外部和2个内部信号源,外部信号源就是16个GPIO口,在引脚上直接接模拟信号就行了,不需要任何额外的电路,引脚就直接能测定,这个还是非常方便的。两个内部信号源是内部温度传感器和内部参考电压,温度传感器可以测量cpu的温度,比如你电脑可以显示一个cpu温度,就可以用adc读取这个温度传感器来测量内部参考电压,是一个1.2伏左右的基准电压,这个基准电压是不随外部供电电压变化而变化的,所以如果你芯片的供电不是标准的3.3伏,那测量外部引脚的电压可能就不对,这时就可以读取这个基准电压进行校准,这样就能得到正确的电压值了。
规则组合注入组两个转换单元,这个就是stm32中adc的增强功能了,普通的ad转换流程是启动一次转换,读一次值,然后再启动再读值,这样的流程,但是stm32 的adc就比较高级,可以列一个组,一次性启动一个组,连续转换多个值,并且有两个组合,一个是用于常规使用的规则组,另外一个是用于突发事件的注入组。
模拟看门狗自动监测输入电压范围,这个adc,一般可以用于测量光线强度温度值,并且经常会有个需求,就是如果光线高于某个阈值,低于某个阈值或者温度高于某个阈值低于某个阈值时,执行一些操作,这个高于某个阈值,低于某个阈值的判断就可以用模拟看门狗来自动执行模拟看门狗可以监测指定的某些通道,当值高于它设定的上余值或者低于下余值时,它就会申请中断,就可以在中断函数里执行相应的操作,这样就不用不断的手动阻止,再用if进行判断了
在STM32F103C8T6的ADC资源:ADC1,ADC2, 10个外部输入通道,也就是它最多只能测量十个外部引脚的模拟信号,之前说的16个外部信号源,这是这个系列最多有16个外部信号源,但是STM32F103C8T6这个芯片引脚比较少,很多引脚没有引出来,所以就只有十个外部信号源。如果想要更多的外部通道,可以选择引脚更多的型号。
二、逐次逼近型ADC
下图是逐次逼近型adc的内部结构,这个图是adc 0809的内部结构图,逐次逼近行adc芯片,在以前的时候,单片机的性能还不是很强,所以需要外挂一个adc芯片才能进行ad转换,这个adc0809就是一款比较经典的adc芯片,现在单片机的性能和集成度都有很大的提升,很多单片机内部就已经集成了adc外设,不用外挂芯片的引脚可以直接测电压。

首先左边通过IN0~IN7八路输入通道,通过通道选择开关,选中一路,输入到红点这里进行转换。下面这里是地址锁存和译码,就是想选中哪一路,就把通道号放到这三个引脚(ADDA,ADDB,ADDC),然后给一个锁存信号,上面这里对应通路开关就可以自动拨好了,这部分就相当于一个可以通过模拟信号的数据选择器,因为adc转换是一个很快的过程,给一个开始信号,过几微秒就转换完成了。所以说如果想转换多路信号那不必设计多个ad转换器,只需要一个ad转换器,然后加一个多路选择开关,想转换哪一路就先拨一下开关选中对应通道,然后再开始进行转换就行了,这就是这个输入通道选择的部分,这个adc0809只有八个输入通道。stm32 内部的adc是有18个输入通道的,所以对应的通道选择开关就是一个18路输入的多路开关,然后输入信号选好了红点这里来。
怎么才能知道这个电压对应的编码数据是多少呢?就需要我们用逐次逼近的方法来一一比较,首先是一个电压比较器,它可以判断两个输入信号电压的大小关系,输出一个高低电平指示谁大谁小,它的两个输入端,一个是待测的电压,另一个是dac的电压输出端,dac是数模转换器,之前说过,给它一个数据,它就可以输出数据对应的电压,dac内部是使用加权电阻网络来实现的转换。

那现在有了一个外部通道输入的未知编码的电压和一个dac输出的已知编码的电压,他俩同时输入到电压比较器进行大小判断,如果dac输出的电压比较大,就调小dac数据,如果dac输出的电压比较小,就增大dac数据,直到dac输出的电压和外部通道输入的电压近似相等,这样dac输入的数据就是外部电压的编码数据,这就是dac的实现原理,这个电压调节的过程就是这个逐次逼近SAR来完成的,通常使用二分法进行寻找。比如这里是八位的adc,那编码就是从0~255,就是在0~255中寻找。对于八位的adc从高位到低位依次判断八次,就能找到未知电压的编码了,对于12位的adc就需要依次判断12次。
然后ad转换结束后,dac的输入数据就是未知电压的编码,通过这下图红点进行输出,八位就有八根线,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的供电是一样的。
三、ADC框架图
这里左边是adc的输入通道,包括16个GPIO口,IN0~IN15, 两个内部的通道一个是内部温度传感器,另一个是vrefint内部参考电压,总共是18个输入通道,然后到达模拟多路开关,可以指定我们想要选择的通道。

右边是多路开关的输出,进入到模拟至数字转换器,模数转换器就是执行前文讲过的逐次比较的过程,转换结果会直接放在这个数据寄存器里,只需读取数据寄存器就能知道abc转换的结果了。

然后在下图这里对于普通的adc多路开关,一般都是只选中一个的,就是选中某个通道开始转换,等待转换完成取出结果,这是普通的流程。但是这里就比较高级了,它可以同时选中多个,而且在转换的时候还分成了两个组,规则通道组和注入通道组,其中规则组可以一次性最多选16个通道,注入组最多可以选中四个通道,这个作用就像是你去餐厅点菜普通的adc,你指定一个菜,老板给你做然后做好了送给你,这里就是你指定一个菜单,这个菜单最多可以填16个菜,然后你直接递个菜单给老板,老板就按照菜单的顺序依次做好一次性给你端上来,当然你的菜单也可以只写一个菜,这样这个菜单就简化成了普通的模式,那对于这个菜单呢也有两种,一种是规则组菜单可以同时上16个菜,但是它有个尴尬的地方,就是在这里这个规则组只有一个数据寄存器,就是这个桌子比较小,最多只能放一个菜,如果上16个菜,那不好意思啊,前15个菜都会被挤掉,你只能得到第16个菜,所以对于规则组转换来说,如果使用这个菜单的话,最好配合dma来实现,dma是一个数据转运小帮手,他可以在每上一个菜之后把这个菜挪到其他地方去,防止被覆盖。那现在就知道了,这个规则组虽然可以同时转换16个通道,但是数据寄存器只能存一个结果,如果不想之前的结果被覆盖,那在转换完成之后,就要尽快把结果拿走。

注入通道组这个组就比较高级了,它相当于是餐厅的vip座位,在这个座位上一次性最多可以点四个菜,并且这里数据寄存器有四个是可以同时上,四个菜的对于注入组而言就不用担心数据覆盖的问题了,这就是规则组和侏儒组的介绍。一般情况下我们使用规则组就完全足够了,如果要使用规则组的菜单,那就再配合dma转移数据,这样就不用担心数据覆盖的问题了,注入组涉及的不多,看手册自行了解。
首先左下角这里是触发转换的部分,也就是下图的start信号开始转换,那对于stm32 的adc,触发adc开始转换的信号有两种,一种是软件触发,就是你在程序中手动调用一条代码就可以启动了,另一种是硬件触发,就是下面第一个图中红框的这些触发源,上面是注入组的触发源,下面这些是规则组的触发源,这些触发源主要是来自于定时器,有定时器的各个通道,还有trgo定时器主模式的输出,这个之前讲定时器的时候也写过,定时器可以通向adc, dac 这些外设用于触发转换,那因为adc经常需要过一个固定时间段转换一次,比如每隔1ms转换一次,正常的思路就是用定时器每隔1ms申请一次中断,在中断里手动开始一次转换,这样也是可以的,但是频繁进中断对我们的程序是有一定影响的,比如你有很多中断都需要频繁进入,那肯定会影响主程序的执行,并且不同中断之间,由于优先级的不同也会导致某些中断不能及时得到响应,如果触发adc的中断不能及时响应,那我们adc的转换频率就肯定会产生影响了,所以对于这种需要频繁进中断,并且在中断里只完成了简单工作的情况,一般都会有硬件的支持,比如就可以给TIM3定一个1ms的时间并且把TIM3的更新事件选择为TRGO输出,然后在adc这里选择开始触发信号为TIM3的TRGO,这样TIM3的更新事件就能通过硬件自动触发adc转换了,整个过程不需要进中断,节省了中断资源,这就是这里定时器触发的作用,当然这里还可以选择外部中断引脚来触发循环,都可以在程序中配置,这就是触发转换的部分。



然后接着看左上角,这里是vref+,vref-, vdda和vssa,上面两个是adc的参考电压,决定了adc输入电压的范围,下面两个是adc的供电引脚,一般情况下vref+ 要接vdda,vref- 要接vssa,在我们这个芯片上没有为vref+ 和vref- 的引脚,它在内部就已经和vdda和vssa接在一起了,vdda和vssa在这个引脚定义里也可以看到,vdda和vssa是内部模拟部分的电源,在这里vdda接3.3v,vssa接gnd,所以adc的输入电压范围就是0~3.3V,右边这里是adcclk是adc的时钟也就是这里的clock,是用于驱动内部逐次比较的时钟,这个是来自adc预分频器,这个adc预分频器是来源于rcc的,这里哈APB2时钟72兆赫兹,通过ADC预分频器,得到ADCCLK,其最大是14MHz,所以这个预分频器就有点尴尬,他可以选择2,4,6,8分屏,如果选择二分屏,72除以他们都无法得到14MHz,并且只能选择6分频才能不超过14MHz,所以只能选择6分频或者8分频。



ADCCLK这是ADC的时钟,上面是DMA请求,这个就是用于触发dma进行数据转运的,然后是两个数据寄存器,用于存放转换结果的,上面还有模拟开门狗,它里面可以存一个阈值高限和阈值低限,如果启动了模拟看门狗,并且指定了开门的通道,那个看门狗就会关注他开门的通道(也就是规则组中的通道),一旦超过这个阈值范围了,它就会乱叫,就会在上面申请一个模拟看门狗的中断,最后通向NVIC,然后对于规则组和注入组而言,它们转换完成之后也会有一个EOC转换完成的信号,在这里EOC是规则组的完成信号,JEOC是注入组完成的信号,这两个信号会在状态寄存器里制一个标志位,读取这个标志位就能知道是不是转换结束了,同时这两个标志位也可以去到NVIC申请中断,如果开启了nvic对应的通道,就会触发中断。
四、ADC基本结构图

总结ADC基本结构图:左边是输入通道,16个GPIO口,外加两个内部的通道,然后进入ad转换器,ad转换器里有两个组,一个是规则组,一个是注入组,规则组最多可以选中16个通道,注入组最多可以选择四个通道,然后转化的结果可以存放在ad数据寄存器里,其中规则组只有一个数据计算器,注入组有四个,然后下面这里有触发控制,提供了开始转换这个十START的信号,触发控制可以选择软件触发和硬件触发,硬件触发主要是来自于定时器啊,当然也可以选择外部中断的硬件,右边这里是来自于RCC的ADC时钟clock, ADC逐次比较的过程就是由这个时钟推动的,然后上面可以布置一个模拟看门狗,用于监测转换结构的范围,如果超出设定的阈值,就通过中断输出控制向NVIC申请中断,另外规则组和注入组转换完成后会有个EOC信号,它会自己一个标志位,当然也可以通向NVIC,最后右下角这里还有个开关控制,在库函数中,就是ADC_Cmd函数,用于给ADC上电,这些就是stm32 中ADC的内部结构图。
五、输入通道

这里有16个外部通道,GPIO口如表所示,这些就是ADC通道和引脚复用的关系,这个对应关系也可以通过引脚定义表看出来
这里总共只有十个通道,然后其他地方就没有了,说明STM32F103C8T6芯片就只有十个外部输入通道。 然后ADC12_IN0的意思是:ADC1和ADC2的IN0都在PA0上,然后下面的ADC1和ADC2的引脚都是相同的,既然都相同,那要ADC2还有啥用呢?这个就要再说一个ADC的高级功能,就是双ADC模式,这个模式比较复杂,只简单介绍一下。双ADC模式就是ADC1和ADC2一起工作,他俩可以配合组成同步模式,交叉模式等等模式。比如交叉模式ADC1和ADC2交叉着对一个通道进行采样这样就可以进一步提高采样率,就像你打拳一样啊,左手打一拳,右手打一拳,快速交叉的打拳,那打击的频率肯定就比一个拳头打得快,当然还有其他的模式,这就是ADC1和ADC2配合使用的双ADC模式。当然adc一和adc 2也是可以分开使用的,可以分别对不同的硬件而进行采样,这样也是可以的。

六、四种转换模式
这四种模式分别是单次转换,非扫描模式;连续转换,非扫描模式;单次转换,扫描模式和连续转换,扫描模式。那在adc初始化的结构体里会有两个参数,一个是选择单次转换还是连续转换的,另一个是选择扫描模式还是非扫描模式的,这两个参数组合起来就有这四种转换方式。
1.单词转换非扫描模式
这个是最简单的,如下图所示:
左边的表就是规则组里的菜单,有16个空位分别是序列1到序列16,可以在这里点菜,就是写入你要转换的通道,在非扫描的模式下,这个菜单就只有第一个序列1的位置有效,这时菜单同时选中一组的方式就退化为简单的选中一个的方式,在这里我们可以在序列一的位置指定我们想转换的通道,比如图中通道2写到这个位置,然后我们就可以触发转换,ADC就会对这个通道2进行模数转换,过一段时间后,转换完成,转换结果放在数据寄存器里,同时给EOC标志位置1,整个转换过程就结束了。
如果我们想再启动一次转换,那就需要再触发一次,转换结束,置EOC标志位,读结果。如果想换一个,通道转换,那在转换之前把第一个位置的通道2改成其他通道,,然后再启动转换,这样就行了,这就是单次转换非扫描的模式。没有用到这个菜单列表。

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

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

4. 连续转换扫描模式
这个模式就是在上一个模式的基础上变了一点,就是一次转换完成后,立刻开始下一次的转换,和上面这里非扫描模式的单次和连续是一个套路,这就是连续转换扫描模式,当然在扫描模式的情况下,还可以有一种模式,叫阶段模式,它的作用是在扫描的过程中每隔几个转换就暂停一次,需要再次触发才能继续,了解一下。

七、触发控制器

第一个是触发控制,上文中说过,这个表就是规则组的触发源,也就是下图中的红框。上图在这个表里有来自定时器的信号;还有来自引脚或定时器的信号,这个具体是引脚还是定时器,需要用AFO重映射来确定;最后是软件控制位。也就是之前说的软件触发这些触发信号怎么选择,可以通过设置上图右边这个寄存器来完成,当然使用库函数的话,直接给个参数就行了哈这就是触发控制。

八、数据对齐
因为我们这个ADC是12位的,它的转换结果就是一个12位的数据,但是这个数据寄存器是16位的,所以就存在一个数据对齐的问题。这里第一种是数据右对齐,就是12位的数据向右靠,高位多出来的几位就补零;第二种是数据左对齐是12位的数据,向左靠低位多出来的几位补零。我们一般使用的都是第一种右对齐,这样读取这个16位寄存器,直接就是转换结果,如果选择左对齐直接读的话,得到的数据会比实际的大,因为数据左对齐实际上就是把数据转移了四次,二进制有个特点,就是数据左移一次,就等效于把这个数据乘二,那这里左移来四次,就相当于把结果乘16了,所以直接读的话会比实际值大16倍。那要这个左对齐有啥用呢,这个用途就是如果你不想要这么高的分辨率,你觉得0~4095数太大了,就做个简单的判断,不需要这么高分辨率,那你就可以选择左对齐,然后再把这个数据的高八位取出来,舍弃掉了后面四位的精度和后面的四位0,这个12位的ADC就退化成了八位的ADC,这就是左对齐的作用。不过我们一般用的话,选右对齐就行了,如果需要裁减一些分辨率,大不了就先把12位都取出来再做处理,这也是可以的,就是多算了一步而已。
九、转换时间

不过转换时间这个参数一般不太敏感,因为一般AD转换都很快,如果不需要非常高速的转换频率,那转换时间就可以忽略了,之前说了AD转换是需要一小段时间的,就像厨子做菜一样也是需要等一小会才能上菜的,那AD转换的时候有哪些步骤需要花时间呢?这里第一条AD转换的步骤有四步:分别是采样,保持,量化,编码。其中采样保持可以放在一起,量化编码可以放到一起,总共就是两大步。量化编码就是我们之前讲过的ADC逐次比较的过程,这个是需要花一段时间的,一般位数越多,花的时间就越长;采样保持的原因是因为量化编码需要一小段时间,如果在这一小段时间里,输入的电压还在不断变化,那就没法定位输入电压到底是在哪了,所以在量化编码之前,需要设置一个采样开关,先打开采样开关,收集一下外部的电压,比如可以用一个小容量的电容存储一下这个电压,存储好了之后,断开采样开关,再进行后面的AD转换,这样在量化编码的期间,电压始终保持不变,这样才能精确地定位位置电源的位置,这就是采样保持电路,那采样保持的过程,需要闭合采样开关,过一段时间再断开,这里就会产生一个采样时间。
通过上面的解释,得到了图中第二条,STM32 ADC的总转换时间为:采样时间加12.5个ADC周期,采样时间是采样保持花费的时间,这个可以在程序中进行配置,采样时间越大,越能避免一些毛刺信号的干扰,不过转换时间也会相应延长,12.5个ADC周期是量化编码花费的时间,因为是12位的ADC,所以需要花费12个周期,多了半个周期可能是做一些其他东西花的时间,ADC周期就是从RCC分频过来的ADCCLK,这个ADCCLK最大为14MHz,所以有了后面的例子。这就是最快1微秒时间的来源。如果你=采样周期再长些,它就达不到1微秒了,另外也可以把ADCCLK的时钟设置超过14MHz,这样的话ADC就是在超频的,那转换时间可以比1微秒还短,不过这样稳定性又没法保证的。

十、校准

不需要理解,只需要在ADC初始化的最后,加几条代码就可以了。
更多推荐





所有评论(0)