您当前的位置: 首页 >  stm32

正点原子

暂无认证

  • 0浏览

    0关注

    382博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【正点原子STM32连载】 第三十一章 ADC实验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1

正点原子 发布时间:2022-09-09 10:54:57 ,浏览量:0

1)实验平台:正点原子MiniPro H750开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=677017430560 3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-336836-1-1.html 4)对正点原子STM32感兴趣的同学可以加群讨论:879133275

第三十一章 ADC实验

本章,我们将介绍STM32H750的ADC(Analog-to-digital converters,模数转换器)功能。我们通过四个实验来学习ADC,分别是单通道ADC采集实验、单通道ADC采集(DMA读取)实验、多通道ADC采集(DMA读取)实验和单通道ADC过采样(26位分辨率)实验。 本章分为如下几个小节: 31.1 ADC简介 31.2 单通道ADC采集实验 31.3 单通道ADC采集(DMA读取)实验 31.4 多通道ADC采集(DMA读取)实验 31.5 单通道ADC过采样(26位分辨率)实验

31.1 ADC简介 STM32H750xx系列有3个ADC,都可以独立工作,其中ADC1和ADC2还可以组成双重模式(提高采样率),ADC3比较独立,我们在下一章会有详细的讲解。 STM32H750的ADC主要特性我们可以总结为以下几条: 1、可配置16位、14位、12位、10位或8位分辨率,降低分辨率可以缩短转换时间,转换时间越短,可以做到的采样率就越高。 2、每个ADC支持多达20个的采集通道,其中有6路快速通道和14路慢速通道,慢速和快速的区别主要是支持的最高采样率不同,慢速通道要比快速通道低。这些通道的A/D转换可以单次、连续、扫描或间断模式执行。 3、ADC的结果可以左对齐或右对齐方式存储在32位数据寄存器中。 4、ADC具有五条专用的内部通道,内部参考电压 (VREFINT ) 连接到ADC3_INP/INN19,内部温度传感器 (VSENSE ) 连接到 ADC3_INP/INN18和VBAT 监测通道 (VBAT /4) 连接到 ADC3_INP/INN17,这三个都是连接到ADC3。另外DAC内部通道1连接到ADC2_INP/INN16,DAC内部通道2连接到ADC2_INP/INN17。 5、支持过采样,最高可以达到26位采样率。 6、每个ADC支持三路模拟看门狗。 7、支持单独输入和差分输入(可按通道进行编程)。 8、ADC输入范围:VREF– ≤ VIN ≤ VREF+。由VREF- 、VREF+ 、VDDA 和VSSA 这四个外部引脚决定。一般我们把VSSA 和VREF- 接地,把 VREF+ 和VDDA接到3.3V,所以得到ADC 的输入电压范围是:0~3.3V。注意不要接超出这个范围的电压进来,否则容易烧坏芯片。 9、自校准(偏移校准和线性度校准)。 10、最多4条注入转换序列,16条常规转换序列。 上面我们列出的一些特性都是ADC重要的特性,其它特性请查看参考手册。 下面来介绍ADC(仅限ADC1或ADC2)的框图: 在这里插入图片描述

图31.1.1 ADC框图 图中,我们标记了11处位置,分别如下: ① VREF+电压 VREF+ 是正模拟参考电压输入,选择范围是1.8V3.6V,开发板上我们一般给VREF+接入的电压时3.3V,所以得到开发板上的ADC测量范围是03.3V。 ②ADC的双时钟域架构 ADC有两种时钟源可以选择,分别是: (1)adc_hclk(属于同步时钟),来自AHB总线的系统时钟,ADC1和ADC2处在240MHz的 AHB1总线时钟。可以通过ADCx_CCR寄存器的CKMODE[1:0]位来选择不同分频的AHB1总线时钟,有以下的四种情况: CKMODE[1:0]=00,这是异步时钟模式选择的配置,适用于下面要讲的adc_ker_ck时钟。 CKMODE[1:0]=01,adc_hclk/1(同步时钟模式) CKMODE[1:0]=10,adc_hclk/2(同步时钟模式) CKMODE[1:0]=11,adc_hclk/4(同步时钟模式) 比如我们选择4分频的adc_hclk,得到的频率是60MHz,但是数据手册限制ADC时钟频率最高是36MHz,说明这样配置就超频了,这是不可行的,因为超频误差会比较大。我们可以降低AHB总线时钟,但是这样会影响我们其它外设的性能,所以为了系统能达到最优的性能,我们一般不会选择adc_hclk作为ADC的时钟源,于是我们选择下面要说的这种时钟源。 (2)adc_ker_ck(属于异步时钟),可以通过RCC_D3CCIPR寄存器的ADCSEL [1:0]位来选择不同的时钟源,前提是前面提到的CKMODE[1:0]=00。ADC异步时钟模式下可以选择以下的时钟源: ADCSEL [1:0]=00,pll2_p_ck作为ADC时钟源(复位后的默认值) ADCSEL [1:0]=01,pll3_r_ck作为ADC时钟源 ADCSEL [1:0]=10,per_ck作为ADC时钟源 实际的例程中我们选择per_ck作为ADC时钟源,而per_ck 时钟可为 hse_ck、hsi_ker_ck 或 csi_ker_ck,通过RCC_D1CCIPR寄存器的CKPERSEL位选择,默认选择hsi_ker_ck作为per_ck的时钟源。hsi_ker_ck时钟源就是来自频率为64MHz的高速内部RC振荡器(HSI)。 选择了adc_ker_ck时钟源作为ADC的时钟,则可以通过ADCx_CCR寄存器的PRESC[3:0]位进行分频,可以是1、2、4、6、8、10、12、16、32、64、128、256这12种分频系数。 上面的分析请结合下面的ADC时钟方案图理解。 在这里插入图片描述

