1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码 手册 视频下载地址:http://www.openedv.com/thread-318813-1-1.html 4)正点原子官方B站:https://space.bilibili.com/394620890 5)正点原子STM32MP157技术交流群:691905614
第二十二章 ADC实验
本章,我们将介绍STM32MP157的ADC(Analog-to-digital converters,模数转换器)功能。我们通过四个实验来学习ADC,是单通道ADC采集实验,单通道ADC采集(DMA读取)实验,多通道ADC采集(DMA读取)实验和单通道ADC采样(26位分辨率)实验。 本章分为以下几个部分: 22.1 、ADC简介; 22.2 、单通道ADC采集实验; 22.3 、单通道ADC采集(DMA读取)实验; 22.4 、多通道ADC采集(DMA读取)实验; 22.5 、单通道ADC采样(26位分辨率)实验; 22.1 ADC简介 ADC即模拟数字转换器(Analog-to-digital converter),将连续变化的模拟信号转换为离散的数字信号。 在现实世界中,模拟信号,如温度、湿度、音量、压力或图像,是连续的,需要转换为MCU数字信号更容易存储、处理和发射,需要模具/数转换器。在这里,我们将区分一些概念: (1)转换采样率 ADC转换采样率(采样率)是指从模拟量转换为数字量ADC时间倒数,即每秒从连续信号中提取并转换为离散数字的信号数。 TCONV ,我们稍后会介绍TCONV 计算方法。 (2)分辨率 ADC分辨率是指满量程与2n次方的比值(n表示ADC用于计算精度的位数)表示能够采样/分辨的最小值。例如,我们经常听到二进制位的分辨率ADC分辨率为8位、10位、12位。例如,使用16位ADC去采集一个10V假设这个ADC能测量10V输入电压为10的电压信号V),这个16位的ADC满刻度(最大值)的数字量为2^16=65536,当AD655365536时,表示收集到10V,当AD当数字为256时,表示已收集到10V*=0.0391V,此ADC的分辨率是 。ADC位数越高,分辨率越高。 (3)基准电压 基准电压也称为参考电压(VREF),它被用作参考功能。当我们测试外部电压时,我们将以基准电压作为参考,首先将基准电压分成多少点(根据分辨率),然后与测量电压进行比较,然后得到比较结果,以测试输入电压。 22.1.1 ADC特性 STM32MP157系列有2个ADC(ADC1和ADC2),每个ADC每个人都可以独立工作ADC可单独分配A7或者M4使用内核。ADC1和ADC除独立立模式下工作外,还可在双重模式下工作(提高采样率,ADC1为主机),STM32MP157的ADC我们可以总结以下几个主要特点: (1)可配置16位、14位、12位、10位或8位分辨率,可降低分辨率缩短转换时间。 (2)每个ADC多达20个采集模拟通道,包括6个快速通道和14个慢速通道。慢速和快速的区别主要是支持的最高采样率不同,慢速通道低于快速通道。这些通道A/D转换可以单次、连续、扫描或间歇执行。 (3)ADC结果可以左对齐或右对齐存储在32位数据寄存器中。 (4)ADC内部参考电压有6条专用内部通道 (VREFINT ) 、内部温度传感器 (VSENSE )、VBAT 监测通道 (VBAT /4),连接到DAC内部通道、VDDCORE监视通道。 (5)支持采样,最高采样率可达26位。 (6)每个ADC支持3路模拟看门狗。 (7)支持单独输入和差分输入。 (8)ADC输入范围:VREF– ≤ VIN ≤ VREF 。由VREF- 、VREF 、VDDA 和VSSA 这四个外引脚决定。一般我们把VSSA 和VREF- 接地,把 VREF 和VDDA接到3.3V,所以得到ADC 输入电压范围为:0~3.3V。注意不要连接超出此范围的电压,否则芯片很容易烧坏。 我们上面列出的一些特征是ADC重要特点和关键知识点。以下是介绍ADC(仅限ADC1或ADC2)的框图: 22.1.2 ADC 框图
图22.1.2. 1 ADC框图 在进行框图分析之前,我们首先解释框图中的一些信号:
表22.1.2. 1 ADC内部输入/输出信号
在图中,我们标记了11个位置,说明如下:
- VREF 电压 ① 是VREF 电压 VREF 选择范围为1.62V3.6V,我们通常在开发板上给它VREF 接入电压时3.3V,因此得到开发板ADC测量范围是03.3V。此外,STM32MP157有ADC和DAC共用内部基准电压VREFBUF,可通过VREFBUF_CSR配置寄存器,可选1.5 V、1.8 V、2.048 V和2.5 V。
图22.1.2. 部分数据手册截图 2. ADC双时钟域架构 ② 是ADC双时钟域架构 双时钟域架构意味着ADC时钟独立于AHB总线时钟, ADC有两种时钟源可供选择,即adc_hclk和adc_ker_ck。
图22.1.2.1. 1 ADC1和ADC2时钟 (1)adc_hclk(属于同步时钟) adc_hclk来自AHB总线系统时钟,ADC1和ADC2处在209MHZ的 AHB2总线时钟。ADC_CCR寄存器的CKMODE[1:0]选择不同频率的位置AHB2总线时钟。 有四种情况: 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(同步时钟模式) 例如,我们选择1分频adc_hclk,频率为209MHZ,但参考手册上的限制ADC最高是 133MHz,说明配置超频是不可行的,因为超频误差会比较大。我们可以减少AHB2总线时钟,但这可能会影响我们其他外设的性能,所以我们可以选择其他配置来优化整个芯片的性能。 (2)adc_ker_ck(属于异步时钟) adc_ker_ck可以通过RCC_ADCCKSELR寄存器的ADCSRC[1:0]选择不同的时钟源,前提是前面提到的CKMODE[1:0]=00.选择如下: ADCSRC[1:0]=00,pll4_r_ck作为ADC时钟源(复位后的默认值) ADCSRC[1:0]=01,per_ck作为ADC时钟源 ADCSRC[1:0]=10,pll3_q_ck作为ADC时钟源 例如,我们可以选择per_ck作为ADC时钟源,而per_ck 时钟可为 hse_ck、hsi_ker_ck 或 csi_ker_ck,通过RCC_CPERCKSELR寄存器的CKPERSRC[1:0]位置选择,默认选择hsi_ker_ck作为per_ck的时钟源,hsi_ker_ck时钟源来自64频率MHz的高速内部RC振荡器(HSI)。也可以选择pll4_r_ck或者pll3_q_ck作为per_ck 时钟,最大可以配置为133MHz。
图22.1.2.1. 2 PER时钟 如果选择了adc_ker_ck时钟源作为ADC时钟,可以通过ADC_CCR寄存器的PRESC分频位置[3:0]是1、2、4、6、8、10、12、16、32、64、128、256这12种分频系数。上面的分析请结合下面的ADC时钟方案图理解。
图22.1.2.1. 3 ADC时钟方案 3. ADC的输入通道 ③是输入通道 在讲解STM32MP157的ADC输入通道前,我们先了解单端输入和差分输入。
图22.1.2.1. 4 ADC的单端输入和差分输入 (1)单端输入 单端输入只有一个输入引脚ADCin,同时使用公共地GND作为电路的返回端,ADC的采样值:VADC=VADCin -VGND。这种输入方式接线简单,ADC的采样值由Vin决定,且随着Vin受到的干扰而变化。 (2)差分输入 差分输入比单端输入多了一根线,ADC采样值: VADC =VADCin±VADCin-。这种输入方式接线稍微复杂,不过两根线受到的干扰差不多,属于输入共模干扰,在输入ADC时,这些干扰会被互相抵消掉,从而降低了干扰,所以测量精度是比较高的。 (3)STM32MP157的通道资源 STM32MP157的每个ADC最多有20个多路复用模拟通道。因为STM32MP157的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 ,所以ADCx_INN[19:0]不能选择作为单端输入。内部电压信号可以连接到ADC_INP的某个通道上面进行采集,如:内部参考电压 (VREFINT ) 连接到ADC2_INP13、内部温度传感器 (VSENSE ) 连接到ADC2_INP12、VBAT 监测通道 (VBAT/4) 连接到ADC2_INP15等。 注意:STM32MP157的ADC支持单端/差分转换,由寄存器ADC_DIFSEL控制,我们一般使用单端转换模式,默认这个寄存器都是0的,刚好就是单端转换模式。 4. ADC的转换序列 ④是转换序列 (1)常规通道组和注入通道组 在ADC的20个多路复用模拟通道中,可以分为规则通道组(也可以称为常规通道组)和注入通道组。规则通道组最多可以安排16个通道,注入通道组最多可以安排4个通道。规则通道组的通道可以称为规则通道(或常规通道,字面上一个意思),注入通道组的通道可以称为注入通道。规则通道可以理解为常规的通道,相当于正常运行的程序,我们一般使用的是规则通道,而注入通道可以以抢占式的方式打断规则通道的采样,也就是说注入通道相当于中断,当规则通道在执行任务时,可以插入注入通道(中断发生),规则通道先暂停处理任务而去处理注入通道的任务(中断响应),当注入通道处理完以后再返回去继续执行规则通道的任务(中断返回),这个过程就相当于中断的过程了。 (2)转换序列 ADC的作用就是将模拟量转换成数字量,可以将转换分为两组:规则转换和注入转换。每个组包含一个转换序列,该序列的作用就是控制通道的转换顺序。比如20个通道中有16个规则通道和4个注入通道,规则通道有116个转换序列,注入通道有14个转换序列,寄存器ADC_SQR1、ADC_SQR2、ADC_SQR3和ADC_SQR4控制着规则转换顺序,寄存器ADC_JSQR控制着注入转换。我们以规则转换为例,以一个寄存器来说明,例如,ADCx_SQR1寄存器的SQ1[4:0] 控制着规则序列中的第1个转换,SQ4[4:0]控制着规则序列的第4个转换,如果通道8想在第3个转换,则在SQ3[4:0]写入8即可,其它的寄存器也类似。
表22.1.2.4. 1 转换序列 一个常规转换组最多由16个转换构成。一个注入转换组最多由4个转换构成。常规转换必须在ADC_SQRy(y为1~4)寄存器中选择转换序列的常规通道及其顺序,转换总数必须写入ADC_SQR1寄存器中的L[3:0]位。注入转换必须在ADC_JSQR寄存器中选择转换序列的注入通道及其顺序,转换总数必须写入ADC_JSQR寄存器中的 JL[1:0] 位。 注入通道的转换可以打断常规通道的转换, 在注入通道被转换完成之后,常规通道才得以继续转换。 5. ADC的触发源 ⑤是触发源 经过前面的③和④步骤以后,选择好了通道以及转换顺序,接下来就开始进行转换操作了,转换需要触发才可以进行转换,ADC的触发转换有两种方法:分别是通过软件或外部事件(也就是硬件)触发转换。 (1)软件触发 我们先来看看通过软件触发转换的方法,方法是:通过写ADC_CR寄存器的ADSTART这个位来控制,写1就开始转换,写0就停止转换,这个控制ADC转换的方式非常简单。 (2)硬件触发 另一种就是通过外部事件触发转换的方法。有定时器和输入引脚触发等等,具体请看《STM32MP157参考手册》的表187和表188,如下表列出部分,可分为:常规通道的外部触发和注入通道的外部触发两种。 ADC1 和ADC2常规通道的外部触发部分
adc_ext_trg[20:0],对应的就是常规通道的外部触发,共有21路。 adc_jext_trg[20:0],对应的就是注入通道的外部触发,共有21路。 如果选择硬件触发,则需要选择相应的硬件触发通道和触发边沿等,然后由外部硬件通道来触发ADC的采集(注意:ADSTART位同样要设置为1)。硬件触发通道由ADC_CFGR寄存器的EXTSEL[4:0]和ADC_JSQR寄存器的 JEXTSEL[4:0]位来选择,分别是常规转换组和注入转换组的触发源选择。而触发边沿是通过ADC_CFGR寄存器的EXTEN[1:0]和ADC_JSQR寄存器的JEXTEN[1:0]位来选择。其他的设置我们后面再讲解。 6. ADC的转换时间 ⑥是转换时间 (1)计算转换时间 STM32MP157的ADC总转换时间的计算公式如下: TCONV = 采样时间(TSMPL) + 逐次逼近时间(TSAR) 采样时间(TSMPL)可通过ADC_SMPR1和ADC_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)是由分辨率决定的,分辨率通过对ADC_CFGR寄存器的RES[1:0]位进行编程,可将分辨率配置为16位、14位、12位、10位、8位。而逐次逼近时间和分辨率的对应关系如下表所示:
表22.1.2.6. 1 TSAR与分辨率的对应关系 举个例子,我们配置SMP = 111,即设置最大采样周期,然后采用16位分辨率,那么得到: TCONV = 810.5个ADC时钟周期 + 8.5个ADC时钟周期 = 819个ADC时钟周期 表格中,Fadc_ker_ck的频率是24MHZ,我们的例程中ADC的时钟源如果是64MHZ的hsi_ker_ck经过2分频得到,即32MHZ。我们就以Fadc_ker_ck的频率为32MHZ来举例,可得到: TCONV = 819个ADC时钟周期 = = 25.6us (2)计算采样率 得到转换时间,我们就可以计算出采样率: 采样率=1/采样时间 在数据手册中有给出采样率:
图22.1.2. 3ADC的采样率列表 我们以表中第一个参数为例进行计算,ADC的时钟频率是36MHz,采样时间是1.5个ADC时钟周期,所以采样时间TCONV =(1.5+8.5)/36MHz,那么采样率fs =36MHz/10=3.60MSPS,和表中的3.6一致。 7. 其它 ⑦是选择参考电压 选择参考电压,我们可以设置参考电压来自外部的VREF+,也可以设置参考电压来自内部的稳压器。 ⑧ADC的核心 ADC的核心是一个16位的逐次逼近型ADC转换器,它根据我们设置好的参考电压、输入通道、启动条件等,执行模数转换。 ⑨数据寄存器 这是ADC转换完成后的数据输出寄存器。其中RDATA[31:0]用于保存常规通道的转换结果,JDATA1~4[31:0]用于保存注入通道的转换结果,如果是使用双重模式,常规通道的数据则是存放在ADC_CDR寄存器。转换结果CPU可以通过AHB总线读取,同时也可以产生相关中断(adc_it)。 ⑩中断 对于每个ADC都可在下列情况下产生中断:
表22.1.2.7. 1每个ADC的ADC中断 表中前面5个中断都很好理解,我们从模拟看门狗中断介绍。 模拟看门狗中断发生条件:首先通过ADC_LTR和ADC_HTR寄存器设置低阈值和高阈值,然后开启了模拟看门狗中断后,当被ADC转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断。例如我们设置高阈值是3.0V,那么模拟电压超过3.0V的时候,就会产生模拟看门狗中断,低阈值的情况类似。 上溢中断:如果发生传输数据丢失,会置位ADC状态寄存器ADC_ISR的OVR位,如果同时使能了溢出中断ADC_IER寄存器的OVRIE位,就会在转换结束后会产生一个溢出中断。 此外,我们还要知道常规组和注入组的转换结束后,除了产生中断外,还可以产生DMA请求,把转换好的数据存储在内存里面,防止读取不及时数据被覆盖。 ⑪通道预选控制信号 通道预选控制信号,用于将ADC某个通道连接到对应的GPIO上。PCSEL[19:0]每个位对应一个通道,总共20个通道。这一点和以前的STM32系列不一样,在使用的时候,需要特别注意。 22.2 单通道ADC采集实验 本实验配置好的实验工程已经放到了开发板光盘中,路径为:开发板光盘A-基础资料\1、程序源码\11、M4 CubeIDE裸机驱动例程\CubeIDE_project\ 15-1 ADC1_SINGLE_CH。 STM32MP157的ADC可以进行很多种不同的转换模式,这些模式在《STM32MP157参考手册》的第29章也都有详细介绍。ADC有独立模式和双ADC模式,独立模式一般是指常规通道,独立模式中又会有:单通道、单次转换模式、多通道(扫描)、单次转换模式、单通道连续转换模式、多通道(扫描)连续转换模式和注入转换模式。双ADC模式会稍微复杂,我们这里先介绍独立模式。 22.2.1 单次转换和连续转换 ADC的转换模式中,主要需要了解单次转换模式和连续转换模式。
- 单次转换模式 将ADC_CFGR 寄存器的位CONT=0后则设置为单次转换模式,启动ADC后,转换一次完成后则停止,然后等待下一次的ADC启动后再继续进行下一次的转换,这里的通道数可以是一个也可以是多个,但是只采集一次。 转换序列的作用就是控制通道的转换顺序,如果设置了几个通道的转换顺序,当转换完设置的所有通道后,我们就说转换序列完成,只有一个通道的话,可将序列长度编程为1。 (1)对于常规通道: 在常规序列中,一旦选择的通道转换完成,转换数据被储存在16位ADC_DR寄存器中,ADC状态寄存器(ADC_ISR) 的EOC(转换结束)标志被置1,如果设置了EOCIE,则产生中断,然后ADC停止。 如果常规序列完成后,EOS(常规序列结束)标志置 1,EOSIE 位置 1 时将产生中断。 (2)对于注入通道: 在注入序列中,每次转换完成后,转换数据被储存在16位的ADC_DRJ1寄存器中,ADC状态寄存器(ADC_ISR) 的JEOC(注入转换结束)标志被置1,如果设置了JEOCIE位,则产生中断,然后ADC停止。如果注入序列完成后,JEOS(注入序列结束)标志置 1,JEOSIE 位置 1 时将产生中断。
- 连续转换模式 将ADC_CFGR 寄存器的位CONT=1后,则设置为连续转换模式,连续转换模式只适用于常规通道。启动ADC后则开始转换,转换完所设置的所有通道后,返回到第一步再继续重新转换所有的通道,即转换完一次后继续开始下一次转换,转换数据存储在 32位 ADC_DR 寄存器中。 在常规序列中,每次转换完成后,EOC(转换结束)会被置1,如果EOCIE 位被设置为1 时将产生中断;如果转换序列完成后,EOS(序列结束)标志置 1,EOSIE 位置 1 时将产生中断。
- 独立模式 (1)单通道、单次转换模式 这是最简单的ADC模式,在此模式下,ADC 执行单个通道x的单次转换(单次采样),并在转换完成后停止:
图22.2. 1单通道、单次转换模式 (2)多通道(扫描)、单次转换模式 扫描模式一般用于顺序转换多个通道,是针对多通道ADC而言的,单个通道没有扫描模式。多通道(扫描)、单次转换模式用于在独立模式下对一些通道进行依次转换,可以在此模式下以不同的采样时间和采样顺序对任意序列的通道(最多 16 个)依次进行配置。通过这种方式,用户不必在转换过程中停止ADC即可以不同的采样时间重新配置下一个通道。此模式可以避免额外的 CPU 负载以及繁重的软件开发。例如,在机械臂的系统中,必须在上电时读取机械臂系统中每个关节的位置才能确定机械臂顶端的坐标,那么可配置用到的通道,例如下图配置11个通道:
图22.2. 2以不同采样时间转换11个通道 所配置的通道可按设置好的次序进行转换:
图22.2. 3多通道、单次转换 (3)单通道连续转换模式 对单个通道进行连续不断的转换,即转换完一次后继续开始下一次转换,这种模式叫做单通道连续转换模式。连续转换模式也可以使用DMA,从而降低 CPU 负载。
图22.2. 4单通道多次转换 本实验我们来学习使用常规单通道的单次转换模式。 STM32MP157的ADC在单次转换模式下(寄存器ADC_CFGR的CONT位为0),只执行一次转换,该模式可以通过ADC_CR寄存器的ADSTART位(只适用于常规通道)启动,也可以通过外部触发启动(适用于常规通道和注入通道,但是必须先设置ADSTART/JADSTART位)。 以常规通道为例,一旦所选择的通道转换完成,转换结果将被存在ADC_DR寄存器中,EOC(转换结束)标志将被置位,如果设置了EOCIE,则会产生中断。然后ADC将停止,直到下次启动。 22.2.2 ADC寄存器 下面,我们介绍执行常规通道的单次转换,需要用到的一些ADC寄存器。
- ADC通用控制寄存器(ADC_CCR) ADC通用控制寄存器描述如下图所示:
图22.2.1. 1 ADC_CCR寄存器 该寄存器本章只需要用到PRESC[3:0]这四个位,用于设置ADC时钟的预分频系数(即对adc_ker_ck的分频系数),表示2^PRESC[3:0]分频: 0000:输入 ADC 时钟未分频 0001:输入 ADC 时钟 2 分频 0010:输入 ADC 时钟 4 分频 0011:输入 ADC 时钟 6 分频 0100:输入 ADC 时钟 8 分频 0101:输入 ADC 时钟 10 分频 0110:输入 ADC 时钟 12 分频 0111:输入 ADC 时钟 16 分频 1000:输入 ADC 时钟 32 分频 1001:输入 ADC 时钟 64 分频 1010:输入 ADC 时钟 128 分频 1011:输入 ADC 时钟 256 分频 其它:保留 adc_ker_ck的时钟来自RCC_ADCCKSELR寄存器的ADCSRC[1:0]位的选择,我们一般设置ADCSRC[1:0]=0x01,即选择per_ck作为时钟源,而per_ck又由RCC_CPERCKSELR寄存器的CKPERSRC[1:0]位选择,默认为0,即选择hsi_ker_ck(64Mhz)作为per_ck。因此: adc_ker_ck=per_ck=hsi_ker_ck=64Mhz。 注意ADC的输入时钟频率不能大于133MHz。可以根据需要设置ADC时钟的预分频系数,例如设置PRESC[3:0]=1,即可得到ADC转换时钟频率为:adc_ker_ck/2^PRESC[3:0]=64/2=32MHz。 2. ADC控制寄存器(ADC_CR) ADC控制寄存器描述如下图所示:
图22.2.1. 2 ADC_CR寄存器 该寄存器我们用到多个位,这里就不全部列出来讲解了,而是抽出几个重要的位进行针对性的介绍,详细的介绍,请参考参考手册。 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。如果设置的32MHz的ADC转换时钟,因此该位必须设置为1。 ADCALLIN位,用于设置线性ADC校准。设置该位为1,可以设置ADC的校准模式为线性校准。 ADCAL位,用于控制/读取ADC校准状态。设置该位为1时,可以启动ADC校准,等校准完成以后,硬件会自动清零该位。因此在设置改位为1以后,通过判断该位是否变为0,即可判断校准是否完成。 3. ADC配置寄存器(ADC_CFGR) ADC配置寄存器描述如图所示:
图22.2.1. 3 ADCx_CFGR寄存器 RES[2:0]位,用于设置ADC转换的分辨率:0,16位;1,14位;2,12位;3,10位;4,8位;其他值:保留。本章我们使用16位分辨率,因此设置这3个位全0即可。 EXTEN[1:0]位,用于设置常规通道的外部触发方式和极性。本章我们使用软件触发,因此设置EXTEN[1:0]=00,即禁止外部触发即可。 OVRMOD位,用于设置是否使能覆写功能。当设置该位为0时,如果上一次转换的数据未及时读取,新的转换结果将被丢弃;当设置该位为1时,如果上一次转换的数据未及时读取,将会被新的结果覆盖。本章,我们设置该位为1。 CONT位,用于设置转换模式。当CONT=0时,表示单次转换模式;当CONT=1时,表示连续转换模式。本章,我们设置该位为0。 4. ADC配置寄存器2(ADC_CFGR2) ADC配置寄存器2描述如图所示:
图22.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即可。 5. ADC常规序列寄存器1(ADC_SQR1) ADC常规序列寄存器描述如下图所示:
图22.2.1. 5 ADC_SQR1寄存器 L[3:0]:用于存储常规序列的长度,取值范围:015,表示常规序列长度为:116。我们这里只用了1个通道,所以设置这几个位的值为0即可。 SQ1SQ4表示常规序列中的第14个序列的转换通(019),每个常规序列的转换通道,可以由SQx(x=116)指定,比如我们设置:SQ1[4:0]=19,就表示常规序列1的转换通道为19(ADC1/2/3_CH19)。SQ5SQ16由寄存器ADC_SQR24控制。 6. ADC采样时间寄存器2(ADC_SMPR2) ADC采样时间寄存器2描述如下图所示:
图22.2.1. 6 ADC_SMPR2寄存器 该寄存器用于设置ADC通道1019的采样时间,而ADC_SMPR1设置ADC通道09的采样时间。STM32MP157的ADC总转换时间的计算方法前面已经介绍过了,采样时间周期越长,精度就越高,所以这里我们设置为最大采样时间。采样时间我们建议尽量长一点,以获得较高的准确度,但是这样会降低ADC的转换速率,所以大家在实际应用中自行结合自身情况设置。 7. ADCx通道预选寄存器(ADC_ PCSEL) ADC通道预选寄存器描述如下图所示:
图22.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兼容。 8. ADC常规数据寄存器(ADC_ DR) ADC常规数据寄存器描述如下图所示:
图22.2.1. 8 ADC_ DR寄存器 常规序列中的AD转化结果都将被存在这个寄存器里面,我们通过读取该寄存器,即可得到ADC转换后的结果,而注入通道的转换结果被保存在ADC_JDRy(y=1~4)里面,所以读取ADC_JDRy这个寄存器的就可以读取注入通道的ADC的转换值。 9. ADC中断和状态寄存器(ADC_ ISR) ADC中断和状态寄存器描述如下图所示:
图22.2.1. 9 ADC_ ISR寄存器 ADC_ ISR寄存器的位我们只介绍常用的几位: EOS位是常规序列结束标志位,常规通道序列转换结束后,硬件将该位置 1,通过软件写入 1 可将该位清零。 OVR是ADC 溢出位,该位在常规通道上发生溢出事件时由硬件置 1,这意味着在 EOC 标志已置 1 时,新转换已完成,通过软件写入 1 可将该位清零。 EOC位是转换结束标志,当通道的每次常规转换结束,新数据出现在 ADC_DR 寄存器时,会通过硬件将该位置 1通过软件向该位写入1,或读取 ADC_DR 寄存器都可将该位清零。 这里我们仅介绍将要用到的是EOC位,我们可以通过判断该位来决定是否此次规则通道的AD转换已经完成,如果该位位1,则表示转换完成了,就可以从ADC_DR中读取转换结果,否则等待转换完成。 至此,本章要用到的ADC相关寄存器全部介绍完毕了,对于未介绍的部分,请大家参考《STM32MP157参考手册》第29章相关内容。 22.2.3 ADC的HAL库驱动 ADC在HAL库中的驱动代码在stm32mp1xx_hal_adc.c和stm32mp1xx_hal_adc_ex.c文件(及其头文件)中。
- 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注入通道配置结构,用于配置注入通道的转换顺序,数据格式等 */
ADC_InjectionConfigTypeDef InjectionConfig ;
}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; /* 设置转换通道数目 */
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;
- ClockPrescaler:ADC预分频系数选择,可选的分频系数为 1、2、4、6、8、10、12、16、32、64、128、256。ADC最大时钟配置为36MHZ。
- Resolution:配置ADC的分辨率,可选的分辨率有16 位、12 位、10 位和 8 位。分辨率越高,转换数据精度越高,转换时间也越长;反之分辨率越低,转换数据精度越低,转换时间也越短。
- ScanConvMode:配置是否使用扫描。如果是单通道转换使用ADC_SCAN_DISABLE,如果是多通道转换使用ADC_SCAN_ENABLE。
- EOCSelection:可选参数为ADC_EOC_SINGLE_CONV和ADC_EOC_SEQ_CONV,指定转换结束时是否产生EOS中断或事件标志。
- LowPowerAutoWait:配置是否使用低功耗自动延迟等待模式,可选参数为 ENABLE和 DISABLE,当使能时,仅当一组内所有之前的数据已处理完毕时,才开始新的转换,适用于低频应用。该模式仅用于ADC的轮询模式,不可用于DMA以及中断。
- ContinuousConvMode:可选参数为ENABLE和DISABLE,配置自动连续转换还是单次转换。使用ENABLE配置为使能自动连续转换;使用DISABLE配置为单次转换,转换一次后停止需要手动控制才重新启动转换。
- NbrOfConversion:设置常规转换通道数目,范围是:1~16。
- DiscontinuousConvMode:配置是否使用不连续的采样模式,比如要转换的通道有1、2、5、7、8、9,那么第一次触发会进行通道 1 与通道 2,下次触发就是转换通道 5 与通道 7,这样不连续的转换,依次类推。此参数只有将 ScanConvMode 使能,还有ContinuousConvMode失能的情况下才有效,不可同时使能。
- NbrOfDiscConversion:不连续采样通道数。
- ExternalTrigConv:外部触发方式的选择,如果使用软件触发,那么外部触发会关闭。
- ExternalTrigConvEdge:外部触发极性选择,如果使用外部触发,可以选择触发的极性,可选有禁止触发检测、上升沿触发检测、下降沿触发检测以及上升沿和下降沿均可触发检测。
- ConversionDataManagement: 指定ADC转换后的数据处理方式。可以选择 DMA管理传输数据、数据存储在数据寄存器中或者是传输到DFSDM寄存器中。
- Overrun:当有新的数据溢出时,可以选择覆盖写入或者是丢弃新的数据。
- LeftBitShift:数据左移位数,最多可支持左移15位。
- OversamplingMode:是否使用过采样模式。
- Oversampling:配置过采样模式的参数。 函数返回值: HAL_StatusTypeDef枚举类型的值。
- 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枚举类型的值。
- 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;
- Channel:ADC转换通道,范围:0~19。
- Rank:在常规转换中的常规组的转换顺序,可以选择1~16。
- SamplingTime:ADC的采样周期,最大810.5个ADC时钟周期,要求尽量大以减少误差。
- SingleDiff:选择通道单端输入还是差分输入。
- OffsetNumber:选择使用偏移量的通道。
- Offset:定义要从原始数据减去的偏移量。根据ADC的分辨率不同,支持的最大偏移量也不同,例如分辨率是16bit,,最大的偏移量为0xFFFF。
- OffsetRightShift:采样值进行右移的位数。
- OffsetSignedSaturation:是否使能ADC采样值的最高位为符号位。 函数返回值: HAL_StatusTypeDef枚举类型的值。
- HAL_ADC_Start函数 函数描述: 当配置好ADC的基础的功能后,就调用此函数启动ADC。 函数形参: 形参1是ADC_HandleTypeDef结构体类型指针变量。 函数返回值: HAL_StatusTypeDef枚举类型的值。 ADC转换启动函数,其声明如下: HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc);
- HAL_ADC_Stop函数 函数描述: 停止ADC的转换(常规模式下停止常规组的ADC转换,注入模式下停止注入通道),禁用ADC外设。注意的是,ADC外设禁用正在强制停止注入组的电位转换。 如果正在使用注入组,则应使用HAL_ADCEx_InjectedStop函数预先将其停止。 函数形参: 形参1是ADC_HandleTypeDef结构体类型指针变量。 函数返回值: HAL_StatusTypeDef枚举类型的值。 HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
- 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枚举类型的值。
- HAL_ADC_GetValue函数 获取常规组ADC转换值函数,其声明如下: uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef *hadc); 函数描述: 一般先调用HAL_ADC_Start函数启动转换,再调用HAL_ADC_PollForConversion函数等待转换完成,然后再调用HAL_ADC_GetValue函数来获取当前的转换值。 函数形参: 形参1是ADC_HandleTypeDef结构体类型指针变量。 函数返回值: 当前的转换值,uint32_t类型数据。 22.2.4 硬件设计
- 例程功能 使用ADC1采集通道19(PA5)上面的电压,然后通过串口UART4打印ADC转换值以及换算成电压后的电压值。同时程序中通过LED0闪烁来指示程序在运行状态。 开发板上有引出PA5引脚,先使用跳线帽将JP2排针的ADC1和电位器的RP_AD连接,这样PA5就连接到电位器VR1上了,电位器上接的是3.3V,用户可以通过调节电位器的旋钮改变接入到PA5上的电压值为0~3.3V(实际上就是通过改变电阻来改变电压)。实验前要记住检查跳线帽是否有接好:
图22.2.3. 1硬件部分 开发板上有1 组 3.3V 电源供应接口JP7,JP7排针有3路输出3.3V,另外3路接地(0V),我们也可以使用这个排针来测试,接入到被测通道中。注意的是,千万不要接错旁边的JP8排针引出的5V引脚,否则烧坏IO口甚至整个主控芯片。
图22.2.3. 2开发板的电源输出接口 2. 硬件资源 1)LED灯:LED0 2)串口4 3)ADC1的通道19引脚(PA5) LED0 UART4_TX UART4_RX ADC1_INP19 PI0 PG11 PB2 PA5 表22.2.3. 1硬件资源 3. 原理图 ADC属于STM32MP157的内部资源,实际上我们只需要软件设置就可以正常工作,不过我们需要在外部将ADC1的通道19引脚(PA5)连接到被测电压点上面,本实验的被测电压是来自开发板自带的电位器上的电压,电位器可调节的电压范围是:0~3.3V。当然也可以使用ADC1测试其它外接入的电压,只需要一根杜邦线将要测试的电压引入PA5引脚即可,要注意接入的电压范围不能超过3.3V,否则可能烧坏我们的ADC,甚至是整个主控芯片。
图22.2.3. 3原理图部分 22.2.5 软件设计 本实验配置好的实验工程已经放到了开发板光盘中,路径为:开发板光盘A-基础资料\1、程序源码\11、M4 CubeIDE裸机驱动例程\CubeIDE_project\ ADC1_SINGLE_CH。
- 新建和配置工程 (1)引脚配置 新建工程ADC1_SINGLE_CH,然后配置LED0、UART4,这两个配置方法我们前面实验多次介绍了,这里就不再赘述,这里UART4使用中断,UART4的配置请参考前面串口通信实验章节。 接下来配置ADC1引脚,本实验我们使用的是ADC1的单端输入功能,在Pinout view处选择PA5引脚并配置为ADC1_INP19,我们前面说过,ADC_INP[19:0]可以做单端输入,这里选择通道19。配置ADC的通道的话,也可以直接在AnalogADC1处配置ADC,选择对应的通道以后,Pinout view处也会自动配置好,可以参考后面的(2)配置ADC参数。
图22.2.4. 1配置PA5引脚 (2)配置ADC参数 在AnalogADC1处配置ADC。先选择ADC1给M4内核使用,如下所示,有IN0~IN19,表示19个通道,ADC1的通道0、6、7、8、9、13、14、15、17、19只能配置为单端模式,而其余通道可以配置为单端或者差分模式,本实验用到ADC1的通道19的单端输入,所以勾选IN19 Single-ended,我们没有使用硬件触发,使用的是软件触发,所以EXTI Conversion Trigger选项要Disable:
图22.2.4. 2 ADC1模式配置 接下来配置ADC1的初始化参数,如下:
图22.2.4. 3 ADC初始化参数配置 对以上的ADC参数配置选项进行介绍: ●ADCs_Common_Settings(ADC工作模式配置): 这里配置为独立模式,独立模式是指在同一个管脚上只有一个ADC采集该管脚的电压信号。如果只是用了一个ADC的时候就配置为独立模式。 除了独立模式,还有双重模式以及三重模式等多重模式,多重模式是指双ADC共同工作,如果需要两个ADC同步的话,则使用此模式。 ●ADC_Settings(ADC参数设置) Clock Prescaler用于配置时钟分频,这里选择2分频; Resolution用于配置ADC的分辨率,这里选择16位; Scan Conversion Mode用于配置扫描模式,当有多个通道需要采集信号时必须开启扫描模式,此时ADC将会按设定的顺序轮流采集各通道信号,单通道转换不需要使用此功能,这里选择Dsabled; Continuous Conversion Mode用于配置自动连续转换还是单次转换。使用Enable配置为使能自动连续转换;使用Disabled配置为单次转换,转换一次后停止需要手动控制才重新启动转换,我们选择Disabled; Disabled Discontinuous Conversion Mode用于配置是否使用不连续的转换模式,所谓不连续,比如要转换的通道有1、2、5、7、8、9,那么第一次触发会进行通道 1 与通道 2,下次触发就是转换通道 5 与通道 7,这样不连续的转换,依次类推。这里我们选择禁用不连续的转换模式Disabled; End Of Conversion Selection用于配置转换方式结束选择,可选择单通道转换完成后EOC标志位置位或者所有通道转换成后EOC置位,也可以选择转换序列结束后EOS置位(配置为End of sequence of conversion),这里配置End of single conversion,即单通道转换完成后EOC置位; Overrun behaviour用于配置有新的数据溢出时,是覆盖写入还是丢弃新的数据,我们选择覆盖写入新的数据; Conversion Data Management Mode用于配置转换数据管理模式,我们选择Regular Conversion data stored in DR register only,即将常规转换的数据存储在DR寄存器中,另外还有DMA相关以及DFSDM,这两个本实验我们不使用; Low Power Auto Wait配置是否使用低功耗自动延迟等待模式,当使能时,仅当一组内所有之前的数据已处理完毕时,才开始新的转换,适用于低频应用,该模式仅用于ADC的轮询模式,不可用于DMA以及中断,这里我们选择关闭。 ●ADC Regular_ConversionMode(ADC常规通道转换模式) Enable Regular Conversions选择Enable,启用常规转换; Left Bit Shit 数据左移位数,最多可支持左移15位,这里选择没有位转移No bit shit; Enable Regular Oversampling用于配置是否使用常规通道过采样,这里不使用此功能; Number Of Conversion转换通道数量,此参数会影响可供设置的通道数,按实际使用的通道数来选择即可,这里是1; External Trigger Conversion Source外部触发转换模式配置,ADC在接收到到触发信号后才开始进行模数转换,触发源可以是定时器触发、外部中断触发等硬件触发、也可以是软件控制触发,这里选择软件触发,工程中需要我们添加启动ADC的代码; External Trigger Conversion Edge配置触发边沿,这里选择无触发边沿; Rank配置模拟信号采集及转换的次序,默认是1,其中: Channel用于选择转换的通道,这里选择通道19; Sampling Time采样周期选择 810.5Cycles; Offset Number配置偏移量的通道选择,这里选择无偏移通道; ●ADC_Injected_ConversionMode(ADC注入通道转换模式) Enable Injected Conversions用于配置注入通道转换模式,实验中我们不需要使用注入通道,所以此项配为Disable。 后面的是模拟量看门狗的设置,本实验我们不需要,不配置即可。 (3)UART相关的参数配置 UART4的参数配置以及中断配置请参考前面串口通信实验 (4)时钟配置 这里配置MCU的时钟为209MHz,使用外部时钟HSE,这部分配置可以参考前面实验章节:
图22.2.4. 4时钟树配置 ADC1的时钟使用PER,其中PER时钟源默认使用HSI,即为64MHz。上面ADC参数配置中,我们配置分频系数为2,所以实际ADC的时钟是32MHz。
图22.2.4. 5ADC时钟源选择 (5)配置生成独立的.c和.h文件
图22.2.4. 6配置生成独立的文件 2. 生成工程 如下生成工程,本实验中使用到LED0,所以将前面实验使用的BSP文件夹拷贝到Src目录下:
图22.2.4. 7生成工程 4. 初始化代码分析 ADC的初始化代码均在adc.h和adc.c文件中,其代码如下,代码中已经附上了详细的注释:
1 #include "adc.h"
2
3 ADC_HandleTypeDef hadc1; /* ADC句柄 */
4
5 /** 6 * @brief ADC初始化函数 7 * @note 本函数支持ADC1/ADC2任意通道 8 * 我们使用16位精度, ADC采样时钟=32M, 转换时间 9 * 为:采样周期 + 8.5个ADC周期 10 * 设置最大采样周期: 810.5, 则转换时间 = 819个ADC周期 = 25.6us 11 * @param 无 12 * @retval 无 13 */
14 void MX_ADC1_Init(void)
15 {
16 ADC_MultiModeTypeDef multimode = {
0};
17 ADC_ChannelConfTypeDef sConfig = {
0};
18
19 hadc1.Instance = ADC1; /* ADC1 */
20 /* 输入时钟2分频,即adc_ker_ck= PER/2=32MHz */
21 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
22 hadc1.Init.Resolution = ADC_RESOLUTION_16B; /* ADC分辨率为16位模式 */
23 hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;/* 非扫描模式 */
24 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /* 关闭EOC中断 */
25 hadc1.Init.LowPowerAutoWait = DISABLE; /* 自动低功耗关闭 */
26 hadc1.Init.ContinuousConvMode = DISABLE; /* 关闭连续转换 */
27 hadc1.Init.NbrOfConversion = 1; /* 使用了1个转换通道 */
28 hadc1.Init.DiscontinuousConvMode = DISABLE;/* 禁止不连续采样模式 */
29 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;/* 软件触发 */
30 /* 采用软件触发的话,此位忽略 */
31 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
32 /* 规则通道的数据仅仅保存在DR寄存器里面 */
33 hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
34 /* 有新的数据后直接覆盖掉旧数据 */
35 hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
36 hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;/* ADC无位移位 */
37 hadc1.Init.OversamplingMode = DISABLE; /* 过采样关闭 */
38 if (HAL_ADC_Init(&hadc1) != HAL_OK) /* 使用HAL库初始化ADC */
39 {
40 Error_Handler();
41 }
42 multimode.Mode = ADC_MODE_INDEPENDENT; /* 独立模式 */
43 /* 独立模式通道配置 */
44 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
45 {
46 Error_Handler();
47 }
48 sConfig.Channel = ADC_CHANNEL_19; /* ADC1的通道19 */
49 sConfig.Rank = ADC_REGULAR_RANK_1; /* 1个序列 */
50 /* 采样时间,最大采样周期: 810.5个ADC周期 */
51 sConfig.SamplingTime = ADC_SAMPLETIME_810CYCLES_5;
52 sConfig.SingleDiff = ADC_SINGLE_ENDED; /* 单边采集 */
53 sConfig.OffsetNumber = ADC_OFFSET_NONE; /* 不使用偏移量的通道 */
54 sConfig.Offset = 0; /* 偏移量为0 */
55 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)/* 通道配置 */
56 {
57 Error_Handler();
58 }
59 }
60 /** 61 * @brief ADC的GPIO初始化函数 62 * @param 无 63 * @retval 无 64 */
65 void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
66 {
67 GPIO_InitTypeDef GPIO_InitStruct = {
0};
68 RCC_PeriphCLKInitTypeDef PeriphClkInit = {
0};
69 if(adcHandle->Instance==ADC1)
70 {
71 if(IS_ENGINEERING_BOOT_MODE(