STM32F103C8T6这款单片机内置了12位逐次逼近型模数转换器 (ADC) -5-9,这对于将模拟信号(比如传感器读数)转换为微控制器可以处理的数字值非常有用。下面我来为你梳理一下它的关键特性和使用方法。
一.ADC模数转换简介
1. ADC主要特性
STM32F103C8T6的ADC主要具备以下特性
-
分辨率:12位,可将模拟电压转换为0到4095之间的数字值
-
输入电压范围 :0~3.3V,注意:输入电压切勿超过3.6V,否则可能损坏芯片。
-
转换通道 :最多支持18个输入通道,包括:
-
10个外部通道:可通过GPIO引脚(PA0-PA7, PB0-PB1)连接外部信号
-
2个内部通道 :连接至内部温度传感器和参考电压源(
VREFINT= 1.2V)。
-
-
转换模式:支持单次、连续、扫描或间断模式。
-
转换时间 :最短可达1μs (在ADCCLK=14MHz时),实际转换时间
TCONV = 采样时间 + 12.5个ADC周期 -
数据对齐 :支持左对齐或右对齐,通常使用右对齐 ,这样读取的数据寄存器值就是转换结果-7。
-
触发源:支持软件触发和硬件触发(如定时器)
-
时钟 :ADCCLK由APB2时钟(最高72MHz)分频而来,最大不得超过14MHz。通常选择6分频(12MHz) 或8分频(9MHz)。
2.ADC工作模式与通道组
STM32的ADC功能通过规则组和注入组来组织转换具体如下:
| 特性 | 规则组 (Regular Group) | 注入组 (Injected Group) |
|---|---|---|
| 通道数量 | 最多16个通道 | 最多4个通道 |
| 数据寄存器 | 1个规则组数据寄存器 (ADC_DR) | 4个注入组数据寄存器 (JDRx) |
| 数据覆盖风险 | 多通道转换时,若不用DMA,数据可能被覆盖 | 各有其数据寄存器,数据不会被覆盖 |
| 工作特点 | 常规转换通道 | 可中断规则组的转换,优先转换自身通道 |
ADC支持多种转换模式,以下是几种典型组合:
-
单次转换非扫描模式:适用于对单个通道进行一次性的ADC转换。
-
连续转换非扫描模式:适用于持续对单个通道进行ADC转换。
-
单次转换扫描模式:适用于对一组通道依次进行一次性的ADC转换,通常需配合DMA使用
-
连续转换扫描模式:适用于持续对一组通道进行循环ADC转换,通常需配合DMA使用。
3. ADC初始化和使用要点
使用ADC时,通常需要遵循以下步骤和注意要点:
-
初始化步骤:
-
开启时钟 :开启ADC和对应GPIO的时钟(
RCC_APB2PeriphClockCmd)。 -
配置GPIO :将用于ADC的GPIO引脚设置为模拟输入模式(
GPIO_Mode_AIN)。 -
配置ADC时钟分频 :通过
RCC_ADCCLKConfig设置,确保ADCCLK ≤ 14MHz。 -
配置ADC参数 :使用
ADC_InitTypeDef结构体配置ADC模式(通常独立模式)、数据对齐(通常右对齐)、触发方式、转换模式(单次/连续、扫描/非扫描)和通道数等。 -
规则组通道配置 :使用
ADC_RegularChannelConfig指定通道、序列顺序和采样时间。 -
使能ADC :使用
ADC_Cmd使能ADC。 -
ADC校准 :上电后建议执行一次校准(依次调用
ADC_ResetCalibration、等待复位完成、ADC_StartCalibration、等待校准完成),以减少误差
-
-
启动转换与读取结果:
-
软件启动转换 :在单次转换模式下,可使用
ADC_SoftwareStartConvCmd启动转换。 -
等待转换完成 :通过
ADC_GetFlagStatus检查ADC_FLAG_EOC标志位。 -
读取转换值 :使用
ADC_GetConversionValue读取ADC_DR寄存器中的结果。
-
-
多通道与DMA -7:
对于多通道扫描模式 ,由于规则组只有一个数据寄存器,新数据会覆盖旧数据,因此强烈建议使用DMA进行数据转运。
二.电路结构
1.组成
分辨率:12位逐渐逼近型是ADC的模式。他的表示范围是:0~2^12。量化结果的范围是0~4095。
时间:1us因为ad转换是需要花费时间的。这里1us就表示从AD转换开始到产生结果,需要花费1us的时间,对应AD的转换频率,就是1MHz。这是这款芯片的最快转换频率。如果你需要转换一个频率非常高的信号就要考虑这个转换频率是否够用。
输入电压一般要求是在,STM32的供电电路范围内。
最小值是0V,最大值是3.3V,对应着0,到4095,中间都是一一对应的线性关系。
16个外部电路,和2内内部信号源,16个外部就是16个GPIO口在引脚上直接接模拟信号就行了,不需要额外的电路。
两个内部传感器是内部温度传感器和内部参考电压。温度传感器可以测量CPU的温度。
内部参考电压是一个1.2V的基准电压,这个基准电压是不随外部电压变化的所以说芯片供电如果不是3.3V那么测量引脚的电压就可能不对。
规则组和注入组两个单元,这是STM32的ADC增强功能,普通ADC的转换是启动一次,读取一次值,再启动,在读取,但是STM32的ADC就比较高级,可以列一个组,一次性启动一个组连续转换多个值,并且有两个组,一个是用于常规使用的规则组,一个是用于突发事件的注入组。
模拟看门狗自动检测输入电压范围。可以用来检测,光线,温度,并且会有一个需求,比如说光线高于某个阈值,或者低于某个阈值,或者温度高于某个阈值,低于某个阈值时,就会执行对应的操作。这就可以用模拟看门狗来自动监测,然后当AD高于设定的上线,或者低于下限时,看门狗就会申请中断,就可以在中断内执行对应的操作。
2.逐次逼近型ADC测电压方法
这是我们ADC0809的结构图,是逐次逼近型ADC。
这里的IN0~IN7是我们的输入通道,通过通道选择开关,输入到比较器的上通道输入。
这里是地址锁存和译码,就是你想要选择那一路就把通道号放在这个引脚上。ALE是锁存信号,给了之后,上面对应通路的开关就会打开。
比较器的两个输入端,一个是通道选择,另一个是DAC的电压输出端。我们有了一个DAC未知的外部通道编码电压,和已知的内部DAC输出的编码电压,同时输入到编码器进行判断,如果DAC输出电压大,我们就调小DAC数据。反之如果DAC输出电压比较小,就增大DAC数据,直到DAC输出与外部通道的输入电压近似相等。这样DAC输入数据就是外部编码数据了。
电压调节过程就是通过逐次逼近寄存器SAR完成的为了最快找到未知电压的编码,通常我们会使用二分法查找。比如这里是8位的ADC那么编码就是从0~255,第一次比较时候,我们就给DAC输入255的一半进行比较。如果DAC电压大了,那么第二次比较时候就再给128的一半以此类推。
我们可以看到155,128,64,32,这些都是二进制的位权就相当于对二进制从高位到地位,一次进行为1还是为0的过程。这就是逐次逼近型名字的来源。对于8位的ADC只需要一次判断8次就可以找到未知电压的编码了。
当我们查找完了之后,DAC的输入就是未知电压的编码通过后面进行输出8位就要8个输出。
EOC是END OF CONVERT转换结束信号。START是开始转换,给一个输入脉冲开始转换,CLOCK是ADC时钟因为ADC内部是一步一步进行判断的所以需要时钟来推动这个过程。
下面的Vref+和Vref-是DAC的参考电压,比如说给一个数据是255,那么是对应5V还是3.3V呢就由这个参考电压决定,这个DAC的参考电压,也决定了ADC的输入范围所以他也是ADC的参考电压。
最后左面是整个电路的供电。通常参考电压的正极会和VCC接在一起,参考电压的负极,会和GNE接在一起。
所以一般情况下,ADC输入电压的范围和ADC供电也是一样的。
3.STM32的ADC框图
一般在手册里,每一个外设的最前面,都有一个整体的结构框图,这个还是比较重要的,
(1)ADC简介
这里是ADC的输入通道包括16个GPIO口IN0~IN5。和两个内部的通道,一个是温度传感器,一个是内部参考电压。一共是18个输入通道,右边的是模拟多路开关,可以指定我们想要选择的通道。
右边是多路通道的输出,进入到模数转换器。这里的模数转换器就是进行我们上面说过的逐次比较的过程。
转换结果会直接放在数据寄存器里面。我们读取寄存器就能直到转换结果了。对于普通的ADC多路开关一般都是只选中一个,一般的流程:选中某个通道,开始转换,转换完成,读取结果。
但是我们的STM32不同它可以转换多个,而且在转换的时候,划分为了两个组规则通道组和注入通道组。其中规则组可以一次性选择16个通道。注入通道组一次最多可以选择4个通道。
因为规则组只有一个寄存器,所以一次性给16个通道,那么前15个就会被挤掉。如果使用规则组的话,最好配合DMA来使用,DMA是数据搬运的小能手,它可以在每次来一个数据之后,把这个数组转存到其他的地方去,防止数据被覆盖。
但是对于注入组来说,一次可以由四个通道,而且寄存器也是四个,所以可以同时读取四个状态。所以对于注入组而言就不用担心数据覆盖的问题了。
这里的START对应着开始转换
对于STM32来说,触发转换的信号有两种,一种是软件触发再程序上手动调用一条代码。
(2)硬件全自动触发
另一种是硬件触发,分为规划组触发源,以及注入组触发源。这里可以看到,有定时器的输出通道,还有TIGO定时器主模式的输出。上一个博客讲过,定时器可以通向ADC,DAC这些外设,用于触发转换。ADC经常需要过一个固定时间段转换一次,正常的思路就是用定时器,每隔1ms进行一次中断再中断里手动开启一次转换,但是频繁进入中断对我们的程序是有一定的影响的。比如说有很多程序都要中断,那么就会影响主程序的进行。不同中断的优先级之间,会有不同的响应,就会导致有的中断无法及时进行响应,如果ADC的中断不能及时响应就会导致ADC的转换频率产生较大的影响。
向这种频繁进入中断却干简单事情的环节,都会有硬件的支持,比如说我们用TIM3定时器定一个值,然后把TIM3的更新事件选择为TRGO的输出然后在ADC这里,选择开始信号为TIM3的TRGO这样TIM3的更新事件,就能通过硬件,进行自动触发ADC转换了。整个过程不需要进入中断,这就节省了中断资源。
(3)ADC电源
这里的话,上面两个VREF+,VREF-是ADC参考电压,决定了ADC输入电压的范围。下面两个是ADC的供电引脚,一般情况下,VREF+要接VDDA,VERF-要接VSSA。
在引脚定义我们也可以看到,我们之前了解,VDDA和VSSA是我们内部模拟部分的电源,比如ADC,RC振荡器,锁相环等。
这里VDDA接3.3V,VSSA接GND,所以ADC的模拟电压输入,就是0~3.3V。
(4)ADC时钟
这里的ADCCLK是ADC的时钟。是用于驱动内部逐次比较的时钟。来源于ADC预分频器。然而ADC预分频器是来源于RCC的。
APB2时钟72MHz然后通过ADC预分频器,进行分频,得到ADCCLK。ADCCLK最大是14MHz。但是这个分频器如果选择2分频,那么就超出14MHz了,就是变为了36MHz。4分频的话是18MHz也超过了,所以对于ADC预分频器,我们只能选择6分频也就是12MHz。还有8分频也就是9MHz。
这里就是DMA请求,可以把数据搬运到另一个指定的地方。
(5)模拟看门狗
上面这里还要模拟看门狗,这里面可以存放一个阈值高限和阈值低限。如果启动了看门狗,并且制定看门的通道,那么看门狗就会关注他看门的通道,一旦阈值超过这个限制,他就会乱叫,就会在上面申请一个模拟看门狗的中断。最好通向NVIC。
对于规则组和注入组,他们转换完成之后,也会有一个EOC转换完成的信号,在这里EOC是规则组的完成信号,JROC是注入组完成信号,这两个信号会在状态寄存器置一个标志位,我们读取这个标志位,就可以知道是不是转换结束了。同时这两个标志位也可以去NVIC申请中断,如果开启了NVIC对应的通道他们就会触发中断。
4.ADC基本结构图
(1)总览