图31.1.2 ADC时钟方案 ③输入通道 ADC总共有20个输入通道。注意:STM32H7的ADC支持单端/差分转换,由寄存器ADCx_DIFSEL(x=1~3)控制,该寄存器默认是0(单端模式),配置为1(则为差分模式)。因为H750的ADC支持差分通道输入,因此有ADCx_INP[19:0]和ADCx_INN[19:0]两组通道。其中,INP是差分正向输入,INN是差分反向输入。ADC_INP[0:5]和 ADC_INN[0:5]是快速模拟输入。ADC_INP[6:19]和 ADC_INN[6:19]是慢速模拟输入。如果我们使用单端输入,则只有ADCx_INP[19:0]有效,ADCx_INN[19:0]在内部自动接VSSA。 ADC连接5路内部模拟输入,分别是: (1)内部参考电压 (VREFINT ) 连接到ADC3_INP/INN19。 (2)内部温度传感器 (VSENSE ) 连接到ADC3_INP/INN18。 (3)VBAT 监测通道 (VBAT/4) 连接到ADC3_INP/INN17。 (4)DAC内部通道1,连接到ADC2_INP/INN16。 (5)DAC内部通道2,连接到ADC2_INP/INN17。 为了方便大家查询ADC通道和IO的对应关系,给大家整理了表31.1.1。大多数情况,我们都是使用单端模式。前面也说了单端模式下,ADCx_INN[19:0]在内部自动接VSSA,所以表31.1.1中的通道0~通道19指的是ADCx_INP[19:0]。 在这里插入图片描述

表31.1.1 ADC通道表 由于开发板上使用的主控芯片是STM32H750VBT6,它的封装是LQFP100。该封装是没有表31.1.1中标黄色的IO引脚,所以相关的通道自然是没有引出来。 ④转换序列 可以将转换分为两组:常规转换组和注入转换组。常规转换组最多允许16个通道进行转换。注入转换组最多允许4个通道进行转换。 如何理解常规转换组和注入转换组?常规转换组相当于你正常运行的程序,而注入转换组就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的,获得优先执行的权利。所以注入转换组可以打断常规转换组的转换,获得优先转换的权利,在注入转换组转换完成后,常规转换组才得以继续转换。 为了便于理解,请看常规转换组和注入转换组的转换优先级对比图,如图31.1.3所示: 在这里插入图片描述

图31.1.3 常规转换组和注入转换组的转换优先级对比图 常规转换组最多允许16个通道进行转换,注入转换组最多允许4个通道进行转换,那么转换的顺序怎么设置的?我们把这个转换顺序分别称为常规序列和注入序列。 (1)常规序列 常规序列在ADCx_SQRy寄存器中设置,每个ADC都有4个SQR寄存器,比如ADC1的SQR寄存器有ADC1_SQR1~ ADC1_SQR4。这四个寄存器怎么来设置常规序列的呢?下面通过表31.1.2给大家说明。 在这里插入图片描述

表31.1.2 常规序列寄存器控制关系汇总表 从上表可以知道,当我们想设置ADC的某个输入通道在常规序列的第1个转换,只需要把相应的输入通道号的值写入SQR1寄存器中的SQ1[4:0]位即可。例如想让输入通道5先进行转换,那么就可以把5这个数值写入SQ1[4:0]位。如果还想让输入通道8在第2个转换,那么就可以把8这个数值写入SQ2[4:0]位。最后还要设置你的这个规则序列的输入通道个数,只需把通道个数写入SQR1的SQL[3:0]位。注意:写入0到SQL[3:0]位,表示这个常规序列有1个通道的意思,而不是0个通道。 (2)注入序列 注入序列和常规序列差不多,决定的是注入转换组的顺序。注入组最大允许4个通道输入,它的注入序列由JSQR寄存器配置。注入序列寄存器JSQR控制关系如表31.1.3所示: 注入序列寄存器控制关系汇总 在这里插入图片描述

