一、前言
本次DEMO目标:
本文将使用STM32F103ZET6的ADC1通道1来采样外部电压值,并使用串口在上位机XCOM上打印出电压值。
二、模数转换原理与基本概念
2.1 ADC基本概念
模数转换器(ADC,Analog-to-Digital Converter)是一种将模拟信号转换为数字信号的电子器件。它的主要功能是将连续的模拟电压或电流信号转换成可以由数字系统(如微控制器或计算机)处理的离散数字值。在现代电子系统中,ADC广泛应用于数据采集、通信、音频和视频处理、传感器接口等领域。
2.2 ADC的工作原理
ADC的核心任务是将连续变化的模拟信号量化为有限的数字值,主要步骤包括:
- 采样:ADC周期性地对模拟信号进行采样,在每个采样点获取信号的瞬时电压值。
- 保持:在每次采样后,ADC会保持这个电压值直到量化和转换完成。
- 量化:将采样的模拟值映射到对应的数字值。ADC的量化精度由其分辨率决定,通常用位(bit)来表示。比如一个10位的ADC可以将输入信号量化为2^10(即1024)个离散的数字值。
- 编码:最终的数字值会以二进制的形式输出,供数字系统进行处理。
2.3 常见的ADC类型
常见的ADC类型可以分为并行比较型ADC和逐次逼近型ADC。二者的对比如下所示:
特性 | 并行比较型ADC | 逐次逼近型ADC |
---|---|---|
速度 | 极高,适合高速应用 | 适中,适合大多数中速应用 |
精度 | 通常为6-8位 | 通常为10-16位 |
功耗 | 高功耗 | 较低功耗 |
电路复杂度 | 高,比较器数量随位数迅速增加 | 低,电路实现相对简单 |
典型应用 | 雷达、视频处理、示波器、通信 | 传感器接口、音频处理、数据采集 |
2.3.1 并行比较型ADC
Flash ADC 是目前最快的模数转换器,其工作原理基于比较器并行工作,因此称为“并行比较型ADC”。Flash ADC使用多个电压比较器同时比较输入电压和一系列参考电压值。
Flash ADC使用一个由多个比较器组成的阵列,每个比较器对应不同的参考电压。输入模拟信号被同时送到所有比较器,比较器将输入信号与其参考电压进行比较。当输入电压高于某个参考电压时,比较器输出为高电平(1),低于参考电压时,输出为低电平(0)。输出结果形成一个“热码”(thermometer code),然后通过编码器将其转换为对应的二进制码,输出数字值。
2.3.2 逐次逼近型ADC
逐次逼近型ADC(SAR ADC,Successive Approximation Register ADC)是目前广泛应用的一种模数转换器。它通过一种逐步逼近的方式,在多次比较后确定输入信号的数字值。其工作步骤如下:
- ADC首先将输入信号与参考电压的一半进行比较。
- 根据比较结果,SAR寄存器确定最高位是1还是0。
- 然后继续对剩下的低位进行比较,每一步都将范围缩小,逐步逼近输入信号的实际值,直到完成所有位数的确定。
2.4 ADC的相关参数
在选择和使用模数转换器(ADC,Analog-to-Digital Converter)时,有几个关键参数决定了其性能和适用场景。这些参数不仅影响转换精度、速度和功耗,还会决定ADC在实际应用中的表现。这些参数主要包括分辨率、输入电压、转换时间、参考电压。下面将对这些参数进行一一介绍。
2.4.1 分辨率
ADC的分辨率指的是转换输出的二进制位数,决定了ADC可以将模拟信号分成多少个离散的数字值。分辨率越高,ADC能够表示的电压范围越精细。常见的分辨率有8位、10位、12位、14位、16位甚至24位。分辨率越高,量化误差越小,ADC的输出越精确。对于12位ADC,它可以将输入电压分成2^12 = 4096个离散的数字值。
2.4.2 输入电压
输入电压是指ADC能够正确处理的输入信号电压范围。它通常由ADC的内部参考电压或外部参考电压决定。输入范围可能是0V到参考电压(如3.3V或5V),也可能是双极性范围(如-5V到5V)。如果输入信号超出ADC的输入范围,可能会导致信号的饱和或失真,因此需要选择合适的ADC来匹配信号电压范围。
2.4.3 转换时间
转换时间是ADC完成一次完整的模数转换所需的时间。它决定了ADC的反应速度。在实时系统中,转换时间直接影响系统的响应时间。对于需要快速反应的应用(如自动控制),需要较短的转换时间。
2.4.4 参考电压
参考电压Vref是用于ADC进行量化的基准电压。ADC的输入范围和转换精度通常与参考电压直接相关。精确稳定的参考电压对于ADC的高精度转换至关重要。若参考电压不稳定,可能导致ADC输出误差增大。输入电压应在0-Vref之间或-Vref-Vref之间。
三、STM32模数转换ADC介绍
STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器 。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。
STM32F103ZET6包含有 3 个 ADC。 STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us(在 ADCCLK=14M,采样周期为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降。
在STM32的ADC(模数转换器)中,通道被分为两种主要的组:规则通道组和注入通道组。它们的主要功能是用来采集模拟信号,并在一定的时序下进行转换。这两类通道组的设计是为了满足不同的应用场景:规则通道组用于常规的ADC转换。它可以包含多个通道,按照用户定义的顺序逐个采样;注入通道组主要用于优先级较高的任务,比如在规则通道采样过程中,某些特殊的信号需要被立即采样处理。二者的对比如下表所示:
属性 | 规则通道组 | 注入通道组 |
---|---|---|
优先级 | 较低 | 较高 |
触发方式 | 软件或硬件触发 | 主要为硬件触发,部分支持软件触发 |
应用场景 | 普通的传感器信号采集 | 实时性要求较高的采样 |
转换顺序 | 用户定义,按顺序采样 | 用户定义,按顺序采样 |
中断触发 | 支持转换完成中断 | 支持转换完成中断 |
四、时钟树分析
由于ADC时钟不能超过14MHz,故本文设定ADC时钟为12MHz。系统时钟为72MHz,AHB不分频为72MHz,APB2不分频为72MHz,ADC分频器6分频,ADCCLK即为72/6=12MHz。具体时钟树分析如下所示:
五、寄存器介绍
对ADC1的控制主要涉及以下寄存器:
寄存器 | 作用 |
---|---|
ADC_CR1 | ADC控制器1 |
ADC_CR2 | ADC控制器2 |
ADC_SMPR2 | ADC采样时间寄存器2 |
ADC_SQR1 | ADC规则序列寄存器1 |
ADC_SQR3 | ADC规则序列寄存器3 |
ADC_DR | ADC规则数据寄存器 |
ADC_SR | ADC状态寄存器 |
下面将对这些寄存器进行一一介绍
5.1 ADC_CR1控制器1
《STM32中文参考手册》对ADC_CR1寄存器的描述如下:
这里我们仅关注[19:16]DUALMOD和[8]SCAN。本文将[19:16]DUALMOD设置为0000独立模式;将[8]SCAN设置为0关闭扫描模式,如果分别设置了EOCIE或JEOCIE位,那么只有在最后一个通道转换完毕后才会产生EOC或JEOC中断。
5.2 ADC_CR2控制器2
《STM32中文参考手册》对ADC_CR2寄存器的描述如下:
0 1 2 3 11
该寄存器功能较多,我们需关注[22]SWSTART、[20]EXTTRIG、[19:17]EXTSEL、[11]ALIGN、[3] RETCAL、[2]CAL、[1]CONT以及[0]ADON。
[22]SWSTART
该位置1以开始转换规则通道。如果在EXTSEL[2:0]位中选择了SWSTART为触发事件,该位用于启动一组规则通道的转换。
[20]EXTTRIG
该位置1可以使用外部事件启动转换。
[19:17]EXTSEL
该位置111,选择启动规则通道组转换的外部事件为SWSTART。
[11]ALIGN
该位置0数据右对齐。
[3] RETCAL
该位软件置1初始化校准寄存器,在校准寄存器被初始化后该位由硬件清除为0。
[2]CAL
该位软件置1开始校准AD,校准结束时由硬件清除为0。
[1]CONT
该位置1设置为单次转换模式。
[0]ADON
该位设置为1开启ADC并启动转换。
5.3 ADC_SMPR2采样时间寄存器2
《STM32中文参考手册》对ADC_SMPR2寄存器的描述如下:
对于每个要转换的通道,采样时间建议尽量长一点,以获得较高的准确度,但是这样会降低 ADC 的转换速率。ADC 的转换时间可以由以下公式计算:Tcovn=采样时间+12.5 个周期其中:Tcovn 为总转换时间,采样时间是根据每个通道的 SMP 位的设置来决定的。例如,当 ADCCLK=14Mhz 的时候,并设置 1.5 个周期的采样时间,则得到:Tcovn=1.5+12.5=14 个周期=1us由于我们使用的是PA1(ADC1_IN1),故仅需关注该寄存器的[2:0]位,我们将其设置为111,即239.5周期,较长的采样时间可以提升采样的精确度。
5.4 ADC_SQR1规则序列寄存器
《STM32中文参考手册》对ADC_SQR1寄存器的描述如下:
我们仅需关注该寄存器的[23:20]规则通道序列长度, 本次DEMO只用了一个ADC1_CH1,故L[3:0]设置为0000,即1个转换。
5.5 ADC_SQR3规则序列寄存器
《STM32中文参考手册》对ADC_SQR3寄存器的描述如下:
我们仅需关注该寄存器的[4:0],将规则序列中的第一个转换设置为ADC1_CH1,即1.
5.6 ADC_DR规则数据寄存器
《STM32中文参考手册》对ADC_DR寄存器的描述如下:
AD转化结果都被保存在这个寄存器中,值得注意的是,该寄存器的数据可以通过ADC_CR2的ALIGN位设置左对齐还是右对齐。
5.7 ADC_SR状态寄存器
《STM32中文参考手册》对ADC_SR寄存器的描述如下:
我们仅需关注其EOC位,当通道转换结束时,由软件清除或由读取ADC_DR时清除。
六、程序设计
本文的程序设计主要分为ADC1_CH1初始化、ADC数据读取、均值滤波以及轮询主函数。下面进行一一介绍。
6.1 ADC1_CH1初始化
该函数位于HARDWARE/adc.c/Adc_Init();主要作用是设置PA1复用、使能ADC时钟、设置ADC工作模式、校准并复位ADC。具体代码如下所示:
//初始化ADC1
//这里我们仅以规则通道为例
//我们默认仅开启通道1
void Adc_Init(void)
{ //先初始化IO口RCC->APB2ENR|=1<<2; //使能PORTA口时钟 GPIOA->CRL&=0XFFFFFF0F;//PA1 anolog输入 RCC->APB2ENR|=1<<9; //ADC1时钟使能 RCC->APB2RSTR|=1<<9; //ADC1复位RCC->APB2RSTR&=~(1<<9);//复位结束 RCC->CFGR&=~(3<<14); //分频因子清零 //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!//否则将导致ADC准确度下降! RCC->CFGR|=2<<14; ADC1->CR1&=0XF0FFFF; //工作模式清零ADC1->CR1|=0<<16; //独立工作模式 ADC1->CR1&=~(1<<8); //非扫描模式 ADC1->CR2&=~(1<<1); //单次转换模式ADC1->CR2&=~(7<<17); ADC1->CR2|=7<<17; //软件控制转换 ADC1->CR2|=1<<20; //使用用外部触发(SWSTART)!!! 必须使用一个事件来触发ADC1->CR2&=~(1<<11); //右对齐 ADC1->SQR1&=~(0XF<<20);ADC1->SQR1|=0<<20; //1个转换在规则序列中 也就是只转换规则序列1 //设置通道1的采样时间ADC1->SMPR2&=~(3*1); //通道1采样时间清空 ADC1->SMPR2|=7<<(3*1); //通道1 239.5周期,提高采样时间可以提高精确度 ADC1->CR2|=1<<0; //开启AD转换器 ADC1->CR2|=1<<3; //使能复位校准 while(ADC1->CR2&1<<3); //等待复位结束 //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。 ADC1->CR2|=1<<2; //开启AD校准 while(ADC1->CR2&1<<2); //等待校准结束//该位由软件设置以开始校准,并在校准结束时由硬件清除
}
6.2 ADC数据读取
该函数位于HARDWARE/adc.c/Get_Adc();主要作用是读取ADC通道的数值。具体代码如下所示:
//获得ADC1某个通道的值
//ch:通道值 0~16
//返回值:转换结果
u16 Get_Adc(u8 ch)
{//设置转换序列 ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道chADC1->SQR3|=ch; ADC1->CR2|=1<<22; //启动规则转换通道 while(!(ADC1->SR&1<<1));//等待转换结束 return ADC1->DR; //返回adc值
}
6.3 均值滤波
该函数位于HARDWARE/adc.c/Get_Adc_Average();主要作用是对多次采集得到的ADC数据进行均值滤波,具体代码如下所示:
//获取通道ch的转换值,取times次,然后平均
//ch:通道编号
//times:获取次数
//返回值:通道ch的times次转换结果平均值
u16 Get_Adc_Average(u8 ch,u8 times)
{u32 temp_val=0;u8 t;for(t=0;t<times;t++){temp_val+=Get_Adc(ch);delay_ms(5);}return temp_val/times;
}
6.4 轮询主函数
该函数位于USER/test.c;主要作用是对原始ADC数据转换为实际电压值,并通过串口打印在上位机XCOM上。具体代码如下所示:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "adc.h"
//ALIENTEK精英STM32F103开发板实验17
//ADC 实验
//技术支持:www.openedv.com
//广州市星翼电子科技有限公司 int main(void)
{ u16 adcx;float temp; Stm32_Clock_Init(9); //系统时钟设置uart_init(72,115200); //串口初始化为115200delay_init(72); //延时初始化 Adc_Init(); //ADC初始化 while(1){adcx=Get_Adc_Average(ADC_CH1,10);temp=(float)adcx*(3.3/4096);printf("电压值为:%4.3fV\r\n",temp);}
}
七、上机实验
将代码烧录进STM32F103ZET6,通过观察XCOM上位机可以看到ADC1_CH1采集到的电压。如下图所示:
至此本次demo已完成!