1.再来模块化的回顾一下,左边的是输入通道模拟的16个GPIO口外加两个内部通道
2.然后进入AD转换器,AD转换器里有两个组,一个是规则组,一个是注入组。规则组最多可以选择16个通道,注入组有4个通道。然后转换的结果可以存放在AD数据寄存器里,其中规则组只有一个寄存器,注入组有四个寄存器,
3.然后下面有触发控制,提供了开始转换这个START信号。触发控制可以选择软件触发,和硬件全自动触发,硬件触发主要来自于定时器,当然也可以选择,外部中断的引脚。
4.右边的是来自于RCC时钟的CLOCK,ADC逐次比较的过程,就是由这个时钟推进的。
5.上面可以布置一个模拟看门狗,用于检测转换结果的范围。如果超出设定的阈值,就通过中断输出控制向NVIC申请中断。
6.另外规则组和注入组转换完成后,会有一个EOC信号会置一个标志位,也可以向NVIC发起中断
7.最后右下角有一个开关控制,在库函数中就是ADC_Cmd函数,用于给ADC供电,就是使能。
5.输入通道


对应引脚定义表也可以看出。这里只有IN0到IN9这十个通道,因为这个芯片就只能有10个外部输入通道,然后ADC12_IN0的意思是,ADC1和ADC2的IN0都在PA0上。
下面也是同理,就说明ADC1和ADC2的引脚都是相同的,既然都是相同的,那么岂不是一个就好了,实则不然,这里就要说一个ADC的高级功能了。
双ADC模式,这个模式比较复杂。意思就是ADC1和ADC2可以一起工作,他们两个可以组成,同步模式,交叉模式等等。
比如交叉模式ADC1和ADC2交叉对一个通道进行采样,这样就可以进步一提高采样率。