表31.1.3 注入序列寄存器控制关系汇总表 注入序列的长度写入JL [ 1 : 0 ]位,范围是0~3。注意:写入0表示这个注入序列有一个通道,而不是0个通道。 ⑤触发源 ADC的触发转换有两种方法:分别是通过软件或外部事件(也就是硬件)触发转换。 我们先来看看通过软件触发转换的方法,常规通道由ADCx_CR寄存器的ADSTART位触发,注入通道由ADCx_CR寄存器的JADSTART位触发。方法是:通过对ADCx_CR寄存器的ADSTART(JADSTART)位写1开始转换,转换结束由硬件清零该位,这个控制ADC转换的方式非常简单。 另一种就是通过外部事件触发转换的方法,如定时器和输入引脚触发等等,具体请看《STM32H7xx参考手册_V3(中文版).pdf》的825页和826页的表192和表193。外部事件触发转换可分为:常规通道的外部触发和注入通道的外部触发两种。 adc_ext_trg[20:0],对应的就是常规通道的外部触发,共有21路。 adc_jext_trg[20:0],对应的就是注入通道的外部触发,共有21路。 如果选择硬件触发,则需要选择相应的硬件触发事件和触发边沿等,然后由外部硬件事件来触发ADC的采集(外部事件触发配置ADSTART位为1)。 硬件触发事件由ADCx_CFGR寄存器的EXTSEL[4:0]和ADCx_JSQR寄存器的 JEXTSEL[4:0]位来选择,分别是常规转换组和注入转换组的触发源选择。而触发边沿是通过ADCx_CFGR寄存器的EXTEN[1:0]和ADCx_JSQR寄存器的JEXTEN[1:0]位来选择。 ⑥转换时间 STM32H7的ADC总转换时间的计算公式如下: TCONV = 采样时间(TSMPL) + 逐次逼近时间(TSAR) 采样时间(TSMPL)可通过ADCx_SMPR1和ADCx_SMPR2寄存器中的SMP[2:0]位编程,ADC_SMPR1控制的是通道09,ADC_SMPR2控制的是通道1019。所有通道都可以通过编程来控制使用不同的采样时间,可选采样时间值如下: SMP = 000:1.5 个 ADC 时钟周期 SMP = 001:2.5 个 ADC 时钟周期 SMP = 010:8.5 个 ADC 时钟周期 SMP = 011:16.5 个 ADC 时钟周期 SMP = 100:32.5 个 ADC 时钟周期 SMP = 101:64.5 个 ADC 时钟周期 SMP = 110:387.5 个 ADC 时钟周期 SMP = 111:810.5 个 ADC 时钟周期 逐次逼近时间(TSAR)是由分辨率决定的,分辨率通过对ADCx_CFGR寄存器的RES[1:0]位进行编程,可将分辨率配置为16位、14位、12位、10位、8位。而逐次逼近时间和分辨率的对应关系如下表所示: 在这里插入图片描述

表31.1.4 TSAR与分辨率的对应关系 举个例子,我们配置SMP = 111,即设置最大采样周期,然后采用16位分辨率,那么得到: TCONV = 810.5个ADC时钟周期 + 8.5个ADC时钟周期 = 819个ADC时钟周期 表格中,FADC的频率是24MHZ,我们的例程中ADC的时钟源是64MHZ的hsi_ker_ck经过2分频得到,即32MHZ。我们就以FADC的频率为32MHZ来举例,可得到: TCONV = 819个ADC时钟周期 = = 25.6us ⑦参考电压 选择参考电压,我们可以设置参考电压来自外部的Vref+,也可以设置参考电压来自内部的稳压器。 ⑧ADC的核心 ADC的核心是一个16位的逐次逼近型ADC转换器,它根据我们设置好的参考电压、输入通道、启动条件等,执行模数转换。 ⑨数据寄存器 常规转换组的转换结果会存放到ADCx_DR寄存器的RDATA[31:0]位中,注入转换组的转换结果会存放到ADCx_JDRy寄存器的JDATA1~4[31:0]位中。如果是使用双重模式,常规通道的数据则是存放在ADC_CDR寄存器。转换结果CPU可以通过AHB总线读取,同时也可以产生相关中断(adc_it)。 常规数据寄存器(ADCx_DR)(x=1~4) 常规数据寄存器ADC_DR是一个32位的寄存器。因为ADC的最大分辨率是16位,如果使用过采样,则分辨率可达26位,所以允许数据对齐方式。由ADC_CFGR2寄存器的OVSS[3:0]位和LSHIFT[3:0]位设置数据对齐方式。 细心的朋友可能发现,常规转换组最多有16个输入通道,而ADC常则数据寄存器只有一个,如果一个常则转换组用到好几个通道,数据怎么读取?如果使用多通道转换,那么这些通道的数据也会存放在DR里面,按照常规转换组的顺序,上一个通道转换的数据,会被下一个通道转换的数据覆盖掉,所以当通道转换完成后要及时把数据取走。比较常用的方法是使用DMA模式。当常规转换组的通道转换结束时,就会产生DMA请求,这样就可以及时把转换的数据搬运到用户指定的目的地址存放。如果没有使用DMA传输,可以通过判断ADC_ISR寄存器相关位来得到当前ADC的转换状态,从而进行控制。 注入数据寄存器(ADCx_JDRy)(x=13)(y=14) 每个ADC注入数据寄存器有4个,注入转换组最多有4个输入通道,刚好每个通道都有自己对应的数据寄存器。ADC_JDRx寄存器是32位的,低16位有效,高16位保留,数据也同样需要选择对齐方式。也是由ADC_CFGR2寄存器的OVSS[3:0]位和LSHIFT[3:0]位设置数据对齐方式。 通用常则数据寄存器ADC_CDR 常规数据寄存器ADC_DR仅适用于独立模式下,常规转换组的转换数据存储,而通用常规数据寄存器ADC_CDR适用于双重模式下,常规转换组的转换数据存储。在双重模式下,一般会配合DMA来传输数据。 ⑩中断 对于每个ADC都可在下列情况下产生中断: 在这里插入图片描述

