STM32中ADC模数转换器

发布于:2024-12-20 ⋅ 阅读:(16) ⋅ 点赞:(0)

一、ADC简介

ADC模拟-数字转换器

ADC可以将引脚连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁

12位逐次逼近型ADC,1us转换时间

输入电压范围: 0~3.3V,转换结果范围:0~4095

18个输入通道,可测量16个外部和2个内部信号源

规则组和注入组两个转换单元

模拟看门狗自动检测输入电压范围

STM32F2103C8T6  ADC资源:ADC1、ADC2、10个外部输入通道

二、逐次逼近型ADC

逐次逼近型ADC内部结构

ADC0809:是一个独立的8位逐次逼近型ADC芯片,在以前的时候,单片机的性能还不是很强,所以需要外挂一个ADC芯片才能进行AD转换,这个ADC0809就是一款比较经典的ADC芯片,但现在单片机的性能和集成度都有很大的提升,很多单片机内部就已经集成了ADC外设,这样就不用外挂芯片了,引脚可以直接测电压,使用还是非常方便的

结构的分析

首先在最左边这里IN0~IN7,是8路输入通道,通过通道选择开关,选中一路,输入到比较器前面的箭头的位置进行转换

其次下面的这里是地址锁存器和译码:就是你想选择哪个通道,就把通道号放在这三个脚上,然后给一个锁存信号,上面这里对应的通道开关就可以自动拨好了

上面这两个部分就可以看作是一个可以通过模拟信号的数据选择器

因为ADC转换是一个很快的过程,你给一个开始信号,过个us就转换完成了,所以说如果想转换多路信号,那不必设计多个AD转换器,只需要一个AD转换器,然后加一个多路选择开关,想转换哪一路,就先拨一下开关,选中对应通道,然后在开始转换就行了

这就是输入通道选择的部分,这个ADC0809只有8个输入通道,我们STM32内部的ADC是有18个输入通道的,所以对应这里,就是一个18路输入的多路开关,然后输入信号我们选择好了,我们来看下一部分

怎么才能知道这个电压对应的编码数据是多少呢

这个就需要我们用逐次逼近的方法来一一比较了,首先一个电压比较器,它可以判断两个输入信号电压的大小关系,输出一个高低电平指示谁大谁小,它的两个输入端,一个待测的电压,另一个这里DAC的电压输出端,DAC是数模转换器(给他一个数据,他就可以输出数据对应的电压,DAC内部是使用加权电阻网络来实现的转换,想要深入探究看江科大51单片机教程里的DA/AD一节)

现在我们有了一个外部通道输入的未知编码的电压和一个DAC输出的已知编码的电压,它们同时输入到电压比较器,进行大小判断,如果ADC输出的电压比较大,我就调小DAC数据,如果DAC输出的电压比较小,我就增大DAC数据,直到DAC输出的电压和外部通道输入的电压近似相等,这样DAC输入的数据就是外部电压的编码数据,这就是DAC的实现原理。这个电压调节的过程就是这个逐次逼近SAR来完成的,为了最快找到未知电压的编码,通常我们会使用二分法进行寻找

例如:这里是8位的ADC,那编码就是从0~255,那第一次比较的时候,我们就给DAC输入255的一半,进行比较,就是128,然后看看谁大谁小,如果DAC电压大了,如果第二次比较的时候,在就给128的一半,64,如果还是大,第三次比较的时候就给32,如果这次DAC电压小了,那第四次就给32到64中间的值,然后继续,这样依次进行下去,就能最快地找到未知电压的编码

那然后AD转化结束后,DAC的输入数据就是未知电压的编码,输出8位就有8根线,12位就有12根线

最上面EOC是转换结束信号

START是开始转换,给一个输入脉冲,开始转换

CLOCK是ADC时钟,因为ADC内部是一步一步进行判断的,所以需要时钟来推动这个过程

下面的B\VREF+和VREF-是DAC的参考电压,比如你给一个数据255,就是对应5V还是3.3V,就由这个参考电压决定,这个DAC的参考电压也决定了ADC的输入范围,所以它也是ADC参考电压,最后左边是整个芯片电路的供电,VCC和GND,通常这个参考电压的正极和VCC是一样的会接在一起,参考电压的负极和GND也是一样的,也连接在一起,所以一般情况下,ADC输入电压的范围就和ADC的供电是一样的

STM32F103C8T6内部的ADC结构

这里左边是ADC的输入通道,包括16个GPIO口,IN0~IN15,和两个内部的通道,一个内部温度传感器,一个是VREFINT内部参考电压,然后18个输入通道,然后是一个模拟多路开关,可以指定我们想要选择的通道,右边是多路开关的输出,进入到模数转换器,这里模数转换器就是执行的我们刚才讲过的逐次比较的过程,转换的结果会直接放在这个数据寄存器里,我们读取寄存器就能知道ADC转换的结果了

在模拟多路开关中,对于普通的ADC,多路开关一般都是只选一个的,就是选中某一个通道,开始转换,等待转换完成,取出结果,这是普通的流程

但是这里比较高级,他可以同时选中多个,而且在转换的时候,还分成了两个组,规则通道组和注入通道组,其中规则组可以一次性最多选中16个通道,注入组最多选中4个通道