这里只有ADC1有通道16和通道17,AD2是没有的。ADC1和ADC2的引脚是完全相同的,ADC3会有一些变化,不过我们这个芯片,没有ADC3,所以不需要考虑。
这里引脚的顺序就是PA0-PA7,PB0-OB1,PC0-PC5。由于我们芯片没有PC0-PC5所以这个通道也没有。
6.规则组四种扫描模式
在我们ADC初始化的结构体里,会有两个参数,一个是选择单词转换还是连续转换,一个是选择扫描模式还是非扫描模式的,这两个参数组合起来,就有这四种转换方式。
(1)单次转换,非扫描模式

我们看到有16个空位,可以在里面写入要转换的通道,在非扫描的模式下,这个触发就只有序列1的位置有效,这是选中一组的方式,就退化为简单的选择其中一个的方式了。
在这里我们可以在序列一的位置,指定我们想转换的通道,比如通道2写在这个位置,我们就可以触发转换,ADC就会对这个通道2进行模数转换。过一小会,转换完成,同时将转换结果放在数据寄存器里,同时给EOC标志位置1,整个转换过程就结束了,我们判断这个EOC标准位,如果转换完成,我们就可以在数据寄存器里读取结果了。
如果想要转换,那么需要再触发一次。
如果想换一个位置进行转换,那么在转换之前把第一个位置的通道2,改变成其他通道然后在启动转换,这样子就可以了。没有用到菜单列表也是比较简单的一种模式。
(2)连续转换,非扫描模式

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

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