表31.1.5 每个ADC的ADC中断 在表31.1.5中,前面5个中断都很好理解,我们从模拟看门狗中断介绍。 模拟看门狗中断发生条件:首先通过ADCx_LTR和ADCx_HTR寄存器设置低阈值和高阈值,然后开启了模拟看门狗中断后,当被ADC转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断。例如我们设置高阈值是3.0V,那么模拟电压超过3.0V的时候,就会产生模拟看门狗中断,低阈值的情况类似。 采样阶段结束:如果位EOSMP被硬件置1,则说明采样阶段结束(仅限常规转换),然后可以通过对EOSMP位写1来清零该位。如果EOSMPIE位置1,可以产生采样阶段结束中断。 上溢:如果常规转换后的数据未在新转换数据可用之前(由CPU或DMA)读取,会由溢出标志(OVR)指示缓冲区溢出事件。如果OVRIE位置1,可以产生一个溢出中断。 此外,我们还要知道常规组和注入组的转换结束后,除了产生中断外,还可以产生DMA请求,把转换好的数据存储在内存里面,防止读取不及时数据被覆盖。 ⑪通道预选控制信号 通道预选控制信号,用于将ADC某个通道连接到对应的GPIO上。PCSEL[19:0]每个位对应一个通道,总共20个通道。这一点和以前的STM32系列不一样,在使用的时候,需要特别注意。 ⑫单次转换模式和连续转换模式 单次转换模式和连续转换模式在框图中是没有标号,为了更好地学习后续的内容,这里简单给大家讲讲。 (1)单次转换模式 通过将ADC_CFGR寄存器的CONT位置0选择单次转换模式。该模式下,ADC只执行一次转换。单次转换由ADC_CR寄存器的ADSTART位(只适用于常规转换组)或者JADSTART位(只适用于注入转换组)启动,也可以通过外部事件触发启动(适用于常规转换组或注入转换组),并且触发外部事件之前,ADSTART位或JADSTART位必须置1。 在常规序列中,每次转换完成后:转换数据存储在32位ADCx_DR寄存器中、EOC(常规转换结束)标志置 1、EOCIE位置1时将产生中断。 在注入序列中,每次转换完成后:转换数据存储在四个32位ADC_JDR1寄存器的其中一个寄存器中、JEOC(注入转换结束)标志置1、JEOCIE 位置1时将产生中断。 常规序列完成后:EOS(常规序列结束)标志置1、EOSIE位置1时将产生中断。 注入序列完成后:JEOS(注入序列结束)标志置1、JEOSIE 位置1时将产生中断。 随后,ADC会停止工作,直至发生新的外部常规或注入触发,或者将ADSTART或JADSTART位再次置1。 (2)连续转换模式 通过将ADC_CFGR寄存器的CONT位置1选择连续转换模式。该模式仅适用于常规转换组。在连续转换模式下,如果发生软件或者硬件常规触发事件,ADC会将常规转换组的所有通道执行一次,随后会自动重启并持续执行序列的每个转换。CONT位为1时,可通过外部触发或将ADCx_CR寄存器中的ADSTART位置1来启动此模式。 在常规序列中,每次转换完成后:转换数据存储在32位ADCx_DR寄存器中、EOC(转换结束)标志置1、EOCIE 位置1时将产生中断。 转换序列完成后:EOS(序列结束)标志置 1、EOSIE位置1时将产生中断。 随后,会立即重启新序列,ADC会继续重复执行转换序列。 注意:注入通道不能连续转换,唯一例外的是,在连续转换模式下(使用JAUTO位)注入通道配置为在常规通道后的自动转换。 到这里,我们基本上介绍了ADC的大多数基础的知识点,其它知识后面用到会继续补充,如果还有不懂的内容,请参考《STM32H7xx参考手册_V3(中文版).pdf》的第25章。 31.2 单通道ADC采集实验 本实验我们来学习单通道ADC采集实验。本实验使用常规转换组单通道的单次转换模式,并且通过软件触发,即通过对ADCx_CR寄存器的ADSTART位写1启动转换。下面先带大家来了解本实验要配置的寄存器。 31.2.1 ADC寄存器 这里,我们只介绍本实验用到的寄存器的关键位,其它寄存器后续用到会继续介绍。 ADCx通用控制寄存器(ADCx_CCR) ADCx通用控制寄存器描述如图31.2.1.1所示: 在这里插入图片描述

