前言
由于在STM32单片机中,主要是数字电路,而数字电路没有多少伏电压的概念,只有高电平和低电平两个概念,如果想要读取电压值,则需要经过ADC模数转换来读取对应引脚的模拟电压,然后存放到对应的寄存器种,通过变量来读取从而进行显示、判断等操作。
1.ADC(Analog-Digital Converter)模拟-数字转换器
12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部 信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右 对齐方式存储在16位数据寄存器中。
上述为手册对ADC的介绍,接下来对上面一一进行解释:
首先ADC是12位的,而一般的寄存器是16位的,所以在对ADC输出的数据进行存储的时候需要选择对齐方式,左对齐还是右对齐,在后续进行介绍。
ADC模数转换的方法是一种逐次逼近的比较方法,实际上是用二分法来实现的,在后续进行介绍。
然后ADC有18个通道输入,其中两个和芯片内部相连接,分别是温度传感器以及内部电压模块相连接,其他的16个通道就对应的接通到其他Pin端口,用于片外外设上的模拟信号读取,如下图。
最后,这18个通道,都可以分别单独地配置 单次/连续、扫描/非扫描、间断/不间断模式,同样在后续进行介绍。
同时ADC一般为1us转换时间 (根据产品型号,时钟频率有所不同)
输入电压范围:0~3.3V,转换结果范围:0~4095(2的12次方-1)
对应的是一个线性关系,用图来表示就是:
1.1ADC结构
接下来看到ADC的结构图:
首先看到主通道,ADCx_IN0~15,也就对应16个外部通道通过GPIO最终进入到ADC模块中,其中会经过一个数据选择器,同时输入还包含之前提到的温度传感器和内部电压模块:
他的名称为模拟多路开关,也就是决定哪个几个通道输出,可以看到输出可以输出至注入通道最多4通道,也可以输出至规则通道最多16通道。
1.1.1注入组和规则组
首先需要明确注入组和规则组:
这里引用江科大的例子:
这一整个过程类比为写菜单点菜,规则组菜单上最多可以写16道菜,如果写16个菜(输入16个规则通道),老板会一次性把16个菜做好(16个通道按顺序依次一次性执行),然而放菜的桌子仅能放一盘菜也就其他前15盘菜会被挤掉(覆盖)(对应的就是AD转换后的前15个规则通道数据都会被覆盖,只会留下IN15通道的数据。
改进方法,通过DMA转运,防止转换后的数据被覆盖,也就叫服务员先把菜移至别的地方,在后续对DMA的会提到。
然后是规则组,注入组则是菜单只能够写满四个菜(四个注入通道),同样老板也会一次性做好,在注入组的餐桌上正好能够摆满四个菜(四个注入通道转换后的数据都能够被存储),不会出现有菜被挤掉(覆盖)的情况。
1.1.2ADCCLK时钟
同时能看到ADCCLK对ADC提供时钟,对应的时钟树部分:
可以看到,一般都是由系统时钟72MHz输入到ADC预分频器,同时ADCCLK最大为14MHz,所以在系统时钟72MHz输入的情况下,ADC预分频器的值只能为6分频和8分频,对应输出ADCCLK为12MHz、9MHz。
1.1.3VREF+和VREF-
VREF+和VREF-为参考电压的正负极,下图为各引脚的说明解释:
实际上,VREF+和VREF-分别接上VDDA和VSSA,然后VDDA和VSSA分别接到VDD和VSS,结果就是VREF+和VREF-分别接到VDD和VSS。
1.1.4中断触发
可以看到,超过看门狗的上阈值或是低于下阈值会产生AWD标志位,规则组、注入组AD转换结束分别会产生EOC和JEOC标志位,在对应寄存器的位上设置就可以实现转换结束后产生中断:
上述寄存器是用来存储对应标志位的,需要注意的是,需要软件清除,也即手动清除。当需要使用对应的结束标志位来启动中断的时候,还需要手动清除一下对应的标志位。
对应的,还需要再下面的寄存器种设置对应的位:
对应在ADC_ITConfig函数进行产生中断源的选择:
具体是ADC_IT这个参数,可以选择ADC_IT_EOC、ADC_IT_AWD、ADC_IT_JEOC,分别对应规则组转换完成、模拟看门狗触发、注入组转换完成。
对应的中断通道IRQ的选择,需要根据自身芯片的型号来选择对应的中断通道枚举类型:
这里我采用的是STM32F103C8T6,在该芯片中,只有ADC1和ADC2两个模块,即对应MD中容量类型如下图:
由以上的解释,NVIC_IRQChannel=ADC1_2_IRQn;这样即完成对中断通道的配置。
最终代码如下:
ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC1;
NVIC1.NVIC_IRQChannel=ADC1_2_IRQn;
NVIC1.NVIC_IRQChannelCmd=ENABLE;
NVIC1.NVIC_IRQChannelPreemptionPriority=2;
NVIC1.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC1);
这里我定义的结构体变量为NVIC1,对于抢占优先级和响应优先级的设置,要求不高的情况下,随意配置。
最后配置一下中断函数需要执行的内容,即完成对中断的配置:
1.1.5外部触发输入
也就是ADC结构的下半部分,同时可以看到在右下角,说明了ADC3外设下的触发结构,于ADC1和ADC2左边的结构略有不同,在使用ADC3的时候需要注意一下。
可以看到输入进注入通道和规则通道之前,有一个与门(相当于开关),与门的一位为触发信号输入,另一位则为控制位,通过对控制位的控制来使能或失能触发输入。
对应寄存器:
这两位分别控制两个与门的控制位,类似于“开关”。
同时在这个寄存器种,还含有对外部触发输入的数据寄存器控制的位:
可以看到,基本上都是由TIM定时器产生的触发事件,所以我们可以使用TIM定时器在隔多少秒后使用ADC采集并转换一下数据。
上述的寄存器位描述用图表表示就是,注入组:
对应的选择触发函数:
对应的注入组与门控制位函数:
规则组:
规则组与门的控制位函数:
奇怪的是,并没有规则组的外部触发选择函数,如ADC_ExternalTrigConvConfig,并没有在固件库中找到,而却含有规则组与与门控制位的函数,这里个人推测是ST公司漏装了^ ^,这里就不在深究了,毕竟他们只需要写写函数,而我们考虑的东西就更多了。
这里说一下JSWSTART、SWSTART:
对应函数:
对应函数:
这两位可以通过软件设置,即通过上述的两个函数,设置后就会开启对应规则/注入通道的转换,同时在转换启动后,该位会由软件自动清除。
同样的,在外部触发源数据选择器中,置111,对应启动规则/注入通道的转换,同时还需打开与门的控制位,这样才能够真正启动ADC转换。
再来看看数据手册对触发注入的描述:
清除ADC_CR1寄存器的JAUTO位,并且设置SCAN位,即可使用触发注入功能。 1. 利用外部触发或通过设置ADC_CR2寄存器的ADON位,启动一组规则通道的转换。 2. 如果在规则通道转换期间产生一外部注入触发,当前转换被复位,注入通道序列被以单次 扫描方式进行转换。 3. 然后,恢复上次被中断的规则组通道转换。如果在注入转换期间产生一规则事件,注入转 换不会被中断,但是规则序列将在注入序列结束后被执行。 注:当使用触发的注入转换时,必须保证触发事件的间隔长于注入序列。例如:序列长度为28个 ADC时钟周期(即2个具有1.5个时钟间隔采样时间的转换),触发之间最小的间隔必须是29个 ADC时钟周期 先看到JAUTO位: 先看到这个位的描述: 用于开启或关闭规则通道组转换结束后自动的注入通道组转换,也就是在规则通道组转换的时候,此时软件或外部触发注入通道组的转换,通过JAUTO设置可以选择规则通道组转换结束后自动的注入通道组转换。 而清除时满足SCAN位被设置,也即选择扫描模式(在后续会具体介绍),会直接复位规则通道组转换,注入通道组转换被单次(后续介绍)扫描方式进行转换,注入转换后,回复上次的规则组通道转换。 如下图: 突然的注入触发相当于中断,只是没有“保护现场”的功能。 如果,正在注入转换的时候,来了一个规则事件(产生规则通道组转换),并不会中断注入转换,而是会在注入序列结束后再进行规则事件的转换。 类比优先级,抢占和响应优先级。同时看到时序图来理解下面的注:
当使用触发的注入转换时,必须保证触发事件的间隔长于注入序列。例如:序列长度为28个ADC时钟周期(即2个具有1.5个时钟间隔采样时间的转换),触发之间最小的间隔必须是29个ADC时钟周期。
这意味着,从一次触发事件开始到下一次触发事件开始,这段时间必须足够长,以确保当前的注入转换序列能够完全执行完成,以避免不同注入转换序列之间的冲突或中断。
同时还有一个自动注入: 如果设置了JAUTO位,在规则组通道之后,注入组通道被自动转换。这可以用来转换在 ADC_SQRx和ADC_JSQR寄存器中设置的多至20个转换序列。 在此模式里,必须禁止注入通道的外部触发。 如果除JAUTO位外还设置了CONT位,规则通道至注入通道的转换序列被连续执行。 对于ADC时钟预分频系数为4至8时,当从规则转换切换到注入序列或从注入转换切换到规则序列时,会自动插入1个ADC时钟间隔;当ADC时钟预分频系数为2时,则有2个ADC时钟间隔的 延迟。 注意: 不可能同时使用自动注入和间断模式。看到COUNT位:
自动注入需要禁止外部触发的注入模式,因为外部触发的注入转换会中断正在执行的规则转换,对应的置JAUTO为1,如果置COUNT位为1,也即选择连续转换模式,当规则通道后面有注入通道在“排队”的时候,当执行完规则转换,自动执行后面的转换。
需要注意自动注入不能和间断模式共同作用。
2.ADC的模式
前面提到过,ADC的模式有很多种,连续/非连续、扫描/非扫描、间断/非间断,以及在后面还有一个双ADC模式。
2.1连续/非连续模式
在连续转换模式中,当前面ADC转换一结束马上就启动另一次转换。此模式可通过外部触发启 动或通过设置ADC_CR2寄存器上的ADON位启动,此时CONT位是1。 每个转换后: ● 如果一个规则通道被转换: ─ 转换数据被储存在16位的ADC_DR寄存器中 ─ EOC(转换结束)标志被设置 ─ 如果设置了EOCIE,则产生中断。 ● 如果一个注入通道被转换: ─ 转换数据被储存在16位的ADC_DRJ1寄存器中 ─ JEOC(注入转换结束)标志被设置 ─ 如果设置了JEOCIE位,则产生中断。 上述为数据手册中对连续模式的描述,连续模式也就是连续地进行ADC转换,后面有多少个“排队”的ADC转换,就会执行多少次,同时在每个规则/注入组转换后分别会设置标志位EOC/JEOC,用下图来大致表示: 每一组通道转换完成后都会置EOC。 非连续模式(单次转换模式)也就是,只执行一组通道转换后置EOC就结束。 对应的在COUNT位置1或是置0来使用连续,还是非连续模式。2.2扫描/非扫描模式
此模式用来扫描一组模拟通道。 扫描模式可通过设置ADC_CR1寄存器的SCAN位来选择。一旦这个位被设置,ADC扫描所有被 ADC_SQRX寄存器(对规则通道)或ADC_JSQR(对注入通道)选中的所有通道。在每个组的每个 通道上执行单次转换。在每个转换结束时,同一组的下一个通道被自动转换。如果设置了CONT 位,转换不会在选择组的最后一个通道上停止,而是再次从选择组的第一个通道继续转换。 如果设置了DMA位,在每次EOC后,DMA控制器把规则组通道的转换数据传输到SRAM中而 注入通道转换的数据总是存储在ADC_JDRx寄存器中。 同样上述为数据手册对扫描模式的概述,所谓扫描模式,ADC会依次扫描所有规则通道/注入通道,然后将产生的数据存储到对应的寄存器中,如果是规则组中,16个通道只会留下第16位的数据,其他前15位数据会被覆盖。上图会依次序列顺序进行转换,直到转换到最后一位序列,然后置EOC标志位。
非连续就是,只转换第一位序列的通道,而忽略下面序列的通道,第一位序列转换完成直接置EOC标志位。
2.3间断/非间断模式
ADC中的间断模式是一种特殊的转换模式,它允许将一组通道分成多个短序列进行转换,而不是像扫描模式那样连续转换整组通道。
此模式在规则组和注入组之间有所不同:
规则组,此模式通过设置ADC_CR1寄存器上的DISCEN位激活。它可以用来执行一个短序列的n次转换(n<=8),此转换是ADC_SQRx寄存器所选择的转换序列的一部分。数值n由ADC_CR1寄存器的DISCNUM[2:0]位给出。
位DISCEN在规则通道组上决定失能还是使能。
DISCNUM[2:0]用来决定短序列的转换次数n。
这里看起来难以理解,举个例子,例如接下来我需要转换规则通道组:0、1、2、3、5、6、7、8、9、11、15、16这12个通道。
如果n=4(也即每次转换的次数4),第一次转换为0、1、2、3,第二次转换为5、6、7、8,第三次转换为9、11、15、16。
再来看n=3的情况,第一次转换为0、1、2,第二次转换为3、5、6,第三次转换为7、8、9,第四次转换为11、15、16。
这样看来,是不是更好理解规则组下的间断模式。
当n=4时,如果执行完三次,第四次就会重新执行第一次0、1、2、3规则通道的转化。
有三个SQR寄存器,处理SQR1中包含L[3:0]确定规则组通道数目,其他都是每五位确定一个转换通道,SQ16~1对应序列16~1。
接下里介绍注入组,也是类似的:
此模式通过设置ADC_CR1 寄存器的JDISCEN位激活。在一个外部触发事件后,该模式按通道顺序逐个转换ADC_JSQR寄存器中选择的序列。 一个外部触发信号可以启动ADC_JSQR 寄存器选择的下一个通道序列的转换,直到序列中所有的转换完成为止。总的序列长度由ADC_JSQR寄存器的JL[1:0]位定义。 对应的使能位,不在赘述 由于注入组中只有4个,也即注入通道只有四个,所以并没有注入组的间断模式通道计数,该模式按通道顺序逐个转换ADC_JSQR寄存器中选择的序列。 下面位数据手册中的例子: n=1,被转换的通道 = 1、2、3 第一次触发:通道1被转换 第二次触发:通道2被转换 第三次触发:通道3被转换,并且产生EOC和JEOC事件 第四次触发:通道1被转换 同样,不难理解,每次触发转换一次通道,只不过相比规则组通道数较少。小结
这样在当需要同时监控多个模拟信号,但每个信号的采样频率不同时,可以使用间断模式来优化资源使用,同时相比扫描模式减少不必要的转换,间断模式有助于降低ADC的功耗。
最后在某些应用场景中,可能需要在不同的时间点获取不同通道的数据,间断模式提供了这种灵活性。
2.4混合模式
上面连续/非连续(单次)可以和扫描/非扫描混合出四种:连续扫描、连续非扫描、单次扫描、单次非扫描。
而扫描/非扫描不能和间断/非间断混合,也即剩下连续/非连续混合间断/非间断:连续间断、连续非间断、非连续间断、非连续非间断。
这样就有八种模式共ADC使用,然而大部分情况下不会用到间断模式,在特殊情况下有可能会用到。
然而上述只是单ADC的模式,对应的有双ADC模式,同样对应特殊情况,例如需要采样频率较高的场合下,需要的可以自行查阅手册,这里不进行展开。
3.ADC的校准及温度传感器
3.1ADC的校准
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。在校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换 中每个电容器上产生的误差。 通过设置ADC_CR2寄存器的CAL位启动校准。一旦校准结束,CAL位被硬件复位,可以开始正常转换。建议在上电时执行一次ADC校准。校准阶段结束后,校准码储存在ADC_DR中。 注意: 1建议在每次上电后执行一次校准。 2启动校准前,ADC必须处于关电状态(ADON=’0’)超过至少两个ADC时钟周期。每次使用ADC转换之前,都应该进行ADC的校准,校准可以减小一些误差,对应的CAL为校准位:
在校准期间置CAL,校准完成置0,同时校准结束会将校准码存储在ADC_DR寄存器中:
对于库函数,只需要完成如下的代码,即可实现校准:
ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
3.2温度传感器
前面提到过,再ADC1中,温度传感器和内部电源模块分别再ADC通道的17和18中:
温度传感器可以用来测量器件周围的温度(TA)。 温度传感器在内部和ADC1_IN16输入通道相连接,此通道把传感器输出的电压转换成数字值。 温度传感器模拟输入推荐采样时间是17.1μs。 当没有被使用时,传感器可以置于关电模式。 注意: 必须设置TSVREFE位激活内部通道:ADC1_IN16(温度传感器)和ADC1_IN17(VREFINT)的转换 通过设置上面的位来使能温度传感器和内部电源模块,对应函数: 读温度 为使用传感器:- 选择ADC1_IN16输入通道
- 选择采样时间为17.1 μs
- 设置ADC控制寄存器2(ADC_CR2)的TSVREFE位,以唤醒关电模式下的温度传感器
- 通过设置ADON位启动ADC转换(或用外部触发)
- 读ADC数据寄存器上的VSENSE 数据结果
4.模拟看门狗
如果被ADC 转换的模拟电压低于低阀值或高于高阀值, AWD 模拟看门狗状态位被设置。阀值位于ADC_HTR 和 ADC_LTR 寄存器的最低 12 个有效位中。通过设置 ADC_CR1 寄存器的 AWDIE 位 以允许产生相应中断。 阀值独立于由ADC_CR2 寄存器上的 ALIGN位选择的数据对齐模式。比较是在对齐之前完成的。通过配置 ADC CR1 寄存器,模拟看门狗可以作用于 1 个或多个通道如下图: 对应函数: 对应的AWDCH[4:0]选择位: 对应单一通道选择函数: 需要注意的是,ADC1、ADC2、ADC3模拟输入通道的内部连接有所不同。 同时模拟看门的警戒区如下图: 对应寄存器: 上下阈值配置对应函数: 以上就是对模拟看门够的描述,当 被ADC 转换的模拟电压低于低阀值或高于高阀值, AWD 模拟看门狗状态位被设置。5.数据对齐以及采样时间的计算
5.1数据对齐
数据对齐是因为ADC为12位,而寄存器位16位,所以就存在一个数据对齐的问题。
分为,左对齐和右对齐,对于注入组:
注入组通道转换的数据值已经减去了在ADC_JOFRx 寄存器中定义的偏移量,因此结果可以是一个负值。SEXT 位是扩展的符号值,SEXT可以位负号。 对应的下图:一般使用的是右对齐,这样读取到的结果就直接是转换的结果。
左对齐会是转换后的数据增大,左移一位×2,对应规则组就是扩大16倍。
如果你不需要这右对齐这么高的精度(分辨率)也就是0~4095(2的12次方-1),就是做一个简单的判断,将数据左移4位,然后舍弃低八位的数据,这样12位的ADC就被当作8位ADC来使用。
5.2采样时间的计算
AD转换的步骤:采样,保持,量化,编码
STM32 ADC的总转换时间为:
TCONV = 采样时间 + 12.5个ADC周期
例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期
TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs
其中 量化、编码这两个过程属于逐次比较的过程,一般位数较多,花的时间也就越多。 而 采样、保持是配合 逐次逼近比较的,因为 采集的数据是动态的,同时量化编码又需要一段时间,所以需要 采样保持来使电压不变。 其内部由一个采样开关和一个电容构成,当采样电压时,闭合开关,储存好了采样电压,就断开开关,由于电容的作用,能够保持一段时间该电压不变。 采样时间越大,越能避免一些毛刺信号的干扰,但花费的时间也越长。6.逐次逼近比较法
接下里通过对一个8位ADC来介绍逐次逼近比较法:
首先从外部接收到一个未知编码的电压进入到比较器,同时DAC数模转换中为一个已知编码 值的电压进入到比较器中。通过比较,在逐次逼近寄存器SAR中不断改变DAC内的编码电压,直到 DAC输出的电压和外部输入的电压近视相等,就输出到锁存寄存器中储存。 具体操作是,由于该ADC为8位,对应的值就为0~255,通过二分法: 如上图,就会不断的进行二分比较目标值188,第一次DAC为255和0中间的127,第二次是127和255之间的191,以此类推,最终大概第6次的时候,就能近似188目标值,然后输出DAC的值到锁存寄存器中储存。 实际上,二分法对应的就是二进制从高位第8位到低位的判断1还是0的过程,例如: 188=1011 1100,对应二分法中DAC的值比188小的时候就改位就置1。 对应的,12位ADC也就是0~4095,同样的对应12位的输出DAC的值,12位的存储寄存器,都是类似的方法。 接下里就介绍ADC的不同配置。7.ADC的配置
首先是开启时钟,以及初始化ADC采样输入的接口。
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*设置ADC时钟*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为模拟输入
模式采用模拟输入模式(GPIO_Mode_AIN),GPIO引脚直接接入ADC中:
最后还需关注一个模式输入的引脚重映射,来选择GPIO端口:
接下来配置ADC规则组通道:
/*规则组通道配置*/
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0
上述采用的ADC规则组,使用的函数是ADC_RegularChannelConfig ,对应的如果想要使用ADC的注入组,使用函数ADC_InjectedChannelConfig,接下来对ADC_RegularChannelConfig 规则组进行展开。
跳转到定义:
参数较多,首先是ADCx,也就是选择ADC1~3外设。
然后是ADC_Channel,也就选择规则组的通道,每个外设ADC都会有所差异,PAx为默认重映射的引脚如下图:
下一个参数是选择第几行,行数值小的先执行,如下图先:
先选择通道二ADC_Channel_2,然后放到第一行(rank)1。
最后一个ADC_SampleTime转换时间,根据自身的需求来选择,如果你需要更快的转换,则选择更小的参数,也即ADC_SampleTime_1Cycles5;
需要更稳定的转换,则选择更大的参数ADC_SampleTime_71Cycles5,相应的转换时间也会更长。
如果都没要求,可以任意选择。
这样就配置好规则组通道的配置,如果还想再设置一个通道,就可以对上述代码进行复制,修改一下通道和RANK就行。
然后配置ADC通道的模式、数量等参数:
/*ADC初始化*/
ADC_InitTypeDef ADC_InitStructure; //定义结构体变量
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //非连续转换(单次转换),每转换一次规则组序列后停止
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //非扫描模式,只转换规则组的序列1这一个位置
ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1
首先是ADC_Mode,跳转定义:
其中,除了第一个的单ADC模式,其他的都为双ADC模式下的选择。
接着是数据对齐方式,一般是右对齐。
然后是外部触发ADC来源选择,选择需要要外部触发,也即软件触发。
接着是扫描和连续的选择,这个也是根据自身的需求来的,同时结合扫描和连续的作用,这里转换一个通道一次,选择非扫描、非连续(单次)转换的模式。
然后是通道数量,根据配置的通道数量来选择,这里选1,1个通道。
ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行
/*ADC校准*/
ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
接着是ADC使能以及ADC校准,这里就不在进行展开了。
最后设置一个返回ADC转换值的函数:
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); //在每次转换前,根据函数形参灵活更改规则组的通道1
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果
}
通过读取AD_GetValue函数的返回值,就可以得到AD转换后的数值。
8.总结
以上就是对ADC模数转换器的全部介绍了,其中没有介绍到的双ADC模式,自行查阅资料进行展开,不过最重要的还是得回归数据手册来进行理解,最后欢迎大家来进行讨论以及指正文章错误的地方。
文章参考:[7-2] AD单通道&AD多通道_哔哩哔哩_bilibili
标签:总结,转换,规则,关于,ADC,寄存器,注入,通道 From: https://blog.csdn.net/qq_68915581/article/details/141180786