接下来我们看一下连续转换扫描模式,这个模式就很好猜出来了。
就是再上一个基础上,变了一点。就是一次转换完成后,立刻开始下一次的转换,和上面的非扫描模式的单次和连续是一个道理。
6.间断模式
当然再扫描的模式下还可以有一种模式,叫间断模式。他的作用是在扫描的过程中每个几个转换就会暂停一次。需要再次触发才可以继续,我们目前知道就好
7.细节知识
(1)触发控制

这个表就是规则组的触发源

就是这里。
在这里有来自定时器的信号,还有来自引脚或定时器的信号,具体是引脚还是定时器,需要用AFIO重映射来确定。最后是软件控制位,也就是我们前面提及到的软件触发。
这些通道的选择,可以选择控制右边的寄存器来完成,当然使用库函数的话直接给一个参数就可以了。
(2)数据对齐

因为我们ADC是12位的他的转换结果就是12位的。但是数据寄存器是16位的,所以就存在一个数据对齐的问题。
1.数据右对齐,就是12位数据向右靠,高位多出来几位就补几个0。
2.数据左对齐,就是12位数据向左靠,低位多出来几位就补几个0。
我们一般使用的都是第一种右对齐方式,这样子读取16位寄存器,直接就是转换结果。选择左对齐的话,读出来的结构会比实际的大,因为相当于向左移动了4位,二进制有个特点,数据左移一次,就相当于把数据扩大了2倍。这里左移了四次就相当于2×2×2×2,相当于扩大了16倍,也就是2^4,2的4次方。
左对齐的作用就是,如果你不想要这么高的分辨率,0-4095这个数太大了,就可以选择左对齐,然后把这个数的高八位读取出来,舍去了后四位的精度,这个12位的ADC就退化为了8位的ADC了。
(3)转换时间