图31.2.1.1 ADCx_CCR寄存器 该寄存器本章只需要用到PRESC[3:0]这四个位,用于设置ADC时钟的预分频系数(即对adc_ker_ck的分频系数),由上图可以得到这四个位域的值的含义可以表示为设置2^PRESC[3:0]分频。 adc_ker_ck的时钟源由RCC_D3CCIPR寄存器的ADCSEL[1:0]位配置。本章的实验我们都设置ADCSEL[1:0]=2,即选择per_ck作为时钟源,而per_ck又由RCC_D1CCIPR寄存器的CKPERSEL[1:0]位选择,默认为0,即选择hsi_ker_ck(64MHz)作为per_ck。因此: adc_ker_ck=per_ck=hsi_ker_ck=64MHz。 又由于ADC的输入时钟频率不能大于36M,所以,我们需要设置PRESC[3:0]=1,即可得到ADC输入时钟频率为: adc_ker_ck/2^PRESC[3:0]=64/2=32MHz。 ADCx控制寄存器(ADCx_CR) ADCx控制寄存器描述如图31.2.1.2所示: 在这里插入图片描述

图31.2.1.2 ADCx_CR寄存器 该寄存器我们用到多个位,这里就不全部列出来讲解了,而是抽出几个重要的位进行针对性的介绍,详细的介绍请参考《STM32H7xx参考手册_V3(中文版).pdf》第25.5.3节,881页。 ADEN位用于使能ADC转换器。需要设置该位为1,ADC才可以正常工作。 ADSTART位用于启动ADC常规通道的转换序列。当使用硬件触发时(EXTEN[1:0]!=0),设置该位为1,必须在相应的硬件触发事件产生时,才会启动ADC转换。而当不使用硬件触发时(EXTEN[1:0]=0),设置该位为1则可以立即启动ADC转换。 BOOST位用于设置是否使用BOOST模式。当BOOST=0时,ADC输入时钟必须小于20MHz;当BOOST=1时,ADC输入时钟必须大于20MHz。因为我们设置的ADC输入时钟频率为32MHz,因此该位必须设置为1。 ADCALLIN位用于设置线性ADC校准。设置该位为1,可以设置ADC的校准模式为线性校准。 ADCAL位用与控制/读取ADC校准状态。设置该位为1时,可以启动ADC校准,等校准完成以后,硬件会自动清零该位。因此在设置改位为1以后,通过判断该位是否变为0,即可判断校准是否完成。 ADCx配置寄存器(ADCx_CFGR) ADCx配置寄存器描述如图31.2.1.3所示: 在这里插入图片描述

图31.2.1.3 ADCx_CFGR寄存器 RES[2:0]位用于设置ADC转换的分辨率:0表示16位;1表示14位;2表示12位;3表示10位;4表示8位;其它值:保留。本实验使用16位分辨率,因此设置RES[2:0]=0即可。 EXTEN[1:0]位用于设置常规通道的外部触发方式和极性。本实验使用软件触发,因此设置EXTEN[1:0]=00即可,即禁止外部触发。 OVRMOD位用于设置是否使能覆写功能。当设置该位为0时,如果上一次转换的数据未及时读取,新的转换结果将被丢弃;当设置该位为1时,如果上一次转换的数据未及时读取,将会被新的结果覆盖。本实验该位设置为1。 CONT位用于设置转换模式。当CONT=0时,表示单次转换模式;当CONT=1时,表示连续转换模式。本实验该位设置为0。 ADCx配置寄存器2(ADCx_CFGR2) ADCx配置寄存器2描述如图31.2.1.4所示: 在这里插入图片描述

图31.2.1.4 ADCx_CFGR2寄存器 OSR[9:0]位用于设置ADC的过采样率。OSR[9:0]=01023,表示1x1024x过采样。本实验不使用过采样,设置OSR[9:0]=0即可。 LSHIFT[3:0]位用于设置输出结果的左移位数,015表示左移015位。本实验使用右对齐,因此设置LSHIFT[3:0]=0即可。 ADCx常规序列寄存器1(ADCx_SQR1) ADCx常规序列寄存器1描述如图31.2.1.5所示: 在这里插入图片描述

图31.2.1.5 ADCx_SQR1寄存器 L[3:0]位用于存储常规序列的长度,取值范围:015,表示常规序列长度为:116。本实验只用到1个通道,L[3:0]=0即可。 SQ1[4:0]SQ4[4:0]同于设置常规序列中第14个转换通道,第5~16个转换通道的设置请查看ADCx_SQR2和ADCx_SQR4寄存器。设置过程非常简单,忘记了请参考前面给大家整理出来的常规序列寄存器控制关系汇总表。 ADCx采样时间寄存器2(ADCx_SMPR2) ADCx采样时间寄存器2描述如图31.2.1.6所示: 在这里插入图片描述

图31.2.1.6 ADCx_SMPR2寄存器 该寄存器用于设置ADC通道1019的采样时间,而ADCx_SMPR1设置ADC通道09的采样时间。STM32H7的ADC总转换时间的计算方法前面已经介绍过了。建议采样时间尽量长一点,以获得较高的准确度,但是这样会降低ADC的转换速率,所以大家在实际应用中自行结合自身情况设置。 ADCx通道预选寄存器(ADCx_ PCSEL) ADCx通道预选寄存器描述如图31.2.1.7所示: 在这里插入图片描述

