1.ADC模数转换简介😊
-
STM32主要是数字电路,数字电路只有高低电平,没有几v电压的概念,所以想读取电压值,就需要借助ADC模数转换器来实现,ADC读取引脚上的模拟电压转换为一个数据存在寄存器里,我们再把这个数据读取到变量里来就可以进行显示、判断、记录等操作了。
-
输入电压范围:0到3.3V,转换结果范围:0 ~ 4095(12位)。(adc的输入电压一般要求是在芯片供电的负极和正极之间变化的,0v对应0,3.3v对应4095,中间都是一一对应的线性关系).
-
12位逐次逼近型ADC,1us转换时间。(逐次逼近型是ADC的工作模式;12位和1us涉及到adc的俩个关键参数,
- 第一个是分辨率,一般用多少位来表示,12位ad值表示范围就是02^12-1就是量化结果的范围0~4095,位数越高量化结果就越精细,对应分辨率就越高;
- 第二个是转换时间就是转换频率,ad转换是需要花一小段时间的,这里1us就是表示从ad转换开始到产生结果需要花1us的时间,对应ad转换的频率就是1MHz(1MHz的周期是1微秒,是stm32的adc最快转换频率),如果你需要转换一个频率非常高的信号那就需要考虑一下这个转换频率是不是够用,如果你的信号频率比较低那这个最大1MHz的转换频率也完全够用)。
-
规则组和注入组两个转换单元。(是stm32 adc的增强功能,普通的ad转换流程是启动一次转换读一次值然后再启动再读值这样的流程,stm32的adc可以列一个组,一次启动一个组连续转换多个值并且有两个组,一个是用于常规使用的规则组,一个是用于突发事件的注入组)。
-
stm32由12个采集通道,10个外部通道,2个内部通道(一个连接在内部温度传感器上,一个连接在内部参考电压上)
12位逐次逼近法不懂的话看一看【STM32入门教程】ADC 模拟数字转换 ,超清晰动画讲解_哔哩哔哩_bilibili
2.逐次逼近型ADC(ADC0809外置ADC芯片)
-
ADC0809是一个独立的8位逐次逼近型ADC芯片。它拥有IN0~IN7,8个输入通道,通过地址锁存器和译码器电路实现对通道的选择,且每一次转换通道选择开关只能转换一个通道的信号(输入通道选择这部分相当于一个可以通过模拟信号的数据选择器)。
-
ADC转换的速度非常快,从信号转换开始到结束只需要几个us的时间,如果想转换多路信号,不必设计多个ADC,只需要在每一次转换前通过多路选择开关选择要转换的通路即可。
-
接下来如何知道这个电压对应的编码数据是多少呢:就需要用逐次逼近的方法一一比较了。
- 一个外部通道输入的未知编码的电压和一个DAC输出。已知编码的电压,它俩同时输入到电压比较器进行大小判断 输出一个高低电平指示谁大谁小。两个输入端一个是待测电压,另一个是DAC的电压输出端,给dac一个数据它就可以输出数据对应的电压,若dac输出的电压比较大就调小DAC数据,若dac输出电压比较小就增大dac数据,直到dac输出电压和外部通道输入的电压近似相等,这样dac输入的数据就是外部电压的编码数据了,这就是DAC的实现原理,这个电压调节的过程就是逐次逼近SAR来完成的。
-
ADC内部拥有一个DAC模块,其内部是通过加权电阻网络实现模数转换,可以将逐次逼近寄存器SAR的值转换为对应的模拟电压值,将其电压值再与待测电压相比较,比较结果控制SAR中存储的值,直到DAC输出的电压与外部通道输入的电压近似相等,DAC输入的数据就是外部电压的编码数据了。
-
为了最快找到未知编码的电压,通常使用二分法进行查找
-
结构图上方的EOC(End Of Convert)是转换结束信号。该芯片通过START端口控制转换开始(给一个输入脉冲,开始转换),CLOCK是adc时钟(因为adc内部是一步一步进行判断的所以需要时钟来推进这个过程)控制ADC内部的转换工作频率。
3.ADC结构框图(STM32内置)
-
总共有18个输入通道包括16个gpio口(IN0~IN15)和2个内部通道(内部温度传感器和内部参考电压)。模拟多路开关可以指定我们想要的通道,右边是多路开关的输出,进入到模数转换器(这里模数转换器就是执行刚讲的逐次比较的过程),转换结果会直接放在数据寄存器里,读取寄存器就能知道adc转换的结构了
-
stm32的多路开关就比较高级,可以同时选中多个,而且在转换的时候还分成了两个组(规则组和注入组),其中规则组可以一次性最多选中16个通道,注入组最多可以选中4个通道。
- 以餐厅点菜模型为例,普通模式为每次点一个菜,做好菜后上菜;STM32可以做到每次列出一个菜单,规则组一次最多可以列16个菜(但是一次只能作一个(规则通道数据寄存器只有16位),会造成数据覆盖,因此需要配合DMA使用),注入组一次最多可以列4个菜,做好后依次上菜。(注入组不常用,只讲规则组)
- 结构图的左下角为触发转换信号,对应ADC0809的START信号。STM32的触发转换信号来源有两种:软件触发和硬件触发。软件触发就是在程序中手动调用一条代码就可以启动转换了。硬件触发信号可以来自于定时器的各个通道、定时器TRGO定时器主模式的输出,外部中断EXTI。
- 这里ADC的时钟ADCCLK是来自于RCC的APB2时钟。由原理图可得,ADCCLK最大为14MHz,所以ADC预分频器只能选择6分频(得到12MHz)和8分频(得到9MHz)两个值。
- 模拟看门狗的功能是监测指定的通道。可以设置模拟看门狗的阈值高限(12位)、阈值底限(12位)和指定“看门”的通道。只要通道的电压值超过阈值范围,模拟看门狗就会“乱叫”,申请一个模拟看门狗的中断,之后通向NVIC。
- ECC是规则组的完成信号,JEOC是注入组完成信号,这两个信号会在状态寄存器里置一个标志位,读取这个标志位,就能知道是不是转换结束了,同时这两个标志位也可以去到NVIC申请中断,如果开启了NVIC对应的通道就会触发中断。
4.ADC基本结构
如图,左边是输入通道,16个GPIO口外加两个内部通道,然后进行AD转换器,ad转换器里有两个组,一个是规则组、一个是注入组。规则组最多可以选中16个通道,注入组最多可以选择4个通道。 然后转换的结果可以存放在AD数据寄存器里,其中规则组有1个数据寄存器,注入组有4个,然后有触发控制提供了开始转换的START信号,触发控制可以选择软件触发和硬件触发,硬件触发主要来自定时器,也可以选择外部中断引脚,然后还有ADC时钟CLOCK来自RCC,adc逐次比较的过程就是由这个时钟推动的。 然后可以布置一个模拟看门狗用于检测转换结果的范围,如果超出设定的阈值就通过中断输出控制向NVIC申请中断。 另外规则组和注入组转换完成后会有个EOC信号会置一个标志位,当然也可以通向NVIC,最后还有个右下角有个开关控制,在库函数中就是ADC_Cmd函数用于给ADC上电,以上就是STM32ADC的内部结构了。
输入通道
- 由ADC的内部结构可知,STM32的ADC对应16个输入通道。这16个输入通道对应的GPIO端口如图。
- 参考引脚定义表可以看到,STM32的ADC1和ADC2的引脚是相同的。这样的设计是为双ADC模式服务的。关于双ADC模式的内容比较复杂,这里仅作简单了解即可。
- 双ADC模式,即ADC1和ADC2同时工作,二者可以配合为同步模式、交叉模式等多种不同的工作模式。以交叉模式为例,ADC1和ADC2交叉对同一个通道进行采样,这样就可以进一步提高采样率(交叉模式就像你打拳一样,左手打一圈、右手打一圈快速交叉地打拳,那打击的频率肯定比一个拳头打得快)。当然ADC1和ADC2也是可以分开用的,可以分别对不同的引脚进行采样,这样也是可以的。
5.ADC规则组的模式
-
单次转换 非扫描模式
-
单次转换 扫描模式
-
连续转换 非扫描模式
-
连续转换 扫描模式
-
单次转换:每触发一次,转换结束就会停下来,下次转换就得再触发才能开始。
-
连续转换: 转换完一个通道后立即自动执行下一个通道的转换(肯定选连续转换啊)()
-
非扫描模式:只对存放在序列1的通道起作用。
-
扫描模式:用到“菜单”列表,可以在菜单里点菜,每个菜单列表位置是通道几是可以任意指定的并且可以重复,然后初始化结构体有个通道数目的参数(表明用了几个通道)(总之,开启后,自动的连续读取多个通道)
-
扫描模式下转换到数据寄存器的过程中,用DMA防止数据被覆盖,DMA进行数据及时转移
在扫描模式的情况下,还可以使用间断模式。它的作用是在扫描的过程中,每隔几次转换就暂停,需要再次触发才能继续。该模式仅作了解即可。
触发控制
这个图是结构框图中的:
- 这个表,有来自定时器的信号、来自引脚或定时器的信号。这里具体是引脚还是定时器需要用AFIO重映射来确定,最后是软件控制位(就是软件触发)
转换时间(提及sampling time )
-
AD转换的步骤分别是:采样、保持、量化、编码。其中采样和保持可以看作一个过程,量化和编码可以看作一个过程。量化和编码,实际上就是ADC逐次比较的过程,一般ADC的位数越多,所花费的时间就越长。
-
采样和保持,是为了保证在量化和编码的过程中输入电压的变化不会过大。在量化和编码之前,需要添加采样-保持电路,即需要设置一个采样开关,打开开关一段时间来收集电压(可以用一个小容量的电容来存储这个电压),存储完成之后断开开关,再进行之后的AD转换。这样就可以保证在量化和编码器件始终保持电压基本不变。这就是采样保持电路。
-
采样保持的过程,会产生一个采样时间,这个采样时间是比较长的。ADC的采样时间可以在程序中进行配置。之后花费12个ADC周期进行量化和编码,多余的0.5个周期完成了其他的工作。ADC周期就是从RCC分频过来的ADCCLK,
ADCCLK最大是14MHz
硬件电路
-
第一个是电位器产生可调电压的电路。电位器产生一个可调电压,这里电位器的两个固定端,一端接3.3v一端接GND,这样中间的滑动就可以输出一个0~3.3v可调的电压输出,可以接ADC的输入通道比如PA0口,当滑动端往上滑时,电压增大,往下滑时电压减小,注意电阻的阻值不能给太小因为电阻两端也是直接跨接在电源正负极的,如果阻值太小电阻就会比较费电,再小就有可能发热冒烟 ,一般至少接kΩ级的电阻,比如这里接的是10k电阻。
-
第二个是分压方法来输出传感器阻值的电路。一般来说像光敏电阻、热敏电阻、红外接收管、麦克风等都可以等效为可变电阻N1,电阻值无法直接测量,所以就可以通过和一个固定电阻(R1)串联分压来得到一个反应电阻值的电压的电路。传感器N1阻值变小时,下拉作用变强,输出端PA1电压就下降;传感器N1阻值变大时,下拉作用变弱,输出端PA1受上拉电阻的作用,电压就会升高。固定电阻R1一般可以选择和传感器N1阻值相近的电阻,这样可以得到一个位于中间电压区域比较好的输出,当然这里的固定电阻R1和传感器N1的位置也可以缓过来,这样输出电压的极性就反过来了。
-
第三个是简单的电压转换电路。比如你想测一个0-5v的VIN电压,但是ADC只能接受0-3.3v的电压,那就可以使用这样的简易转换电路,还是使用电阻进行分压,上面电阻r1阻值17k,下面阻值r2是33k,一共是50k,根据分压公式,中间的电压就是VIN/50K * 33k最后得到的电压范围就是0-3.3v,就可以进入ADC转换了,这就是简单的电压转换电路。若想采集5v、10v这些电压的话就可以使用这个电路,但是若电压再高些就不建议使用这个电路了可能会比较危险,高电压采集最好使用一些专用的采集芯片,比如隔离放大器等,做好高低电压的隔离,保证电路的安全。
如果AD的最终值有跳变
-
现象AD的值有些抖动,可以采用迟滞比较的方法来完成,设置两个阈值,低于下阈值开灯,高于上阈值,关灯,这就可以避免输出抖动的问题。
-
觉得数据跳变的太厉害,可以采用滤波的方法,让AD的值平滑一些,如均值滤波,读10个或20个值,取平均值,作为AD滤波的值。
-
或还可以裁剪分辨率,把数据的尾数去掉,这样也可以减少数据波动。
传感器的接法
注意DO不用接,ADC,D为数字,A为模拟,因此接AO口
6.HAL库配置ADC
- 只需要选择你需要的ADC开启通道即可
- 注意开启连续转换模式,这样就不用将ADC开启放在while中了
- 也可以开启,ADC的扫描模式(上面提到:扫描模式:用到“菜单”列表,可以在菜单里点菜,每个菜单列表位置是通道几是可以任意指定的并且可以重复,然后初始化结构体有个通道数目的参数(表明用了几个通道)) 注意:扫描模式不可直接打开需要在下面的NUMBER of conversion 中,增加一个通道,便会自动打开
- 这两个选项便可以测量stm32的内部温度和内部电压,不过需要注意,要将规则组通道加上这两个,还要将 内部参考电压的通道测量周期便为71.5个周期(内部电压测采样时间典型值为5.1us,因此5.1us*1/F=61.2个)
DMA
首先点add添加一个dma通道
-
描述中显示:Periph TO Memory,也即外设到内存,也就是规则组数据寄存器到内存变量
-
数据寄存器只有1个,因此不进行地址自增
- 而数据要依次写入数组的4个位置,因此内存端的数据要进行自增
- ADC分辨率为12位,因此每次传递数据的宽度位半个字(1个字节8位,一个字4个字节)
- 注意要在 ,初始化函数中加上 校准函数
HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);//adc2 单端模式