转换时间一般不是很敏感,因为AD的转换速度都非常快,如果不需要非常快的转换时间,那么这个可以忽略。
可以分为四个步骤,采样,保持,量化,编码,这四个步骤,采样和保持又可以分在一起,量化和编码又可以分在一起。
1.量化,编码
量化,编码好理解,就是我们之前看到的ADC逐次比较的过程这个是需要花一段时间的,一般ADC位数越多,花的时间越长。
2.采样,保持
采样,保持就是,因为我们的AD转换,也就是后面的量化,编码是需要一小段时间的。如果在这一小段时间里,输入的电压还在不断变化,那就没办法定位输入电压到底是在哪里了,所以在量化编码之前,我们需要设置一个采样开关。
先打开采样开关收集一下外面的电压,比如可以用一个小容量的电容,存储下这个值,存储好了之后,断开采样开关,在进行后面的AD转换。
这样在量化编码的期间,电压始终保持不变,这样才能精确的定位未知电压的位置。这就是采样保持电路。
在采样保持的过程,需要闭合采样开关,过一段时间再断开。这里就会产生一个采样时间。

我们就得到了,STM32的总转换周期=采样时间+12.5个ADC周期。采样时间是采样,保持花费的时间,这里可以再程序中进行配置。采样时间越大,越能避免一些毛刺信号的干扰。不过转换时间也会相应延长。
12.5个ADC周期是量化编码花费的时间,因为是12个ADC所以需要花费12个周期。多了半个周期可能是别的花费的,
ADC周期就是从RCC分频过来的ADCCLK。这跟=个ADCCLK最大是14MHz,所以下面有个例子,就是最快的转换时间。
当ADCCLK=14MHz时,采样时间为1.5个周期。那么TCONV=1.5+12.5=14个ADC周期在14MHzADCCLK的情况下就是1uS。也可以把ADCCLK时钟设置超过14MHz,那样子会更快,但是就超频了。
(4)校准

这跟校准过程看起啦复杂,但是我们不需要理解,我们只需要在ADC初始化的最后加几条代码就可以了,至于怎么计算,怎么校准我们暂时不用清除。
(5)硬件电路
那么ADC的外围电路我们应该怎么设计呢,这里给出了三个电路图

1.电位器产生可调电压电路
电位器产生一个可调电压,电位器两个固定端,一端3.3V一端GND。这样子中间的滑动端就可以产生一个0~3.3V的可调电压了。我们这里就可以接ADC的输入通道,比如说PA0。另外注意电阻一定要够大,因为是直接接在3.3V和GND之间的,过小就会短路,一般是kΩ起步。
2.传感器输出电压电路
一般来说像,光敏电阻,热敏电阻,红外接收管,麦克风等等,都可以等效为一个可变电阻。但是阻值没办法测量,就可以和一个固定电阻进行分压来得到一个反应电阻值电压的电路。这跟固定电阻一般选和传感器阻值相近的电阻,可以得到一个好的中间电压的输出。

看我们以前传感器模块的电路,这里也是使用分压方法来进行输出的。
3.电压转换电路
如果你想测量0-5V的电压但是传感器只能接收0-3.3V电压就可以搭建一个这样子的电路。中间的电位经过分压,最大时3.3V,如果你想采集5-10V的电压可以使用,再大的电压就不推荐了,可能大电压会比较危险。
高电压采集,最好使用一些专用的采用芯片,比如隔离放大器等等。做好高低电压的隔离,保证电路的安全。
8.手册查阅
到这里我们有关ADC介绍就结束了,我们最后来看一下手册

这里就是关于ADC的介绍,里面有ADC的主要特征,ADC的框图,VDD和VREF的使用介绍


ADC开关控制,时钟,通道选择。

还有ADC执行过程中的时序图。

还有间断模式。

DMA请求,和双ADC模式。

还有温度传感器,以及如何计算温度。

重要的就是ADC寄存器介绍。

其中EOC信号就可以在这里置标注为,我们读取标志位,就可以知道硬件的状态。

最后就是寄存器的总表,这里有所有的ADC的寄存器。

还有各个寄存器的复位值,上电后就会变为复位值,这里复位值对应的,就是各个外设的默认配置
比如说GPIO口上电后默认配置为浮空输入模式,输出数据寄存器默认输出低电平等等。
如果想要了解上电后的默认配置,就可以参考这里的寄存器的默认值,在对照相应的寄存器描述,就可以知道默认配置了。
有关STM32ADC的介绍到这里就结束了,大家可以看看我以前的博客笔记,里面有我们STM32F103C8T6的各种外设的学习笔记。