STM32学习笔记(13)——模数转换ADC

Posted Mount256

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32学习笔记(13)——模数转换ADC相关的知识,希望对你有一定的参考价值。

这个月一直忙于准备考试,已经考完一半科目了,偷闲写了这篇文章。因为还没考完试,估计还得咕一段时间了。

模拟量转换为数字量的过程称为A/D模数转换,完成这一转换过程的器件称为ADC(Analog-to-Digital Converter)。

在STM32中,有三个ADC:ADC1、ADC2、ADC3,其分辨率为12位,每个ADC通道具有18个通道,其中外部通道有16个。

第一部分:ADC功能框图

在这里插入图片描述

我们分为七个部分讲解:

一、输入电压

输入电压一般由参考电压VREF-VREF+VDDA(模拟电压源)VSSA(模拟地)提供,具体的输入电压范围为VREF- ≤ VIN ≤ VREF+

在一般的电路设计中,我们会将VSSAVREF-接地(GND),将VDDAVREF+接高电平(即3.3V),如下图电路原理图所示。因此,ADC的输入电压范围为0 ~ 3.3V

我们可以根据数字量来算出模拟量:首先 ADC 分辨率为12位,电压范围为 0~3.3V,则最小精度为 3.3 − 0 2 12 \\frac{3.3-0}{2^{12}} 2123.30,假设数字量为X,则最终模拟量 = 3.3 − 0 2 12 ⋅ X \\frac{3.3-0}{2^{12}}\\cdot X 2123.30X

在这里插入图片描述

当然,ADC可以测量范围为 0 ~ 3.3V 的电压,但如果超出这个范围的电压该如何测量呢?举一个简单的例子:如果我们想扩大测量范围至 -10 ~ +10V,可以将电路设计成如下:

在这里插入图片描述

根据KCL(基尔霍夫定律:节点流入电流之和等于流出电流之和)方程可得出:

V I N − V O U T R 2 + 3.3 V − V O U T R 1 = V O U T R 3 \\frac{VIN-VOUT}{R2}+\\frac{3.3V-VOUT}{R1}=\\frac{VOUT}{R3} R2VINVOUT+R13.3VVOUT=R3VOUT

已知 R1、R2 和 R3,就能根据这个方程得出 VIN 和 VOUT 的关系式。

二、输入通道

STM32 为三个 ADC 分配了 18 个通道,如下表所示:

在这里插入图片描述

这是 STM32F103ZET6 的通道引脚分配,不同型号的芯片有不同的分配。在这里,对于 ADC1 和 ADC2,通道16和17均为内部通道;对于 ADC3,通道9和通道14~17均为内部通道。注意有部分 IO 引脚被重复占用。

三、规则通道

STM32 的 ADC 输入通道分为两类:规则通道和注入通道。ADC 可以对一组指定的通道,按照既定的顺序,逐个转换这组通道,转换结束后,再从头循环。这些指定的通道组被称为规则通道组(规则组),组内的通道被称为规则转换通道(规则通道)。但在实际情况中,有可能需要临时中断规则组的转换,对某些通道进行转换,这些需要中断的规则组就称为注入通道组(注入组),组内的通道被称为注入转换通道(注入通道)

规则组最多可以设置 16 个通道。

我们可通过规则序列寄存器SQRx(x=1, 2, 3)来设置规则通道的优先顺序。规则序列寄存器一共有三个,除了寄存器SQR1的第23位至20位(SQL[3:0])用做配置转换通道的个数外,其他都是每 5 位一组配置第 n 个转换的通道。如下表所示:

在这里插入图片描述

例如,配置寄存器SQR1SQL[3:0]为3,表明有 3 个规则通道,则可在寄存器SQR3SQ1[4:0]SQ2[4:0]SQ3[4:0]中分别配置为11、5、7,表明通道5、7和11都是规则通道,而且转换顺序是先通道11、再通道5、最后通道7。

四、注入通道

注入通道和规则通道有所不同的是,注入通道与中断程序类似,在规则通道进行转换时“强行”插入进行转换。因此,注入也有插入的意思,插入和规则是相对的,注入通道只有在规则通道存在的时候才会出现。

我们可通过注入序列寄存器JQSR来设置注入通道的优先顺序。注入序列寄存器只有一个,第21和20位两位(JL[1:0])用来设置转换通道的个数,其余都是每 5 位一组配置第 n 个转换通道。如下表所示:

在这里插入图片描述

因为与规则通道序列寄存器类似,因此就不举例了。但要注意一点:寄存器JSQR和寄存器SQR的转换顺序是不一样的。JSQR的第 4 个转换通道其实是第一次进行转换的,第 3 个转换通道是第二次进行转换的,正好是反过来的,以此类推。

关于规则组和注入组的例子:系统需要采集温度,但又要适时监控湿度,那么湿度采集的转换通道可以放在注入组中,通过某种触发源启动转换。一旦启动注入通道转换,规则通道转换被暂停,然后等待注入通道转换完成后,规则组在进行转换。