在这里这个东西有什么作用呢

举个简单的例子

这就像你去餐厅点菜,普通的ADC是你指定一个菜,老板给你做,然后做好了送给你。但在这里是你指定一个菜单,这个菜单最多可以填16个菜,然后你直接递个菜单给老板,老板按照菜单的顺序依次做好,一次性给你端上来,这样的话就可以大大提高效率,当然你的菜单也可以只写一道菜,这样这个菜单就简化成了普通的模式了

对于这个菜单呢也有两种,一种是规则组菜单,可以同时上16个菜,但是有一点,这个规则通道数据寄存器是有一个,也就是说这个桌子比较小,最多只能放一个菜,如果上16个菜,那不好意思,前15个菜都会被挤掉,你只能得到16个菜,所以对于规则组转换来说,如果使用这个菜单的话,最好配合DMA来实现,DMA是一个数据转运小帮手,它可以在每上一个菜之后把这儿菜挪到其他地方去,放置被覆盖

注入组:这个注入组就比较高级了,它相当于餐厅的VIP座位,在这个座位上,一次性最多可以点4个菜,并且这里数据寄存器有4个,是可以同时上4个菜的,对于注入组而言,就不用担心数据覆盖的问题了,一般情况下我们使用规则组就完全足够了

首先,左下角这里就是触发转换的部分,也就是最上面的START信号,开始转换,对于STM32的ADC,触发ADC开始转换的信号有两种,一种是软件触发,就是你在程序中手动调用一条代码,就可以启动转换了,另一种就是硬件触发,就是右下角部分这些触发源,上面是注入组的触发源,下面这些是规则组的触发源,这些触发源只要来自定时器,有定时器的各个通道,还有TRGO定时器主模式的输出,定时器可以通向ADC,DAC这些外设,用于触发转换。那因为ADC经常需要过一个固定时间段转换一次(比如每隔1ms转换一次,正常思路就是,用定时器,每隔1ms申请一次中断,在中断里手动开始一次转换,这样也是可以的)但是频繁进入中断对我们的程序是有一定影响的,比如你有很多中断都需要频繁进入,那肯定会影响主程序的执行,并且不同中断之间,由于优先级的不同,也会导致某些中断不能及时得到响应,如果触发ADC的中断不能及时响应,那么我们ADC的转换频率就肯定会产生影响了,所以对于这种需要频繁进中断,并且在中断里只完成了简单工作的情况,一般都会有硬件的支持

在左上角这里是VREF+、VREF-、VDDA和VSSA,上面是ADC的参考电压,决定了ADC输入电压的范围,下面是ADC的供电引脚,一般情况下,VREF+要接VDDA,VREF-要接VSSA

右边的这里的ADCCLK是ADC的时钟,用于驱动内部逐次比较的时钟,这个是来自ADC预分频器,这个ADC预分频器是来源于RCC的

DMA请求是用于触发DMA进行数据转运的

模拟看门狗:它里面可以存一个阈值高限和阈值底限,如果启动了模拟看门狗,并指定了看门的通道,那这个看门狗就会关注它看门的通道,一旦超过这个阈值范围了,它就会乱叫,就会在上面申请一个模拟看门狗的中断,最后通向NVIC,对于规则组和注入组而言呢,它们转换完成之后,也会有一个EOC转换完成的信号

EOC:规则组的完成信号

JEOC:注入组完成的信号

这两个信号会在状态寄存器里置一个标志位,我们读取标志位,就能知道是不是转换结束了,同时这两个标志位也可以去到NVIC申请中断,如果开启了NVIC对应的通道,它们就会触发中断

ADC基本结构

输入通道

这些就是ADC通道和引脚复用的关系

这个对应关系也可以通过引脚定义表看出来

转换模式

单次转换,非扫描模式

这个是最简单的

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

连续转换,非扫描模式

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

单次转换,扫描模式

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

连续转换,扫描模式

 这个模式的转换就是在上一个的基础上变了一点,就是一次转换完成后,立刻开始下一次的转换

触发控制

这个表就是规则组的触发源,这个表里,有来自定时器的信号,还有外部引脚或定时器的信号,这个具体是引脚还是定时器,需要用AFIO重映射来确定,最后是软件控制位,也就是我们之间说的然软件触发,这些触发信号怎么选择,可以通过设置右边这个寄存器来完成,当然使用库函数的话,直接给一个参数就行了

数据对齐

 我们这个ADC是12位的,它的转换结果就是一个12位的数据,但是这个数据寄存器是16位的,所以就存在一个数据对齐的问题

数据右对齐:就是12位的数据向右靠,高位多出来的几位就补0

数据左对齐:就是12位的数据向左靠,低位多出来的几位补0

在这里我们一般使用的都是第一种右对齐,这样读取这个16位寄存器,直接就是转换结果

如果是左对齐,直接读的话,得到的数据会比实际的大

转换时间

 校准

 这个我们不需要理解,因为这个过程是固定的,我们只需要在ADC初始化的最后,加几条代码就行了,至于怎么计算,怎么校准的,我们不需要管,所以这个了解一下就行

硬件电路

 第一个是一个单位器产生一个可调的电压


网站公告

今日签到

点亮在社区的每一天
去签到