图31.2.1.7 ADCx_ PCSEL寄存器 该寄存器用于控制ADC具体某个输入通道和对应IO的连接,相当于在ADC输入和IO之间,加了一个开关,想要正常使用某个通道,则必须设置对应的PCSELy位为1(y=0~19),否则无法得到对应IO口的正常电压。注意:在STM32H7之前的的其它STM32芯片上面,是没有该寄存器的。该寄存器的存在,有利于ADC和IO的隔离。 举个简单的例子,在STM32H7上面,即便是ADC通道对应的IO口,只要不使用ADC功能(PCSEL不设置为1),那么该IO口就可以兼容5V,但是在STM32H7之前的其它STM32芯片上面,ADC所在的IO口,都不能做5V兼容。 ADCx常规数据寄存器(ADCx_ DR) ADCx常规数据寄存器描述如图31.2.1.8所示: 在这里插入图片描述

图31.2.1.8 ADCx_ DR寄存器 常规序列中的AD转化结果都将被存在这个寄存器里面,我们读取该寄存器,即可得到ADC转换后的结果,而注入通道的转换结果被保存在ADCx_JDRy(y=1~4)里面。 ADCx中断和状态寄存器(ADCx_ ISR) ADCx中断和状态寄存器描述如图31.2.1.9所示: 在这里插入图片描述

图31.2.1.9 ADCx_ ISR寄存器 该寄存器保存了ADC转换时的各种状态。本实验我们通过EOC位的状态来判断ADC转换是否完成,如果查询到EOC位被硬件置1,就可以从ADC_DR寄存器中读取转换结果,否则需要等待转换完成。 至此,本章要用到的ADC相关寄存器全部介绍完毕了,对于未介绍的部分,请大家参考《STM32H7xx参考手册_V7(英文版).pdf》第25章相关内容。 31.2.2 硬件设计

  1. 例程功能 使用ADC1采集通道19(PA5)上面的电压,在LCD模块上面显示ADC转换值以及换算成电压后的电压值。使用短路帽将P3的ADC和RV1连接,使得PA5连接到电位器上,然后将ADC采集到的数据和转换后的电压值在TFTLCD屏中显示。用户可以通过调节电位器的旋钮改变电压值。LED0闪烁,提示程序运行。
  2. 硬件资源 1)RGB灯 RED : LED0 - PB4 2)串口1(PA9/PA10连接在板载USB转串口芯片CH340上面) 3)正点原子2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动) 4)ADC1 :通道19 - PA5
  3. 原理图 ADC属于STM32H750内部资源,实际上我们只需要软件设置就可以正常工作,另外还需要将待测量的电压源连接到ADC通道上,以便ADC测量。本实验,我们通过ADC1的通道19(PA5)来采集外部电压值,开发板有一个电位器,可调节的电压范围是:0~3.3V。我们可以通过短路帽将PA5与电位器连接,如下图所示: 在这里插入图片描述

图31.2.2.1 PA5与电位器示意图 使用短路帽将P3的ADC和RV1连接好后,并下载程序后,就可以用螺丝刀调节电位器变换多种电压值进行测试。 有的朋友可能还想测试其它地方的电压值,我们只需要1跟杜邦线,一端接到P3的ADC排针上,另外一端就接你要测试的电压点。一定要保证测试点的电压在0~3.3V的电压范围,否则可能烧坏我们的ADC,甚至是整个主控芯片。 31.2.3 程序设计 31.2.3.1 ADC的HAL库驱动 ADC在HAL库中的驱动代码在stm32h7xx_hal_adc.c和stm32h7xx_hal_adc_ex.c文件(及其头文件)中。

  1. HAL_ADC_Init函数 ADC的初始化函数,其声明如下: HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef *hadc); 函数描述: 用于初始化ADC。 函数形参: 形参1是ADC_HandleTypeDef结构体类型指针变量,其定义如下:
typedef struct
{
  ADC_TypeDef                    *Instance;        	/* ADC寄存器基地址 */ 
  ADC_InitTypeDef               Init;               /* ADC参数初始化结构体变量 */   
  DMA_HandleTypeDef             *DMA_Handle;      /* DMA配置结构体 */        
  HAL_LockTypeDef               Lock;               /* ADC锁定对象 */    
  __IO uint32_t                 State;              /* ADC工作状态 */     
  __IO uint32_t                 ErrorCode;         /* ADC错误代码 */    
  ADC_InjectionConfigTypeDef InjectionConfig ; /* ADC注入通道配置结构,用于配置注入通道的转换顺序,数据格式等 */  
}ADC_HandleTypeDef;
该结构体定义和其他外设比较类似,我们着重看第二个成员变量Init含义,它是结构体
ADC_InitTypeDef类型,结构体ADC_InitTypeDef定义为:
typedef struct {
 uint32_t ClockPrescaler;                 	/* 设置预分频系数,即PRESC[3:0]位 */
 uint32_t Resolution;                      	/* 配置ADC的分辨率 */
 uint32_t ScanConvMode;                    	/* 扫描模式 */
 uint32_t EOCSelection;                    	/* 转换完成标志位 */
 FunctionalState LowPowerAutoWait;       	/* 低功耗自动延时 */
 FunctionalState ContinuousConvMode;     	/* 设置单次转换模式还是连续转换模式 */
 uint32_t NbrOfConversion;                 	/* 设置转换通道数目,赋值范围是1~16 */
 FunctionalState DiscontinuousConvMode; 	/* 设置常规转换组不连续模式 */
 uint32_t NbrOfDiscConversion;            	/* 常规转换组不连续模式转换通道的数目 */
 uint32_t ExternalTrigConv;                	/* ADC外部触发源选择*/
 uint32_t ExternalTrigConvEdge;           	/* ADC外部触发极性*/
 uint32_t ConversionDataManagement;      	/* 数据管理 */
 uint32_t Overrun;                          	/* 发生溢出时,进行的操作 */
 uint32_t LeftBitShift;                    	/* 数据左移几位 */
 FunctionalState OversamplingMode;       	/* 过采样模式 */
 ADC_OversamplingTypeDef Oversampling;  	/* 过采样的参数配置 */
} ADC_InitTypeDef;
  1. ClockPrescaler:ADC预分频系数选择,可选的分频系数为 1、2、4、6、8、10、12、16、32、64、128、256。ADC最大时钟配置为36MHZ。
  2. Resolution:配置ADC的分辨率,可选的分辨率有16 位、12 位、10 位和 8 位。分辨率越高,转换数据精度越高,转换时间也越长;反之分辨率越低,转换数据精度越低,转换时间也越短。
  3. ScanConvMode:配置是否使用扫描。如果是单通道转换使用ADC_SCAN_DISABLE,如果是多通道转换使用ADC_SCAN_ENABLE。
  4. EOCSelection:可选参数为ADC_EOC_SINGLE_CONV和ADC_EOC_SEQ_CONV,指定转换结束时是否产生EOS中断或事件标志。
  5. LowPowerAutoWait:配置是否使用低功耗自动延迟等待模式,可选参数为 ENABLE和 DISABLE,当使能时,仅当一组内所有之前的数据已处理完毕时,才开始新的转换,适用于低频应用。该模式仅用于ADC的轮询模式,不可用于DMA以及中断。
  6. ContinuousConvMode:可选参数为ENABLE和DISABLE,配置自动连续转换还是单次转换。使用ENABLE配置为使能自动连续转换;使用DISABLE配置为单次转换,转换一次后停止需要手动控制才重新启动转换。
  7. NbrOfConversion:设置常规转换通道数目,范围是:1~16。
  8. DiscontinuousConvMode:配置是否使用不连续的采样模式,比如要转换的通道有1、2、5、7、8、9,那么第一次触发会进行通道 1 与通道 2,下次触发就是转换通道 5 与通道 7,这样不连续的转换,依次类推。此参数只有将 ScanConvMode 使能,还有ContinuousConvMode失能的情况下才有效,不可同时使能。
  9. NbrOfDiscConversion:不连续采样通道数。
  10. ExternalTrigConv:外部触发方式的选择,如果使用软件触发,那么外部触发会关闭。
  11. ExternalTrigConvEdge:外部触发极性选择,如果使用外部触发,可以选择触发的极性,可选有禁止触发检测、上升沿触发检测、下降沿触发检测以及上升沿和下降沿均可触发检测。
  12. ConversionDataManagement: 指定ADC转换后的数据处理方式。可以选择 DMA管理传输数据、数据存储在数据寄存器中或者是传输到DFSDM寄存器中。
  13. Overrun:当有新的数据溢出时,可以选择覆盖写入或者是丢弃新的数据。
  14. LeftBitShift:数据左移位数,最多可支持左移15位。
  15. OversamplingMode:是否使用过采样模式。
  16. Oversampling:配置过采样模式的参数。 函数返回值: HAL_StatusTypeDef枚举类型的值。
  1. HAL_ADCEx_Calibration_Start函数 ADC的自校准函数,其声明如下: HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef *hadc, uint32_t CalibrationMode, uint32_t SingleDiff); 函数描述: 首先调用HAL_ADC_Init函数配置了相关的功能后,再调用此函数进行ADC自校准功能。 函数形参: 形参1是ADC_HandleTypeDef结构体类型指针变量。 形参2是校准模式选择,有以下两种: 1)ADC_CALIB_OFFSET表示只运行偏移校准而不运行线性度校准。 2)ADC_CALIB_OFFSET_LINEARITY表示同时运行偏移校准和线性度校准。 形参3是单端或差分模式选择,有以下两种: 1)ADC_SINGLE_ENDED表示单端输入模式。 2)ADC_DIFFERENTIAL_ENDED表示差分输入模式。 函数返回值: HAL_StatusTypeDef枚举类型的值。
  2. HAL_ADC_ConfigChannel函数 ADC通道配置函数,其声明如下: HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef *hadc, ADC_ChannelConfTypeDef *sConfig); 函数描述: 调用了HAL_ADC_Init函数配置了相关的功能后,就可以调用此函数配置ADC具体通道。 函数形参: 形参1是ADC_HandleTypeDef结构体类型指针变量。 形参2是ADC_ChannelConfTypeDef结构体类型指针变量,用于配置ADC采样时间,使用的通道号,单端或者差分方式的配置等。该结构体定义如下:
typedef struct {
  uint32_t Channel;                           	/* ADC转换通道*/
  uint32_t Rank;                              	/* ADC转换顺序 */
  uint32_t SamplingTime;                     	/* ADC采样周期 */
  uint32_t SingleDiff;                       	/* 输入信号线的类型*/
  uint32_t OffsetNumber;                     	/* 采用偏移量的通道 */
  uint32_t Offset;                         	   	/* 偏移量 */
  FunctionalState OffsetRightShift;        	/* 数据右移位数*/
  FunctionalState OffsetSignedSaturation; 	/* 转换数据格式为有符号位数据 */
} ADC_ChannelConfTypeDef;
  1. Channel:ADC转换通道,范围:0~19。
  2. Rank:在常规转换中的常规组的转换顺序,可以选择1~16。
  3. SamplingTime:ADC的采样周期,最大810.5个ADC时钟周期,要求尽量大以减少误差。
  4. SingleDiff:选择通道单端输入还是差分输入。
  5. OffsetNumber:选择使用偏移量的通道。
  6. Offset:定义要从原始数据减去的偏移量。根据ADC的分辨率不同,支持的最大偏移量也不同,例如分辨率是16bit,,最大的偏移量为0xFFFF。
  7. OffsetRightShift:采样值进行右移的位数。
  8. OffsetSignedSaturation:是否使能ADC采样值的最高位为符号位。 函数返回值: HAL_StatusTypeDef枚举类型的值。
  1. HAL_ADC_Start函数 ADC转换启动函数,其声明如下: HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc); 函数描述: 当配置好ADC的基础的功能后,就调用此函数启动ADC。 函数形参: 形参1是ADC_HandleTypeDef结构体类型指针变量。 函数返回值: HAL_StatusTypeDef枚举类型的值。
  2. HAL_ADC_PollForConversion函数 等待ADC常规组转换完成函数,其声明如下: HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef *hadc, uint32_t Timeout); 函数描述: 一般先调用HAL_ADC_Start函数启动转换,再调用该函数等待转换完成,然后再调用HAL_ADC_GetValue函数来获取当前的转换值。 函数形参: 形参1是ADC_HandleTypeDef结构体类型指针变量。 形参2是等待转换的等待时间,单位是毫秒(ms)。 函数返回值: HAL_StatusTypeDef枚举类型的值。
  3. HAL_ADC_GetValue函数 获取常规组ADC转换值函数,其声明如下: uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef hadc); 函数描述: 一般先调用HAL_ADC_Start函数启动转换,再调用HAL_ADC_PollForConversion函数等待转换完成,然后再调用HAL_ADC_GetValue函数来获取当前的转换值。 函数形参:ADC_HandleTypeDef结构体类型指针变量。 函数返回值:当前的转换值,uint32_t类型数据。 单通道ADC采集配置步骤 1)开启ADCx和ADC通道对应的IO时钟,并配置该IO为模拟功能 首先开启ADCx的时钟,然后配置GPIO为模拟模式。本实验我们默认用到ADC1通道19,对应IO是PA5,它们的时钟开启方法如下: __HAL_RCC_ADC12_CLK_ENABLE (); / 使能ADC1 & ADC2 时钟 / __HAL_RCC_GPIOA_CLK_ENABLE(); / 开启GPIOA时钟 */ 2)初始化ADCx, 配置其工作参数 通过HAL_ADC_Init函数来设置ADCx时钟分频系数、分辨率、模式、扫描方式、对齐方式等信息。 注意:该函数会调用:HAL_ADC_MspInit回调函数来存放ADC及GPIO时钟使能、GPIO初始化等代码。 3)配置ADC通道并启动AD转换器 在HAL库中,通过HAL_ADC_ConfigChannel函数来设置配置ADC的通道,根据需求设置通道、序列、采样时间和校准配置单端输入模式或差分输入模式等。 配置好ADC通道之后,通过HAL_ADC_Start函数启动AD转换器。 4)读取ADC值 这里选择查询方式读取,在读取ADC值之前需要调用HAL_ADC_PollForConversion等待上一次转换结束。然后就可以通过HAL_ADC_GetValue来读取ADC值。 31.2.3.2 程序流程图 在这里插入图片描述

图31.2.3.2.1 单通道ADC采集实验程序流程图 31.2.3.3 程序解析 这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。ADC驱动源码包括两个文件:adc.c和adc.h。 adc.h文件针对ADC及通道引脚定义了一些宏定义,具体如下:

/*****************************************************************************/
/* ADC及引脚 定义 */
#define ADC_ADCX_CHY_GPIO_PORT           GPIOA
#define ADC_ADCX_CHY_GPIO_PIN            GPIO_PIN_5
#define ADC_ADCX_CHY_GPIO_CLK_ENABLE()     
do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)   /* PA口时钟使能 */

#define ADC_ADCX                           ADC1 
#define ADC_ADCX_CHY                      ADC_CHANNEL_19 /* 通道Y,  0 CR &= ~(1 CR |= 1             
关注
打赏
1665308814
查看更多评论
0.0526s