1.3.1 基本概念
1.转换精度
转换精度(Conversion accuracy)是指数字量变化一个最小量时对应模拟信号的变化量,也称为分辨率(Resolution),通常用模数转换器ADC的二进制位数来表征。
2.单端输入与差分输入
只使用一个输出引脚,使用公共地GND作为参考电平的叫做单端输入。而从微机的两个引脚接入模拟信号,AD采样值是两个引脚的电平差值叫做差分输入。
通常在AD转换编程时,把每一路模拟量称为一个通道(Channel),使用通道号(Channel number)表达哪个模拟量。这样,在单端输入情况,通道号与一个引脚对应,在差分输入情况,与两个引脚对应。在STM32L4系列芯片中,ADC 通道 0、 16、 17、 18 连接至单端外部模拟输入或内部通道,无对应引脚,因此其强制采用单端配置。
3.软件滤波问题
即使输入的模拟量保持不变,常常发现利用软件得到的AD值也不一致,其原因可能是电磁干扰,也可能是模数转换器ADC的本身转换误差,但是许多情况下,可以通过软件滤波(Filter)方法给予解决。
4.物理量回归问题
在实际应用中,得到稳定的AD值以后,还需要把AD值与实际物理量对应起来,这一步称为物理量回归(Regression)。
AD转换物理量回归问题,可以转化为数学上的一元回归分析(Regression analysis)问题,也就是一个自变量,一个因变量,寻找它们之间的逻辑关系。设AD值为x,实际物理量为y,物理量回归需要寻找它们之间的函数关系:y=f(x)。许多情况下,这种关系是非线性的,人工神经网络可以较好地应用于这种非线性回归分析中。
5.量化误差
在把模拟量转换为数字量过程中,要对模拟量进行采样和量化,使之转换成一定字长的数字量,量化误差(Quadratuer Error)就是指模拟量量化过程而产生的误差。
6.转换速度
转换速度通常表示完成一次AD转换花费的时间。在STM32L4系列芯片中,完成一次完整的AD转换时间是配置的采样时间与逐次逼近时间(具体取决于采样精度)的总和。例如,如果ADC的时钟频率为FADC_CLK,时钟周期为TADC_CLK。采样精度为12位时,逐次逼近时间固定为12.5个ADC时钟周期。其中采样时间可以由SMPx[2:0]寄存器控制,每个通道可以单独配置。计算转换时间TCONV为:
7.AD参考电压
AD转换需要一个参考电平。比如要把一个电压分成1024份,每一份的基准必须是稳定的,这个电平来自于基准电压,就是AD参考电压。
1.3.2 芯片ADC基本特征
ADC转换模块:模数转化模块,将电压信号转化为对应的数字信号。实际应用中,这个电压信号可能由温度、湿度、压力等实际物理量经过传感器和相应的变换电路转化而来。经过AD转化后,MCU就可以直接处理这些物理量。
STM32L431芯片共有19个通道,0号通道为内部电压监测通道,17号通道为内部温度监测通道,18号通道为内部电源监测通道,这三个通道为内部通道,没有对应的引脚。而且,通道16连接至单端外部模拟输入,因此0、16、17、18通道强制采用单端配置(相应的 DIFSEL[i] 位始终为零)
1.3.3 ADC编程基本步骤
本节将会通过直接地址对寄存器进行位操作,以实现ADC模块的初始化,并对13~15通道的ADC值进行读取。该部分程序的具体代码见“User_STM32_ADC_Simple_20200506”。在开始操作前,需要先定义相应的变量,以将需要用到的寄存器的基地址存在指定变量中,变量定义的语句如下。
vuint_32* RCC_BaseAddr; //RCC基地址 vuint_32* ADC1_BaseAddr; //ADC1模块基地址
RCC_BaseAddr=(vuint_32*)0x40021000; ADC1_BaseAddr=(vuint_32*)0x50040000;
//0x4002104c AHB2外设时钟使能寄存器基地址RCC->AHB2ENR vuint_32* RCC_AHB2ENR=(vuint_32*)(RCC_BaseAddr+0x13);
vuint_32* ADC1_ISR=(vuint_32*)ADC1_BaseAddr; //0x50040000 vuint_32* ADC1_CR=(vuint_32*)(ADC1_BaseAddr+0x2); //0x50040008 vuint_32* ADC1_CFGR=(vuint_32*)(ADC1_BaseAddr+0x3); //0x5004000C vuint_32* ADC1_SMPR1=(vuint_32*)(ADC1_BaseAddr+0x5); //0x50040014 vuint_32* ADC1_SMPR2=(vuint_32*)(ADC1_BaseAddr+0x6); //0x50040018 vuint_32* ADC1_SQR1=(vuint_32*)(ADC1_BaseAddr+0xC); //0x50040030 vuint_32* ADC1_DR=(vuint_32*)(ADC1_BaseAddr+0x10); //0x50040040 vuint_32* ADC1_DIFSEL=(vuint_32*)(ADC1_BaseAddr+0x2C); //0x500400B0 vuint_32* ADC1_CCR=(vuint_32*)(ADC1_BaseAddr+0xC2); //0x50040608 |
ADC1模块配置步骤如下所示。
1.初始化ADC模块
初始化adc的具体步骤如下所示。
1)开启ADC时钟,时钟频率=总线时钟/4,预分频系数为2
*RCC_AHB2ENR |= (1<<13); *ADC1_CCR |= (3<<16); |
2)退出掉电状态并使能稳压器,ADC默认处于掉电状态以降低功耗
*ADC1_CR &= ~(1<<29); *ADC1_CR |= (1<<28); |
3)初始化ADC控制寄存器,清零各个控制位
ADC1->CR &= 0x3fffffc0; |
4)单端差分选择,但0,16~18通道只能选择单端模式
*ADC1_DIFSEL&=~(1<<Channel); |
5)开启ADC
*ADC1_CR |= (1<<0); |
6)设置采样时间为12.5个时钟周期,0~9号通道使用SMPR1寄存器配置,10~18号通道使用SMPR2寄存器配置。而且,SMPx[2:0]从000~111分别对应6.5,12.5,24.5,47.5,92.5,247.5,640.5个ADC时钟周期。
if((int)Channel >= 0 && (int)Channel <= 9 ) { BCLR(Channel*3,*ADC1_SMPR1); BSET(Channel*3+1,*ADC1_SMPR1); BCLR(Channel*3+2,*ADC1_SMPR1); } if((int)Channel >= 10 && (int)Channel <= 18 ) { BCLR((Channel%10)*3,*ADC1_SMPR2); BSET((Channel%10)*3+1,*ADC1_SMPR2); BCLR((Channel%10)*3+2,*ADC1_SMPR2); } |
7)精度和数据对齐方式
精度和数据对齐方式由CFGR寄存器的RES[1:0],Align位决定(RES[1:0]即第3、4位,Align即第5位)。RES[1:0]从00~11分别对应精度位数为12,10,8,6。Align=0,则是右对齐,反之左对齐。默认配置即为12位精度,右对齐。
8)常规单次不连续转换模式
采用单次不连续模式读取ADC时,MCU每次只读一次通道值,可通过对多次ADC值取平均值减小误差。
*ADC1_CFGR |= (1<<16); //设置常规转换单次采集 *ADC1_CFGR &= ~(1<<13); //单次转换模式 *ADC1_CFGR &= ~(7<<17); //一个通道 *ADC1_CFGR &= ~(3<<10); //禁止硬件触发检测 |
9)常规通道序列长度为1
*ADC1_SQR1 &= ~(0xF<<0); |
2.读取指定通道adc
1)开启ADC,使能稳压器
*ADC1_CR |=((1<<0)|(1<<28)); |
2)所选通道加入单次转换序列中
在将所选通道加入单次转换序列之前需要将SQR1寄存器复位。如果要将x通道载入SQR1寄存器只需要通过“ADC1->SQR1 |= x<<6;”即可。
3)开始转换
*ADC1_CR |=(1<<2); |
4)等待转换完成
while(BGET(2,*ADC1_ISR)!=1); |
5)获取转换值
ADCResult = *ADC1_DR; printf(" Channel=%d, ADCResult =%d \n",Channel,ADCResult); |