五、触发源

1. 软件触发

是否启动 ADC 由寄存器ADC_CR2ADON位控制,写入1则表示打开或启动模拟至数字转换器的电压。

启动转换器后,由寄存器ADC_CR2SWSTART位和JSWSTART位分别控制规则通道的转换和注入通道的转换,写入1则表示转换使能允许。

2. 外部事件触发

寄存器ADC_CR2EXTSEL位和EXTTRIG位控制规则通道的触发源,触发源来自TIM1_CHx(x=1, 2, 3)TIM2_CH2TIM4_CH4TIM3_TRGOEXTSEL位用于选择使用哪个触发源,EXTTRIG位用于使能触发允许或禁止。

类似地,寄存器ADC_CR2JEXTSEL位和JEXTTRIG位控制注入通道的触发源,触发源来自TIM1_CH4TIM2_CH1TIM3_CH4TIM1_TRGOTIM2_TRGOTIM4_TRGOJEXTSEL位用于选择使用哪个触发源,JEXTTRIG位用于使能触发允许或禁止。

注意,以上描述的是 ADC1 和 ADC2 的触发源,ADC3 与前两者有区别,具体可参考手册内容。

GPIO 外部中断的 EXTI11 和 EXTI15 也可作为触发源。

六、转换时间

转换时间公式为:T(conv) = 采样时间 + 12.5个周期

转换速度由 ADC 模拟时钟(ADC_CLK)决定,其最大频率为 14MHz。 ADC_CLK 由 PCLK2 提供。之前在讲解时钟树的时候已经提及过,PCLK2 在经过 APB2 预分频器后最大频率可达到 72MHz。因为 ADC_CLK 规定最大频率为 14MHz,因此, 时钟信号经过 的 ADC 预分频器的分频因子最小为 6,所以实际的最大频率为72MHz / 6 = 12MHz

在这里插入图片描述

那么在哪里可以配置 ADC 预分频因子呢?注意,并不在 ADC 相关的寄存器中配置,而是在与 RCC 相关的寄存器进行配置。在寄存器RCC_CFGRADCPRE[1:0]可以配置 ADC 预分频因子。

ADC 需要若干个 ADC_CLK 周期才能完成对输入模拟量的采样,因此采样时间可由 n
个 ADC_CLK 周期来表示,即采样的周期数。我们可以通过两个采样时间寄存器ADC_SMPRx(x=1, 2) 来配置(如下表所示),位SMPx[2:0] (x=0-17)用来配置采样的周期。其中寄存器ADC_SMPR2控制的是通道 0~9,寄存器ADC_SMPR1控制的是通道 10~17。这意味着每个通道都可以采用不同的采样周期。

在这里插入图片描述

如上表所示,最快的采样周期为 1.5 个 ADC_CLK 周期,最慢的采样周期为 239.5 个 ADC_CLK 周期。而一个周期的时间一般为1 / 12MHz,所以最短的转换时间为:T(conv) = 采样时间 + 12.5个周期 = 1.5 + 12.5 = 14 个周期 = 14 *(1 / 12us) = 1.17us

六、数据寄存器

ADC将转换好的数据存放到数据寄存器中,规则组的数据存放到寄存器ADC_DR中,注入组的数据则存放到寄存器ADC_JDRx(x=1, 2, 3, 4)中。

1. 数据规则寄存器(ADC_DR)

在这里插入图片描述

对于独立模式,即只使用一个 ADC 的情况(即只使用 ADC1 或 ADC2 或 ADC3)下,由于 ADC 分辨率为 12 位,所以只使用寄存器的低16位中的12位,高16位就不使用了。 这12位数据可以左对齐,也可以右对齐,这是由寄存器ADC_CR2ALIGN来决定。

对于双ADC模式(ADC1和ADC2同时使用,注意ADC3是不能用于双ADC模式的),ADC2 的数据存放在寄存器的高16位,而 ADC1 的数据存放在寄存器的低16位。

由于数据规则寄存器只有一个,因此在使用多通道采集的时候寄存器的数据必然会被覆盖,一般的解决办法是采用DMA模式(ADC1和ADC3可用,2不可用),将转换结果转移进 DMA 中。

2. 数据注入寄存器(ADC_JDRx,x=1, 2, 3, 4)

在这里插入图片描述

和数据规则寄存器一样,由于 ADC 分辨率为 12 位,所以只使用寄存器的低16位中的12位,高16位就不使用了。 这12位数据可以左对齐,也可以右对齐,这是由寄存器ADC_CR2ALIGN来决定。

由于数据注入寄存器有 4 个,因此就不存在多通道采集时所产生的数据覆盖问题了。

七、中断

在这里插入图片描述

