1.ADC简介
模数转换器(Analog-to-Digital Converter,简称ADC)是一种重要的电子设备,它能够将模拟信号转换为数字信号。是一种将连续变化的模拟信号转换为离散的数字信号的电子设备。这种转换使得模拟信号可以在数字系统中进行处理、存储和传输。
ADC的工作原理通常包括采样、保持、量化和编码四个步骤:
采样:在采样阶段,ADC使用一定的时间间隔对模拟信号进行采样,从而得到一系列离散的信号样本。
保持:在保持阶段,ADC将采样得到的信号样本保持一段时间,以便进行后续的量化操作。
量化:在量化阶段,ADC将连续变化的模拟信号幅度转换为有限数量的离散值。这些离散值通常是以二进制形式表示的。
编码:在编码阶段,ADC将量化后的离散值转换为数字信号,并输出到数字系统中。
2.ADC性能
分辨率:分辨率表示ADC能够分辨的最小模拟信号电平值,通常以位数(bit)来表示。位数越多,ADC的分辨率越高,能够转换的模拟信号范围越广。
采样率:采样率表示ADC每秒钟能够采样的次数,通常以每秒采样点数(SPS)或兆每秒采样点数(MSPS)来表示。采样率越高,ADC能够捕获的模拟信号细节越多。
信噪比(SNR):SNR是衡量ADC转换过程中噪声干扰程度的指标。SNR越高,表示ADC转换过程中的噪声越小,转换精度越高。
ADC有多种类型和结构,常见的包括逐次逼近型ADC、计数/斜率积分型ADC、并联比较型ADC以及Σ-Δ(Sigma-delta)ADC等:
逐次逼近型ADC:逐次逼近型ADC通过不断地将采样输入信号与已知电压进行比较,逐步逼近输入信号的实际值。这种ADC具有结构简单、功耗低等优点,但采样率可能受到限制。
计数/斜率积分型ADC:计数/斜率积分型ADC使用积分器将输入模拟电压转换为时间间隔,并使用计数器对这个时间间隔进行计数。这种ADC具有抑制交流噪声干扰的能力,适用于嘈杂的工业环境。
并联比较型ADC:并联比较型ADC使用一系列互连的比较器和电压参考来生成特定分辨率的等效输出代码。这种ADC具有转换速度快、结构简单的优点,但可能需要较多的比较器和精密电阻网络。
Σ-Δ ADC:Σ-Δ ADC通过积分器、比较器、1位DA转换器和数字滤波器组成。它使用高频时钟信号对输入信号进行调制和采样,并通过数字滤波器对采样结果进行滤波和解调。这种ADC具有高精度、低噪声等优点,适用于高精度数据采集领域。
3.应用领域
ADC在电子和计算机工程领域具有广泛的应用,包括但不限于以下几个方面:
通信领域:ADC用于将模拟语音信号转换为数字信号进行传输和处理。
数据处理领域:ADC用于将模拟信号转换为数字信号以便进行数字信号处理和分析。
自动化控制领域:ADC用于将传感器输出的模拟信号转换为数字信号以便进行自动化控制。
音频和视频处理领域:ADC用于将音频和视频信号转换为数字信号以便进行数字音频和视频处理。
综上所述,ADC是一种重要的电子设备,在电子和计算机工程领域具有广泛的应用前景。随着技术的不断发展,ADC的性能将不断提高,应用领域也将不断拓展。
4.STM32F10X系列中的外设ADC
在STM32中是12位ADC,一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
其ADC框图如下:
ADC转换组分为规则组转换和注入组转换两种。有16个多路通道。可以把转换组织成两组:规则组和注入组。在任意多个通道上以任意顺序进行的一系列转换构成成组转换。例如,可以如下顺序完成转换:通道3、通道8、通道2、通道2、通道0、通道2、通道2、通道15。
- 规则组由多达16个转换组成。规则通道和它们的转换顺序在ADC_SQRx寄存器中选择。规
则组中转换的总数应写入ADC_SQR1寄存器的L[3:0]位中。 - 注入组由多达4个转换组成。注入通道和它们的转换顺序在ADC_JSQR寄存器中选择。注入
组里的转换总数目应写入ADC_JSQR寄存器的L[1:0]位中。
如果ADC_SQRx或ADC_JSQR寄存器在转换期间被更改,当前的转换被清除,一个新的启动脉冲将发送到ADC以转换新选择的组。
4.1 采样周期
ADC使用若干个ADC_CLK周期对输入电压采样,采样周期数目可以通过ADC_SMPR1和ADC_SMPR2寄存器中的SMP[2:0]位更改。每个通道可以分别用不同的时间采样。
总转换时间如下计算:
TCONV = 采样时间+ 12.5个周期
- 例如:
当ADCCLK=14MHz,采样时间为1.5周期
TCONV = 1.5 + 12.5 = 14周期 = 1μs
4.2 ADC配置步骤
1.配置ADC通道引脚,设置工作模式为模拟输入。
2.使能ADC时钟,设置工作频率不超过14MHZ。
3.设置通道采样周期。
4.设置要转换的通道,以及转换的通道个数
5.若需要多通道转换,则开始扫描模式;若需要循环转换,则开启连续转换模式和自动注入转换。
6.启动ADC,初始化ADC校准寄存器,等待校准完成。
7.开启ADC转换。
- 代码配置实现如下:
/*
ADC规则通道初始化
ADC_IN8 --PB0
*/
void ADC1_RegulerInit(void)
{
//1.配置引脚
RCC->APB2ENR|=1<<3;
GPIOB->CRL&=0xFFFFFFF0;//配置为模拟输入
//2.配置ADC时钟
RCC->APB2ENR|=1<<9;//ADC1时钟
RCC->APB2RSTR|=1<<9;
RCC->APB2RSTR&=~(1<<9);
RCC->CFGR&=~(0x3<<14);
RCC->CFGR|=0x2<<14;//设置ADC工作频率:72MHZ/6=12MHZ
//3配置ADC的规则组转换
ADC1->CR2|=1<<23;//启动内存温度传感器
ADC1->CR2|=1<<20;//选择外部事件启动
ADC1->CR2|=0x7<<17;//选择软件触发
//设置通道信息
ADC1->SMPR1|=7<<18;//设置通道16的采用周期
ADC1->SMPR2|=7<<24;//设置通道8采样周期
ADC1->CR2|=1<<0;//启动ADC1
ADC1->CR2|=1<<3;//初始化校准寄存器
while(ADC1->CR2&1<<3){}//等待初始化完成
ADC1->CR2|=1<<2;//开始校准
while(ADC1->CR2&1<<2);//等待校准完成
}
本次使用ADC1的通道8,采集光照强度数据,其光强模块硬件原理图如下:
通道16为STM32内部温度传感器,其温度转换算法如下:
温度传感器在内部和ADC1_IN16输入通道相连接,此通道把传感器输出的电压转换成数字值。温度传感器模拟输入推荐采样时间是17.1μs。
读温度
- 选择ADC1_IN16输入通道
- 选择采样时间为17.1 μs
- 设置ADC控制寄存器2(ADC_CR2)的TSVREFE位,以唤醒关电模式下的温度传感器
- 通过设置ADON位启动ADC转换(或用外部触发)
- 读ADC数据寄存器上的VSENSE 数据结果
- 利用下列公式得出温度
温度(°C) = {(V25 - VSENSE) / Avg_Slope} + 25
- 相关参数
V25 = VSENSE在25°C时的数值
Avg_Slope = 温度与VSENSE曲线的平均斜率(单位为mV/ °C 或 μV/ °C)
](https://i-blog.csdnimg.cn/direct/4e7db606a74e47e2bc192776462d9601.png)
4.3 读取AD通道值
/*
规则通道启动一次转换
形参:chx --要转换的通道
返回值:通道采集的AD值
*/
u16 ADC1_GetRegChx(u8 chx)
{
ADC1->SQR1&=~(0xF<<20);//转换序列为1
ADC1->SQR3&=~(0x1F<<0);
ADC1->SQR3|=chx;//设置要转换的通道
ADC1->CR2|=1<<22;//启动转换
while(!(ADC1->SR&1<<1)){}//等待转换完成
u16 data=ADC1->DR;//读取转换的AD值
return data;
}
4.4 光强和温度采集示例
#include "stm32f10x.h"
#include "beep.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "usart1.h"
#include "timer.h"
#include "adc.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
u8 rtc_menu_cnt=0;
int main()
{
Beep_Init();//蜂鸣器器初始化
LED_Init();//LED
Key_Init();
USARTx_Init(USART1,115200);//一个字符的收发时间:1s/(115200/10)=86us
TIMx_Init(TIM2,72,10000);//工作频率:72MHZ/72=1MHZ
//10000*(1/1)us=10ms
USARTx_Init(USART3,115200);//串口3配置
u16 temp=0;
ADC1_RegulerInit();//ADC规则通道初始化
float cpu_temp=0;
while(1)
{
if(usart1_flag)
{
usart1_buffer[usart1_cnt]='\0';
printf("rx1=%s,%d\n",usart1_buffer,usart1_cnt);
usart1_cnt=0;
usart1_flag=0;
}
LED1=!LED1;
temp=DS18B20_GetTemp();//读取温度
printf("temp=%.1f\n",temp*0.0625);
//采集光强
temp=ADC1_GetRegChx(8);
printf("光强:%d\n",temp);
//采集内部温度
temp=ADC1_GetRegChx(16);
/*
温度(°C) = {(V25 - VSENSE) / Avg_Slope} + 25
Avg_Slope=4.3mV/℃-->0.0043V/℃
V25=1.43V
VSENSE --温度传感器采集的AD值对应的电压
ADC分辨率:0~4095
参考电压:0~3.3V
温度传感器采集的对应的电压: temp*3.3/4095;
*/
cpu_temp=(1.43-temp*3.3/4095)/0.0043+25;
printf("内部温度:ad:%d Temp=%.2f ℃\n",temp,cpu_temp);
Delay_Ms(1000);
}
}