STM32 ADC数模转换器
ADC简介
-
ADC(Analog-Digital Converter)模拟-数字转换器
-
ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
- STM32主要是数字电路,数字电路只有高低电平,没有几V电压的概念,所以如果想读取电压值,就需要借助ADC模数转换器来实现了,ADC读取引脚上的模拟电压,转换为一个数据,存在寄存器里,我们再把这个数据读到变量里来,就可以进行显示、判断、记录等等操作了,ADC可以将模拟信号转换为数字信号,是模拟电路到数字电路的桥梁。
- DAC,数字模拟转换器,使用DAC就可以将数字量转化为模拟电压;PWM也可以作为数字电路到模拟电路的桥梁,同时PWM只有完全导通和完全断开两种状态,在这两种状态上都没有功率损耗,所以在直流电机这种大功率的应用场景,使用PWM来等效模拟量是比DAC更好的选择,并且PWM电路更加简单,更加常用。目前DAC的应用主要是在波形发生这些领域,比如信号发生器、音频解码芯片等。
-
12位逐次逼近型ADC,1us转换时间
- ADC的两个关键参数
- 分辨率,一般用多少位来表示,12位AD值,它的表示范围就是0~212-1,就是量化结果的范围是0~4095,位数越高,量化结果就越精细,对应分辨率就越高。
- 转换时间(转换频率),AD转换需要花费一小段时间,这里1us就表示从AD转换开始,需要花1us的时间,对应AD转换的频率就是1MHz,这个就是STM32ADC的最快转换频率,如果你需要转换一个频率非常高的信号,那就要考虑一下这个转换频率是不是够用,如果你的信号频率比较低,那最大1MHz的转换频率也完全够用了。
- ADC的两个关键参数
-
输入电压范围:0~3.3V,转换结果范围:0~4095
- ADC的输入电压,一般要求都是要在芯片供电的负极和正极之间变化的,最低电压就是负极0V,最高电压是正极3.3V,经过ADC转换滞后,最小值就是0,最大值是4095,0V对应0,3.3V对应4095,中间都是一一对应的线性关系。
-
18个输入通道,可测量16个外部和2个内部信号源
- 外部信号源就是16个GPIO口,在引脚上直接接模拟信号即可,不需要任何额外的电路,引脚就能直接测电压。
- 两个内部信号源是内部温度传感器和内部参考电压
- 温度传感器可以测量CPU的温度,比如电脑可以显示一个CPU的温度,就可以用ADC读取这个温度传感器来测量。
- 内部参考电压是一个1.2V左右的基准电压,这个基准电压是不随外部供电电压变化而变化的,所以如果芯片供电不是标准的3.3V,那测量外部引脚的电压可能就不对,这时就可以读取这个基准电压进行校准,就能得到正确的电压值了。
-
规则组和注入组两个转换单元
- 普通的AD转换流程是,启动一次转换,读一次值,然后再启动,再读值,这样的流程。
- 但是STM32的ADC可以列一个组,一次性启动一个组,连续转换多个值,并且有两个组
- 一个是用于常规使用的规则组
- 一个是用于突发事件的注入组,
-
模拟看门狗自动监测输入电压范围
- 一般可以用于测量光线强度、温度这些值,并且经常会有个需求,就是如果光线高于某个阈值、低于某个阈值,或者温度高于某个阈值、低于某个阈值时,执行一些操作,这个高于某个阈值、低于某个阈值的判断,就可以用模拟看门狗来自动执行,模拟看门狗可以检测指定的某些通道,当AD值高于它设定的上阈值或者低于下阈值时,它就会申请中断,你就可以在中断函数里执行相应的操作,这样就不用不断地手动读值,在进行if判断操作了。
-
STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道
- 最多只能测量10个外部引脚的模拟信号。之前说的16个信号源,这是这个系列最多有16个外部信号。但是STM32F103C8T6芯片引脚比较少,有很多引脚没有引出来,所以就只有10个外部信号源。如果需要更多的外部通道,可以选择引脚更多的型号。
逐次逼近型ADC
- STM32的ADC与ADC0809的工作原理相同,均为逐次逼近型ADC,所以为了更好地理解STM32ADC的工作原理,我们不妨先来看一下逐次逼近型ADC的工作原理。
- ADC0809是一个独立的8位逐次逼近型ADC芯片,在以前的时候,单片机的性能还不是很强,所以需要外挂一个ADC芯片才能进行AD转换,现在单片机的性能和集成度都有很大的提升,很多单片机内部就已经集成了ADC外设,这样就可以不用外挂芯片了,引脚可以直接测电压,使用很方便。
-
首先左边是IN0~IN7,一共是8路输入通道,并通过通道选择开关,选择一路,输入到电压比较器进行转换。
-
下面是地址锁存和译码,就是你想选中哪个通道,就把通道号放在这三个脚上(三个bit位对应0~7),然后给一个锁存信号,上面这里对应的通路开关就可以自动拨好了,这部分就相当于一个可以通过模拟信号的数据选择器。
-
因为ADC转换是一个很快的过程,你给个开始信号,过几个us就转换完成了,所以说如果你想转换多路信号,那不必涉及多个AD转换器,只需要一个AD转换器,然后加一个多路选择开关,像转换哪一路,就先拨一下开关,选中对应通道,然后再开始转换就行了。
- STM32内部的ADC有18个输入通道,对应这里,就是一个18路输入的多路开关。
-
输入信号选择完成后,如何知道这个电压对应的编码数据是多少呢,这就需要用逐次逼近的方法来一一比较了。电压比较器,可以判断两个输入信号电压的大小关系,输出一个高低电平指示谁大谁小,它的两个输入端,一个是待测的电压,另一个是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的供电是一样的。
ADC框图
- ADC的输入通道(ADCx_IN0~15、温度传感器、VREFINT)包括16个GPIO口,IN0~IN15,和两个内部的通道,一个是内部温度传感器,一个是VREFINT(V Reference Internal) 内部参考电压。总共是18个输入通道,然后到达模拟多路开关,可以指定我们想要选择的通道,右边是多路开关的输出,进入到模数转换器,这里的模数转换器执行的就是逐次比较的过程,转换结果会直接放到数据寄存器里,读取寄存器就可以知道ADC转换的结果了。
- 对于普通的ADC,多路开关一般都是只选中一个,就是选中某个通道、开始转换、等待转换完成、取出结果。但是STM32的ADC可以同时选中多个通道,而且在转换的时候,还分成了两个组,规则通道组和注入通道组。
- 规则组可以一次性最多选中16个通道
- 注入组可以一次性最多选中4个通道
举个例子
- 就像去餐厅点菜,普通的ADC是指定一个菜,老板给你做,然后做好了送给你
- STM32的ADC就是指定一个菜单,这个菜单最多可以填16个菜,然后直接递个菜单给老板,老板就按照菜单的顺序依次做好,一次性给你端上来,这样的话就可以大大提高效率,当然你的菜单也可以只写一个菜,这样这个菜单就简化成了普通模式了。那对于这个菜单呢,也有两种
- 一种是规则组菜单,可以同时上16个菜,但是规则组只有一个数据寄存器,就是这个桌子比较小,最多只能放一个菜,如果上16个菜,那前15个菜都会被挤掉,你只能得到第16个菜,多以对于规则组转换来说,如果使用这个菜单的话,最好配合DMA来实现,DMA可以实现数据转运,它可以在每上一个菜之后,把这个菜挪到其它地方去,防止被覆盖。
- 规则组虽然可以同时转换16个通道,但是数据寄存器只能存一个结果,如果不想之前的结果被覆盖,那在转换完成之后,就要尽快把结果拿走。
- 注入组,相当于是餐厅的VIP座位,在这个座位上,一次性最多可以点4个菜,并且这里数据寄存器有4个,是可以同时上4个菜的,对于注入组而言,就不用担心数据覆盖的问题了。
- 触发转换(START 开始转换),对于STM32的ADC,触发ADC开始转换的信号有两种。
- 软件触发,就是在程序中手动调用一条代码,就可以启动转换了
- 硬件触发,就是这里的这些触发源
- 这些触发源主要来自于定时器,有定时器的各个通道,还有TRGO定时器主模式的输出,定时器可以通向ADC、DAC这些外设,用于触发转换,因为ADC经常需要过一个固定时间转换一次,比如每隔1ms转换一次,正常的思路就是用定时器,每隔1ms申请一次中断,在中断里手动开启一次转换,但是频繁进中断对程序会造成一定的影响,比如你有很多中断都需要频繁进入,那肯定会影响主程序的执行,并且不同中断之间,由于优先级的不同,也会导致某些中断不能及时得到响应,如果触发ADC的中断不能及时响应,那ADC的转换频率肯定会产生影响,所以对于这种需要频繁进中断,并且在中断里只完成简单工作的情况,一般都会有硬件的支持,比如这里就可以给TIM3定个1ms的时间,并且把TIM3的更新时间选择为TRGO输出,然后在ADC这里,选择开始触发信号为TIM3_TRGO,这样TIM3的更新时间就能通过硬件自动触发ADC转换了,这个过程不需要进中断,节省了中断资源,当然这里还可以选择外部中断引脚来触发转换。
- 注入组触发源
- 规则组触发源
- TIM1_CH1
- TIM1_CH2
- TIM1_CH3
- TIM2_CH2
- TIM3_TRGO
- TIM4_CH4
- VREF+、VREF-、VDDA和VSSA
- VREF+、VREF-是ADC的参考电压,决定了ADC输入电压的范围,
- VDDA和VSSA是ADC的供电引脚
- 一般情况下VREF+要接VDDA,VREF-要接VSSA,在STM32F103C8T6上没有VREF-和VREF+的引脚,其在内部就已经和VDDA和VSSA接在一起了,VDDA和VSSA是内部模拟部分的电源,比如ADC、RC振荡器、锁相环等,在这里VDDA接3.3V,VSSA接GND,所以ADC的输入电压范围就是0~3.3V。
- ADCCLK是ADC的时钟(CLOCK),适用于驱动内部逐次比较的时钟,来自ADC预分频器,这个ADC预分频器来源于RCC时钟树,APB2 72MHz然后通过ADC预分频器进行分频,得到ADCCLK,但ADCCLK最大是14MHz,所以这个预分频器就有点尴尬,可以选择2,4,6,8分频,但选择2分频和4分频都超出了14MHz,所以对于ADC预分频器,只能选择6分频,结果是12MHz和8分频,结果是9MHz,这两个值。
- DMA请求,用于触发DMA进行数据转运。
- 两个数据寄存器,注入通道数据寄存器,规则通道数据寄存器,用于存放转换结果。
- 模拟看门狗,可以存一个阈值高限和阈值低限,如果启动了模拟看门狗,并制定了看门的通道,那这个看门狗就会关注它看门的通道,一旦超过这个阈值范围,就会申请一个模拟看门狗的中断,最后通向NVIC。、
- 对于规则组和注入组而言,它们转换完成之后,也会有一个EOC转换完成的信号,在这里,EOC是规则组的完成信号,JEOC是注入组的完成信号,这两个信号会在状态寄存器置一个标志位,读取这个标志位,就可以知道是不是转换结束了,同时这两个标志位也可以去到NVIC,申请中断,如果开启了NVIC对应的通道,它们就会触发中断。
ADC基本结构
- 输入通道,包括16个GPIO口,外加两个内部的通道。
- 进入AD转换器,AD转换器里有两个组,转换的结果可以存放在AD数据寄存器中
- 规则组,最多可以选择16个通道,只有1个数据寄存器
- 注入组,最多可以选择4个通道,有4个数据寄存器
- 触发控制,提供了开始转换这个START信号,触发控制可以选择软件触发和硬件触发,硬件触发主要是来自于定时器,当然也可以选择外部中断的引脚
- 来自RCC的ADC时钟CLOCK,ADC逐次比较的过程就是由这个时钟推动的。
- 可以布置一个模拟看门狗用于监测转换结果的范围,如果超出设定的阈值,就通过中断输出控制,向NVIC申请中断。
- 规则组和注入组转换完成后会有个EOC信号,它会置一个标志位,当然也可以通向NVIC。
- 开关控制,ADC_Cmd(),使能ADC。
输入通道
- STM32F103C8T6的ADC12_IN0对应的是PA0引脚,IN1对应PA1引脚,然后IN2~9,依次对应的是PA2到PB1,总共只有10个通道,ADC12_IN0的意思是,ADC1和ADC2的IN0都在PA0上,ADC1和ADC2的引脚全都是相同的。
- 双ADC模式,ADC1和ADC2一起工作,可以配合组成同步模式、交叉模式等模式,比如交叉模式,ADC1和ADC2交叉地对一个通道进行采样,据可以进一步提高采样率。
- 通道16对应ADC1的温度传感器,通道17对应ADC1的内部参考电压,只有ADC1由通道16和17,ADC2和ADC3是没有的
通道 | ADC1 | ADC2 | ADC3 |
---|---|---|---|
通道0 | PA0 | PA0 | PA0 |
通道1 | PA1 | PA1 | PA1 |
通道2 | PA2 | PA2 | PA2 |
通道3 | PA3 | PA3 | PA3 |
通道4 | PA4 | PA4 | PF6 |
通道5 | PA5 | PA5 | PF7 |
通道6 | PA6 | PA6 | PF8 |
通道7 | PA7 | PA7 | PF9 |
通道8 | PB0 | PB0 | PF10 |
通道9 | PB1 | PB1 | |
通道10 | PC0 | PC0 | PC0 |
通道11 | PC1 | PC1 | PC1 |
通道12 | PC2 | PC2 | PC2 |
通道13 | PC3 | PC3 | PC3 |
通道14 | PC4 | PC4 | |
通道15 | PC5 | PC5 | |
通道16 | 温度传感器 | ||
通道17 | 内部参考电压 |
转换模式
在ADC初始化的结构体中,有两个参数,一个是选择单次转换还是连续转换,另一个是选择扫描模式还是非扫描模式的。
这两个参数组合起来就有这4种转换方式。
- 单次转换,非扫描模式
- 列表就表示规则组里的菜单,有16个空位,分别是序列1到序列16,可以在这里“点菜”,就是写入你要转换的通道,在非扫描的模式下,这个菜单就只有第一个序列1的位置有效,这时,菜单同时选中一组的方式就退化为简单地选中一个的方式了。
- 在这里我们可以在序列1的位置指定我们想转换的通道,比如通道2,写到序列1的位置,然后我们就可以触发转换,ADC就会对这个通道2进行模式转换,过一小段时间后,转换完成,转换结果放在数据寄存器里,同时给EOC标志位置1,整个转换过程就结束了。
- 判断这个EOC标志位,如果转换完了,就可以在数据寄存器里读取结果了,如果我们想再启动一次转换,那就需要再触发一次,转换结束,置EOC标志位,读结果。
- 如果想换一个通道转换,那在转换之前,把第一个位置的通道2改成其他通道,然后再启动转换,这样就行了。
- 连续转换,非扫描模式
- 还是非扫描模式,所以菜单列表中就只用第一个。
- 与单次转换不同的是,连续转换在一次转换结束后不会停止,而是立刻开始下一轮的转换,然后一直持续下去,这样就只需要最开始触发一次,之后就可以一直转换了。
- 这个模式的好处就是,开始转换后不需要等待一段时间,因为它一直都在转换,所以就不需要手动开始转换了,也不用判断是否结束,想要读AD值的时候,直接从数据寄存器取就是了。
- 单次转换,扫描模式
- 单次转换,所以每触发一次,转换结束后就会停下来,下次转换就得再触发才能开始。
- 扫描模式,这就要用到这个菜单列表了,你可以在菜单里点菜,比如第一个序列1是通道2,序列2是通道5等等,这里每个位置是通道几可以任意指定,并且也是可以重复的。
- 初始化结构体里还有个参数,通道数目,因为这16个位置你可以不用完,只用前几个,那你就需要再给一个通道数目的参数,告知有几个通道,比如下面指定通道数目为7,那它就只看前7个位置,然后每次触发之后,它就会一次对前7个位置进行AD转换,转换结果都放在数据寄存器里,为了防止数据被覆盖,就需要用DMA及时将数据挪走,那7个通道转换完成之后,产生EOC信号,转换结束,然后再触发下一次,就又开始新一轮的转换。
- 连续转换,扫描模式
- 一次转换完成后,立刻开始下一次的转换。
- 在扫描模式的情况下,还可以有一种模式,叫间断模式,它的作用是,在扫描的过程中,每隔几个转换,就暂停一次,需要再次触发,才能继续。
触发控制
数据对齐
-
ADC是12位的,它的转换结果就是一个12位的数据,但是数据寄存器是16位的,所以就存在一个数据对齐的问题。
- 一般使用数据右对齐,这样读取这个16位的数据寄存器,直接就是转换结果。
- 如果选择左对齐,直接读的话,得到的数据会比实际的大,因为数据左对齐实际上就是把数据左移了4位,二进制有个特点,就是数据左移一次,就等效于把这个数据乘2,这里左移了4次,就相当于把结果乘16了,所以直接读的话,会比实际值大16倍。
-
数据右对齐:12位的数据向右靠,高位多出来的几位就补0
- 一般选右对齐,如果需要裁剪一些分辨率,可以先把12位都取出来,再作处理。
- 数据左对齐:12位的数据想左靠,低位多出来的几位就补0
- 左对齐的用途就是,如果不想要这么高的分辨率,0~4095数太大了,就只需要做个简单的判断,不需要这么大的分辨率,那你就可以选择左对齐,然后再把这个数据的高8位取出来,这样就舍弃了后面4位的精度,这个12位的ADC就退化成了8位的ADC。
转换时间
转换时间这个参数,一般不太敏感,因为一般AD转换都很快,如果不需要非常高速的转换频率,那转换时间就可以忽略了,AD转换是需要一小段时间的。
-
AD转换的步骤:采样,保持,量化,编码
-
AD转换,需要一小段时间,如果在这一小段时间里,输入的电压还在不断变化,就无法定位输入电压到底在哪了,所以在量化编码之前,我们需要设置一个采样开关,先打开采样开关,收集一下外部电压,比如可以用一个小容量的电容存储一下这个电压,存储好了之后,断开采样开关,在进行后面的AD转换,这样在量化编码的期间,电压始终保持不变,这样才能精确地定位未知电压的位置,这就是采样保持电路。那采样保持的过程,需要闭合采样开关,过一段时间再断开,这里就会产生一个采样时间。
-
量化编码,就是ADC逐次比较的过程,这个过程需要花费一段时间,一般位数越多,花的时间越长。
-
-
STM32 ADC的总转换时间为:
- TCONV = 采样时间 + 12.5个ADC周期
- 采样时间是采样保持花费的时间,可以在程序中进行配置,采样时间越大,越能避免一些毛刺信号的干扰,不过转换时间也会相应延长。
- 12.5个ADC周期是量化编码花费的时间,因为是12位的ADC,所以要花费12个周期,这里多了0.5个周期,可能是做一些其他东西花的时间。ADC周期就是从RCC分频过来的ADCCLK,这个ADCCLK最大是14MHz。
-
例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期
- TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs
校准
-
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差
-
建议在每次上电后执行一次校准
-
启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期文章来源:https://www.toymoban.com/news/detail-738192.html
-
这个校准过程是固定的,我们只需要在ADC初始化的最后,加几条代码即可。文章来源地址https://www.toymoban.com/news/detail-738192.html
5 + 12.5 = 14个ADC周期 = 1μs
校准
-
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差
-
建议在每次上电后执行一次校准
-
启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期
-
这个校准过程是固定的,我们只需要在ADC初始化的最后,加几条代码即可。
到了这里,关于STM32 ADC数模转换器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!