ADC能产生三种中断,这三种中断对应的标志事件是:转换结束(EOC)、注入转换结束(JEOC)、模拟看门狗事件(AWID),所对应的中断使能位是EOCIE、JEOCIE、AWIDIE。

这里说明一下模拟看门狗的作用:在某些情况下我们希望模拟电压达到一定阈值后就产生一次中断,可以用模拟看门狗来监测模拟电压是否达到这个阈值,如果是,那么就会发出一次中断请求。在 ADC看门狗高阈值寄存器(ADC_HTR)ADC看门狗低阈值寄存器(ADC_LRT) 可以设置这个阈值电压,两者均为低12位有效。

第二部分:ADC结构体和库函数

一、ADC初始化结构体

typedef struct
{
  uint32_t ADC_Mode; // ADC工作模式              

  FunctionalState ADC_ScanConvMode;   // ADC扫描(多通道)或单次(单通道)模式    

  FunctionalState ADC_ContinuousConvMode;  // ADC单次转换或连续转换

  uint32_t ADC_ExternalTrigConv; // ADC触发源选择     

  uint32_t ADC_DataAlign;  // ADC数据寄存器对齐格式             

  uint8_t ADC_NbrOfChannel;   // ADC采集通道数
  
}ADC_InitTypeDef;

1. 工作模式

在寄存器ADC_CR1DUALMOD[3:0]位可以配置ADC工作模式,下面来简要介绍每种模式(除了独立模式外,剩余的模式都属于双重模式,只能搭配ADC1/2):

  • 独立模式(ADC_Mode_Independent):ADC1/2/3 单独使用其中一个。
  • 同步规则模式(ADC_Mode_RegSimult):ADC1 和 ADC2 同时转换一个规则通道组,其中 ADC1 为主,ADC2 为从,ADC1 转换的结果放在ADC_DR低16位,ADC2 转换的结果放在ADC_DR的高16位。
  • 同步注入模式(ADC_Mode_InjecSimult):ADC1 和 ADC2 同时转换一个注入通道组,其中 ADC1 为主,ADC2 为从,ADC1 转换的结果放在各自的ADC_JDR
  • 快速交叉模式(ADC_Mode_FastInterl):ADC1 和 ADC2 交替采集一个规则通道组(通常为一个规则通道),当 ADC2 触发后,ADC1 需要等待 7 个 ADCCLK 之后才能触发。
  • 慢速交叉模式(ADC_Mode_SlowInterl):ADC1 和 ADC2 交替采集一个规则通道组(只能为一个规则通道),当 ADC2 触发后,ADC1 需要等待 14 个 ADCCLK 之后才能触发。
  • 交替触发模式(ADC_Mode_AlterTrig):ADC1 和 ADC2 轮流采集注入通道组,当 ADC1 采集完所有通道后,ADC2 再采集自己的通道,如此循环。
  • 混合的同步规则+注入同步模式(ADC_Mode_RegInjecSimult):规则组同步转换被中断,以启动注入组的同步转换。
  • 混合的同步规则+交替触发模式(ADC_Mode_RegSimult_AlterTrig):规则组同步转换被中断,以启动注入组的交替触发转换。
  • 混合同步注入+快速交叉模式(ADC_Mode_InjecSimult_FastInterl):快速交叉转换被中断,同步注入启动。
  • 混合同步注入+慢速交叉模式(ADC_Mode_InjecSimult_SlowInterl):慢速交叉转换被中断,同步注入启动。

其中,同步规则模式和快速交叉模式比较常用。

2. 扫描模式

在寄存器ADC_CR1SCAN位进行配置。

实际是一个使能位:选择单通道扫描(ENABLE)还是多通道扫描(DISABLE)。

3. 连续转换模式

在寄存器ADC_CR2CONV位进行配置。

实际是一个使能位:对通道选择采集一次(DISABLE)还是不停地重复采集(ENABLE)。

4. 外部触发源选择

寄存器ADC_CR2EXTSEL位和EXTTRIG位控制规则通道的触发源,寄存器ADC_CR2JEXTSEL位和JEXTTRIG位控制注入通道的触发源。

可参考功能框图讲解的第五节触发源。

5. 数据对齐格式

由寄存器ADC_CR2ALIGN来配置数据的左对齐或右对齐。

6. 采集通道数

由寄存器ADC_SQR1L[3:0]位或寄存器ADC_JSQRJL[1:0]位进行配置。

二、ADC常用库函数

以下为ADC常用的库函数:

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); // 软件触发
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); // 外部引脚触发
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC未完待续~

以上是关于STM32学习笔记(13)——模数转换ADC的主要内容,如果未能解决你的问题,请参考以下文章

stm32F103之ADC模数转换

STM32模数转换器ADC

STM32开发笔记103: 24位模数转换芯片ADS1258使用方法(概述)

STM32CubeMX学习笔记——ADC接口使用

STM32外设:信号转换器 ADCDAC

STM32学习笔记