目录
ADC简介
什么叫逐次逼近型?
STM32 ADC框图
模数转换器外围线路
ADC基本结构图
输入通道
规则组的四种转换模式
第一种:单次转换非扫描模式
第二种:连续转换,非扫描模式
第三种:单次转换,扫描模式
第四种:连续转换,扫描模式
触发控制
数据对齐
数据右对齐
数据左对齐
转换时间
校准
硬件电路
声明:本专栏是本人跟着B站江科大的视频的学习过程中记录下来的笔记,我之所以记录下来是为了方便自己日后复习。如果你也是跟着江科大的视频学习的,可以配套本专栏食用,如有问题可以QQ交流群:963138186
这节我们来学习一下STM32的ADC。
ADC简介
ADC(Analog-Digital Converter)模拟-数字转换器
ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。
另外,使用DAC就可以将数字变量转化为模拟电压。上一节我们还学到了一个数字-模拟的桥梁:PWM。我们使用PWM来控制led的亮度,电机的速度,这就是DADC的功能。同时,PWM只有完全导通和完全断开两种状态。在这两种状态上都没有功率损耗,所以在直流电机调速这种大功率的应用场景,使用PWM来等效模拟量是比DADC更好的选择。并且PWM电路更加简单,更加常用。所以可以看出PWM还是挤占了DADC的很多应用空间。目前DADC的应用主要是在波形生成这些领域。信号发生器、音频解码芯片等这些领域。PWM还是不好替代的。
12位逐次逼近型ADC,1us转换时间
这里就涉及到ADC这两个关键参数了:
第一个:分辨率,即一般用多少位来表示,十二位AD值,它的表示范围就是0~2^12-1,就是量化结果的范围是0~4095,位数越高,量化结果就越精细,对应分辨率就越高。
第二个:转换时间,就是转换频率。AD转换是需要花一小段时间的。这里1us就表示从AD转换开始到产生结果,需要花1us的时间。对应AD转换的频率就是1MHz,这个就是STM32ADC的最快转换频率。如果需要转换一个频率非常高的信号,就要考虑一下这个转换频率是不是够用。如果信号频率比较低,这个最大1MHz的转换频率也完全够用了。
什么叫逐次逼近型?
这里不明白可以去看我的51单片机专栏的AD/DA转换的博文:
单片机学习笔记---AD/DA工作原理(含运算放大器的工作原理)_简述da和ad转换的原理-CSDN博客
STM32和51单片机在逐次逼近型ADC这里唯一的不同就是51单片机是8位输出,STM32是12位。
注:我们本节学习的是ADC,DADC大家就自行了解,我们这个型号的STM32也没有DAC的外设。
输入电压范围:0~3.3V,转换结果范围:0~4095
这个ADC的输入电压一般要求都是要在芯片供电的负极和正极之间变化的,最低电压就是负极0V,最高电压是正极3.3V,经过ADC转换之后,最小值就是零,最大值是4095。0V对应零,3.3V对应4095,中间都是一一对应的线性关系。
18个输入通道,可测量16个外部和2个内部信号源
外部信号源就是十六个GPIO口,在引脚上直接接模拟信号就行了,不需要任何额外的电路,引脚就直接能测电压,这个还是非常方便的。
两个内部信号源是内部温度传感器和内部参考电压。
温度传感器可以测量CPU的温度,比如电脑可以显示一个CPU温度,就可以用ADC读取这个温度传感器来测量。
内部参考电压是一个1.2V左右的基准电压,这个基准电压是不随外部供电电压变化而变化的。所以如果芯片的供电不是标准的3.3V,测量外部引脚的电压可能就不对,这时就可以读取这个基准电压进行校准,这样就能得到正确的电压值了。
规则组和注入组两个转换单元
这个就是STM32 ADC的增强功能的。普通的AD转换流流程是启动一次转换读一些值,然后再启动再读值这样的流程。
但是STM32的ADC就比较高级,可以列一个组,一次性启动一个组,连续转换多个值。并且有两个组,一个是用于常规使用的规则组,一个是用于突发事件的注入组。这个等会我们再细看。
模拟看门狗自动监测输入电压范围
这个ADC1般可以用于测量光线强度、温度这些值,并且经常会有个需求,就是如果光线高于某个阈值,低于某个阈值,或者温度高于某个阈值,低于某个阈值时执行一些操作。
这个高于某个阈值,低于某个阈值的判断,就可以用模拟看门狗来自动执行,模拟看门狗可以监测指定的某些通道。当AD值高于它设定的上阈值或者低于下阈值时,它就会申请中断,就可以在中断函数里执行相应的操作。这样就不用不断的手动读值,再用if进行判断了。
STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道
也就是它共有两个ADC外设,十个外部输入通道,也就是它最多只能测量十个外部引脚的模拟信号。我们之前这里说的十六个外部信号源,这是这个系列最多有十六个外部信号源。但是我们这个芯片引脚比较少,有很多引脚没有引出来,所以就只有十个外部信号源。如果想要更多的外部通道,可以选择引脚更多的型号,具体有多少通道还需要再参考一下数据手册来。
STM32 ADC框图
在这里左边是ADC的输入通道,包括十六个GPIO口,IN0到IN15和两个内部的通道:一个是内部温度传感器,另一个是VREFINT(V Reference Internal)内部参考电压,总共是十八个输入通道。
然后到达这里,这是一个模拟多路开关,可以指定我们想要选择的通道。
右边是多路开关的输出,进入到模数转换器。
这里模数转换器就是执行逐次比较的过程。转换结果会直接放在这个数据寄存器里,我们读取寄存器就能知道ADC转换的结果了。
然后在这里对于普通的ADC,多路开关一般都是只选中一个的,就是选中某个通道开始转换,等待转换完成取出结果,这是普通的流程。
但是这里就比较高级,它可以同时选中多个,而且在转换的时候还分成了两个组,规则通道组和注入通道组。
其中规则组可以一次性最多选十六个通道,注入组最多可以选中四个通道。
这有什么用?
举个例子,这就像是去餐厅点菜,普通的ADC是你指定一个菜,老板给做,然后做好了送给你。
而这里就是指定一个菜单,这个菜单最多可以填十六个菜,然后直接递个菜单给老板,老板就按照菜单的顺序依次做好,一次性给端上来,这样的话就可以大大提高效率。
当然你的菜单也可以只写一个菜,这样这个菜单就简化成了普通的模式了。
对于这个菜单,也有两种:
一种是规则组菜单,可以同时上十六个菜,但是它有个尴尬的地方,就是在这里这个规则组只有一个数据寄存器,就是这个桌子比较小,最多只能放一个菜。如果上十六个菜,前十五个菜都会被挤掉,只能得到第十六个菜。所以对于规则组转换来说,如果使用这个菜单的话,最好配合DMA来实现,DAM是一个数据转运小帮手,它可以在每上一个菜之后,把这个菜挪到其它地方去,防止被覆盖(被挤掉)。
因此,这个规则组虽然可以同时转换十六个通道,但是数据寄存器只能存一个结果。如果不想之前的结果被覆盖,在转换完成之后,就要尽快把结果拿走。
接着我们看一下注入组。
这个组比较高级,它相当于是餐厅的vip座位,在这个座位上,一次性最多可以点四个菜。并且这里数据寄存器有四个,是可以同时上四个菜的。对于注入组而言,就不用担心数据覆盖的问题了。
这就是规则组和注入组的介绍。
一般情况下,我们使用规则组就完全足够了。如果要使用规则组的菜单,就再配合DMA转运数据,这样就不用担心数据覆盖的问题了。
所以接下来只讲规则组的操作。
模数转换器外围线路
我们接着继续看这个模数转换器外围的一些线路。
首先左下角这里是触发转换的部分
也就是这里的start信号开始转换。
对于STM32的ADC,触发ADC开始转换的信号有两种:
一种是软件触发,就是在程序中手动调用一条代码就可以启动了。
另一种是硬件触发,就是这里的这些触发源。上面这些是注入组的触发源,下面这些是规则组的触发源。
这些触发源主要是来自于定时器,有定时器的各个通道,还有TRGO定时器主模式的输出。
这个之前讲定时器的时候也介绍过,定时器可以通向ADC/DAC这些外设用于触发转换。因为ADC经常需要过一个固定时间段转换一次,比如每隔一毫秒转换一次,正常的思路就是用定时器每隔一毫秒申请一次中断,在中断里手动开启一次转换,这样也是可以的。但是频繁进中断对我们的程序是有一定影响的。比如有很多中断都需要频繁进入,肯定会影响主程序的执行,并且不同中断之间,由于优先级的不同,也会导致某些中断不能及时得到响应。如果触发ADC的中断不能及时响应,那么ADC的转化频率就肯定会产生影响了。
所以对于这种需要频繁进中断,并且在中断里只完成了简单工作的情况,一般都会有硬件的支持。
比如这里就可以给TIM3定一个一毫秒的时间。并且把TIM3的更新事件选择为TRGO输出。然后在ADC这里选择开始触发信号为TIM3的TRGO。这样TIM3的更新事件就能通过硬件自动触发ADC转换了。
整个过程不需要进中断,节省了中断资源,这就是这里定时器触发的作用。
当然这里还可以选择外部中断引脚来触发转换,都可以在程序中配置。
这就是触发转换的部分。
然后接着看左上角:
vref+,vref-是ADC的参考电压,决定了ADC输入电压的范围。VDDA和VSSA是ADC的的共电引脚。
一般情况下,vref+要接VDDA,vref-要接VSSA。在我们这个芯片上,没有vref+和vref-的引脚。它在内部就已经和VDDA和VSSA接在一起了。
VDDA和VSSA在这个引脚定义里也可以看到,VDDA和VSSA是内部模拟部分的电源,比如ADC、RC振荡器,锁相环等。
在这里VDDA接3.3V,VSSA接GND,所以ADC的输入电压范围就是0到3.3V。
右边这里是ADC CLK是ADC的时钟
也就是这里的clock
是用于驱动内部逐次比较的时钟,它是来自ADC预分频器,
这个ADC预分频器是来源于RCC,在定时器中断那节我们所讲过的RCC时钟树框图里的这里
APB2时钟72MHz,然后通过ADC预分频器进行分频,得到ADC CLK,ADC CLK最大是14MHz。
这个预分频器选择二四六八分频。如果选择二分频,七十二兆除以二等于三十六兆,超出允许范围了。四分频之后是十八兆也超了。所以对于ADC预分频器只能选择六分频,结果是十二兆,八分频结果是九兆这两个值。这个在程序里要注意一下。
继续看上面这里是DMA请求,
这个就是用于触发DMA进行数据转运的,我们下节再讲。
然后是两个数据寄存器用于存放转换结果的。
上面这里还有模拟看门狗,它里面可以存一个阈值高限和阈值低限。
如果启动了模拟看门狗,并且指定了看门的通道,这个看门狗就会关注它看门的通道。一旦超过这个阈值范围了,它就会乱叫,就会在上面申请一个模拟看门狗的中断,最后通向NVIC。
对于规则组和注入组而言,它们转换完成之后,也会有一个EOC转换完成的信号。在这里EOC是规则组的完成信号。JEOC是注入组完成的信号。
这两个信号会在状态寄存器里置一个标志位,我们读取这个标志位,就能知道是不是转换结束了。同时,这两个标志位也可以去到NVIC,如果开启了NVIC对应的通道,它们就会触发中断。
有关ADC的这个框图就介绍完了。
ADC基本结构图
接下来看一下这里总结的一个ADC基本结构图
左边是输入通道,十六个GPIO口外加两个内部的通道,然后进入AD转换器。AD转换器里有两个组,一个是规则组,一个是注入组。规则组最多可以选中十六个通道,注入组最多可以选择四个通道。
然后转换的结果可以存放在AD数据寄存器里,其中规则组只有一个数据寄存器,注入组有四个。
然后下面这里有触发控制,提供了开始转换start信号。触发控制可以选择软件触发和硬件触发。硬件触发主要是来自于定时器,当然也可以选择外部中断的引脚。右边这里是来自于RCC的ADC时钟clock ,ADC逐次逼近的过程,就是由这个时钟推动的。
然后上面可以布置一个模拟看门狗,用于监测转换结果的范围。如果超出设定的阈值,就通过中断输出控制向NVIC申请中断。
另外,规则组和注入组转换完成后会有个EOC信号。它会置一个标志位,当然也可以通向NVIC。
最后右下角还有个开关控制,在库函数中,就是ADC_Cmd函数用于给ADC上电的。
这些就是STM32 ADC的内部结构图了。
输入通道
接下来我们再了解一些细节的问题,首先看一下输入通道:
刚才我们说ADC基本结构中有十六个外部通道,这十六个通道对应的都是哪些GPIO口?
我们就可以看一下这个表,这些就是ADC通道和引脚复用的关系,这个对应关系也可以通过引脚定义表看出来,比如ADC12_IN0对应的是PA0引脚(即ADC1和ADC2的IN0都是在PA0上)。
这里只有IN0到IN9,所以这个芯片就只能有十个外部通道。
ADC1和ADC2的引脚全都是相同的。
既然都相同,要ADC2还有啥用?
这个就要再说一个ADC的高级功能:就是双ADC模式。
双ADC模式就是ADC1和ADC2一起工作。它俩可以配合组成同步模式、交叉模式等等模式。
比如交叉模式,ADC1和ADC2交叉的对一个通道进行采样,这样就可以进一步提高采样率。就像打拳一样,左手打一拳,右手打一拳,左手打一拳,右手打一拳,快速交叉的打拳,打击的频率肯定就比一个拳头打的快。当然还有其它的模式,这里就不再细说了。
当然ADC1和ADC2也是可以分开使用的,可以分别对不同的引脚进行采样。
我们上面所列的通道表格有0到17总共是十八个通道。通道十六对应ADC1的温度传感器。通道十七对应ADC1的内部参考电压。只有ADC1有通道十六和十七,ADC2和ADC3是没有的。
ADC1和ADC2的引脚是完全相同的,ADC3中间会有些变化。注意:我们这个芯片也没有ADC3,不用管。我们这个芯片也没有PC0到PC5引脚,所以对应的通道也就没有。
规则组的四种转换模式
接下来我们再了解一下规则组的四种转换模式:
单次转换,非扫描模式;
连续转换,非扫描模式;
单次转换,扫描模式;
连续转换,扫描模式。
在ADC初始化的结构体里会有两个参数,一个是选择单次转换还是连续转换的,另一个是选择扫描模式还是非扫描模式的这两个参数组合起来,就有这四种转换方式。
我们来逐一看一下。
第一种:单次转换非扫描模式
这个是最简单的,可以看成这个表就是规则组里的菜单,有十六个空位,分别是序列一到序列十六。可以在这里点菜,就是写入要转换的通道。在非扫描的模式下,这个菜单就只有第一个序列一的位置有效。这时,菜单同时选中一组的方式,就退化为简单的选中一个的方式了。
在这里我们可以在序列一的位置,指定我们想转换的通道。比如通道二写到序列1位置,然后我们就可以触发转换,ADC就会对这个通道二进行模数转换,过一小段时间后,转换完成,转换结果放在数据寄存器里,同时给EOC标志位置1,整个转换过程就结束了。我们判断这个EOC标志位,如果转换完了,我们就可以在数据计容器里读取结果了。如果我们想再启动一次转换,就需要再触发一次,转换结束,置EOC标志位,读结果。
如果想换一个通道转换,在转换之前,把第一个位置的通道二改成其它通道,然后再启动转换,这样就行了。这就是单次转换非扫描的模式,没有用到这个菜单列表,也是比较简单的一种模式。
第二种:连续转换,非扫描模式
首先它还是非扫描模式,所以菜单列表就只用第一个。然后它与上一种单次转换不同的是,它在一次转换结束后不会停止,而是立刻开始下一轮的转换,然后一直持续下去,这样就只需要最开始触发一次之后,就可以一直转换了。
这个模式的好处就是开始转换之后,不需要等待一段时间的,因为它一直都在转换,所以就不需要手动开始转换了,也不用判断是否结束的。想要读AD值的时候,直接从数据寄存器取就是了。这就是连续转换非扫描的模式。
第三种:单次转换,扫描模式
这个模式也是单次转换,所以每触发一次转换结束后就会停下来,下次转换就得再触发才能开始。
然后它是扫描模式,这就会用到这个菜单列表的。可以在这个菜单里点菜。比如第一个菜是通道二,第二个菜是通道五等等。这点每个位置是通道几,可以任意指定,并且也是可以重复的。
然后初始化结构体里还会有个参数,就是通道数目。因为有十六个位置,可以不用完,只用前几个,就需要再给一个通道数目的参数,告诉它有几个通道。
比如这里指定通道数目为七,它就只看前七个位置。然后每次触发之后,它就依次对这前七个位置进行AD转换转换,结果都放在数据寄存器里。这里为了防止数据被覆盖,就需要用DMA,及时将数据挪走。
七个通道转换完成之后,产生EOC信号转换结束,然后再触发下一次,就又开始新能的转换。这就是单次转换扫描模式的工作流程。
第四种:连续转换,扫描模式
它就是在上一个模式的基础上变了一点,就是一次转换完成后,立刻开始下一次的转换。
间断模式
当然,在扫描模式的情况下,还可以有一种模式叫间断模式。
它的作用是在扫描的过程中,每隔几个转换就暂停一次。需要再次触发才能继续。大家了解一下就可以了,暂时不需要掌握。
触发控制
这个表就是规则组的触发源,也就是前面ADC框图的这里:
在这个表里有来自定时器的信号,还有这个来自引脚或定时器的信号,这个具体是引脚还是定时器需要用AFIO重映射来确定。最后是软件控制位,也就是我们之前说的软件触发。
这些触发信号怎么选择?
可以通过设置右边这个寄存器来完成。
当然使用库函数的话,直接给个参数就行了,这就是触发控制。
数据对齐
我们这个ADC是十二位的,它的转换结果就是一个十二位的数据。但是这个数据寄存器是十六位的,所以就存在一个数据对齐的问题。
数据右对齐
十二位的数据向右靠,高位多出来的几位就补零。
数据左对齐
十二位的数据向左靠低位,多出来的几位补零。
我们一般使用的都是第一种右对齐。这样读取这个十六位寄存器,直接就是转换结果。如果选择左对齐直接读的话,得到的数据会比实际的大。因为数据左对齐,实际上就是把数据左移了四次。二进制有个特点,就是数据左移一次,就等效于把这个数据乘二。这里左移了四次,就相当于把结果乘十六了。所以直接读的话会比实际值大十六倍。
要这个左对齐有啥用?
这个用途就是如果不想要这么高的分辨率,觉得0~4095数太大了,就做个简单的判断,不需要这么高分辨率,就可以选择左对齐,然后再把这个数据的高八位取出来。这样就舍弃掉了后面四位的精度,这个十二位的ADC就退化成了八位的ADC了。
这就是左对齐的作用。不过我们一般选右对齐就行了。如果需要裁剪一些分辨率,大不了就先把十二位都取出来再做处理,这也是可以的,就是多算了一步而已。
转换时间
转换时间这个参数我们一般不太敏感,因为一般AD转换都很快,如果不需要非常高速的转换频率,转换时间就可以忽略。
AD转换的步骤:采样,保持,量化,编码(ADC逐次比较的过程是需要花一段时间的,一般位数越多,花的时间就越长)
为什么需要采样保持?
这是因为我们的AD转换,就是后面的量化编码是需要一小段时间的。如果在这一小段时间里,输入的电压还在不断变化,就没法定位输入电压到底是在哪,所以在量化编码之前,我们需要设置一个采样开关。先打开采样开关,收集一下外部的电压,比如可以用一个小容量的电容存储一下这个电压,存储好了之后,断开采样开关,再进行后面的AD转换。这样在量化编码的期间,电压始终保持不变。这样才能精确的定位未知电压的位置,这就是采样保持电路。
采样保持的过程需要闭合采样开关,过一段时间再断开。这里就会产生一个采样时间。
采样时间是采样保持花费的时间,这个可以在程序中进行配置。
采样时间越大,越能避免一些毛刺信号的干扰。不过转换时间也会相应延长。
12.5个ADC周期是量化编码花费的时间。因为是12位的ADC,所以需要花费十二个周期。这里多了半个周期,可能是做一些其它东西花的时间。ADC周期就是从RCC分频过来的ADC CLK。这个ADC CLK最大是14MHz值。
下面有个例子,这里就是最快的转换时间。
这就是最快1us时间的来源。如果采样周期再长一些,它就达不到1us了。另外也可以把ADC CLK的时钟设置超过14MHz。这样ADC就是在超频,转换时间可以比1us还短,不过这样稳定性又没法保证了。
校准
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差
建议在每次上电后执行一次校准
启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期
这个看上去挺复杂的,但是我们不需要理解。这个校准过程是固定的,我们只需要在ADC初始化的最后加几条代码就行了。至于怎么计算,怎么校准的,我们不需要管,所以这个了解一下就行。
硬件电路
ADC的外围电路
第一个是电位器产生一个可调的电压,中间的滑动端就可以输出一个0到3.3V可调的电压输出。我们这里可以接ADC的输入通道,比如PA0口。
当滑动端往上滑时,电压增大,往下滑时,电压减小。另外注意一下电阻的阻值不要给太小,因为这个电阻两端也是直接跨接在电源正负极的,如果阻值太小,这个电阻就会比较费电,再小就有可能发热冒烟了,一般至少要接千欧级的电阻,比如这里接的是10k的电阻,这是电位器产生可调电压的电路。
然后中间是传感器输出电压的电路。
一般来说像光敏电阻、热敏电阻、红外接头管、麦克风等等都可以等效为一个可变电阻,那电阻阻值没法直接测量,所以这里就可以通过和一个固定电阻串联分压来得到一个反应电阻值电压的电路。
这里传感器阻值变小时,下拉作用变强,输出端电压就下降。传感器阻值变大时,下拉作用变弱,输出端受上拉电阻的作用,电压就会升高。
上面的固定电阻一般可以选择和传感器阻值相近的电阻,这样可以得到一个位于中间电压区域比较好的输出。但这里传感器和固定电阻的位置也可以换过来。这样的话,输出电压的极性就翻过来了,这就是这个分压方法来输出传感器阻值的电路。
之前传感器模块的介绍那里,传感器也是使用分压的方法来进行输出的。
我们这一节AD转换需要用到AO这个引脚,所以这里左边和右边这两块电路是没用的。
AO直接从这里输出,在这里接线:
我们回来接看一下最后这个电路:
这是一个简单的电压转换电路,比如想测一个零到五伏的VIN电压,但是ADC只能接收零到3.3V的电压,就可以搭建一个这样的简易转换电路,在这里还是使用电阻进行分压。上面阻值17k,下面阻值33k加一起是50k。所以根据分压公式,中间的电压就是VIN/50k*33k。最后得到的电压范围就是0到3.3V,就可以进入ADC转换了。这就是这个简单的电压转换电路。
如果想采集5V,10V这些电压的话,可以使用这个电路。但是如果电压再高一些,就不建议使用这个电路了,可能会比较危险。高电压采集最好使用一些专用的采集芯片,比如隔离放大器等等,做好高低电压的隔离,保证电路的安全。
ADC转换这部分在手册里也有详细介绍,感兴趣的可以自己去翻翻看。
ADC的介绍到这里就结束了,下节来开始写代码。
QQ交流群:963138186
本篇就到这里,下篇继续!欢迎点击下方订阅本专栏↓↓↓