关于ADC的一些总结

前言

        由于在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~40952的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个时钟间隔采样时间的转换),触发之间最小的间隔必须是29ADC时钟周期。

        这意味着,从一次触发事件开始到下一次触发事件开始,这段时间必须足够长,以确保当前的注入转换序列能够完全执行完成,以避免不同注入转换序列之间的冲突或中断。

        同时还有一个自动注入:
         如果设置了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 数据结果
        利用下列公式得出温度
        温度(°C) = {(V25 - VSENSE) / Avg_Slope} + 25
这里: V25 = VSENSE25°C时的数值
        Avg_Slope = 温度与VSENSE曲线的平均斜率(单位为mV/ °C μV/ °C)
        参考数据手册的电气特性章节中V25 Avg_Slope的实际值。
注意: 传感器从关电模式唤醒后到可以输出正确水平的VSENSE前,有一个建立时间。ADC在上电后也
有一个建立时间,因此为了缩短延时,应该同时设置ADONTSVREFE位。
        
        上述为手册对温度传感器的温度公式进行计算,有需要的自行查阅。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值