51单片机ADC模数转换
ADC介绍
1、ADC简介
ADC(analog to digital converter)也称为模数转换器,是指一个将模拟信号转变为数字信号。单片机在采集模拟信号时,通常都需要在前端加上 A/D 芯 片。
2、技术指标
分辨率:ADC 的分辨率是指对于允许范围内的模拟信号,它能输出离散数字信号值的个数。
例如:12 位 ADC 的分辨率就是 12 位,或者说分辨率为满刻度的 1/(2^12)。 一个 10V 满刻度的 12 位 ADC 能分辨输入电压变化最小值是 10V×1/(212 )=2.4mV。
转换误差:转换误差通常是以输出误差的最大值形式给出。它表示 A/D 转换器实际输出 的数字量和理论上的输出数字量之间的差别。
转换速率:ADC 的转换速率是能够重复进行数据转换的速度,即每秒转换的次数。而完 成一次 A/D 转换所需的时间(包括稳定时间),则是转换速率的倒数。
3、ADC转换原理
AD 转换器(ADC)将模拟量转换为数字量通常要经过 4 个步骤:采样、保持、量化和编码。所谓采样即是将一个时间上连续变化的模拟量转换为时间上离散变化的模拟量。如下图所示:
将采样结果存储起来,直到下次采样,这个过程叫做保持。将采样电平归化为与之接近的离散数字电平, 这个过程叫做量化。将量化后的结果按照一定数制形式表示就是编码。将采样电 平(模拟值)转换为数字值时,主要有两类方法:直接比较型与间接比较型。直接比较型:就是将输入模拟信号直接与标准的参考电压比较,从而得到 数字量。常见的有并行 ADC 和逐次比较型 ADC。
间接比较型:输入模拟量不是直接与参考电压比较,而是将二者变为中间 的某种物理量在进行比较,然后将比较所得的结果进行数字编码。常见的有双积分型 ADC。
(1) 逐次逼近型 ADC
AD 转换器是有一个比较器、DA 转换器、缓冲寄存器和控 制逻辑电路组成,如下图所示:
基本原理:从高位到低位逐次试探比较,就像用天平秤物体,从重到轻逐级增减砝码进行试探。逐次逼近法的转换过程是:初始化时将逐次逼近寄存器各位清零,转换开始时,先将逐次逼近寄存器最高位置 1,送入 DA 转换器,经 DA 转换后生成的模拟量送入比较器,称为 U0,与送入比较器的待转换的模拟量 Ux 进行比较,若 U0<Ux,该位 1 被保留,否则清除。然后再将逐次逼近寄存器次高位置 1 ,将寄存器中新的数字量送 DA 转换器,输出的 10 再与 Ux 比较,若U0<Ux,该位 1 被保留,否则清除。重复此过程,直至逼近寄存器最低位。转换结束后,将逐次逼近寄存器中的数字量送入缓冲寄存器得到数字量的输出。逐次逼近的操作过程是在一个控制电路的控制下进行的。(2)双积分型 ADC
采用双积分法的 AD 转换器由电子开关、积分器、比较器和控制逻辑等部件组成。如下图所示:
基本原理:将输入电压变换成与其平均值成正比的时间间隔,再把此时间间隔转换成数字量,属于间接转换。双积分法 AD 转换的过程是:先将开关接通待转换的模拟量 Vi,Vi 采样输入到积分器,积分器从零开始进行固定时间 T 的正向积分,时间 T 到后,开关再接通与 Vi 极性相反的基准电压 Vref,将 Vref 输入到积分器,进行反向积分,直到输出为 0V 时停止积分。Vi 越大,积分器输出电压越大,反向积分时间也越长。计数器在反向积分时间内所计的数值,就是 输入模拟电压 Vi 所对应的数字量,实现了 AD 转换。
XPT2046芯片介绍
1、XPT2046芯片简介
XPT2046 是一款 4 线制电阻式触摸屏控制器,内含 12 位分辨率 125KHz 转换速率逐步逼近型 A/D 转换器。XPT2046 支持从 1.5V 到 5.25V 的低电压 I/O 接口。XPT2046 能通过执行两次 A/D 转换查出被按的屏幕位置,除此之外, 还可以测量加在触摸屏上的压力。内部自带 2.5V 参考电压,可以作为辅助输入、 温度测量和电池监测之用,电池监测的电压范围可以从 0V 到 6V。XPT2046 片内集成有一个温度传感器。在 2.7V 的典型工作状态下,关闭参考电压,功耗可 小于 0.75mW。
(1)芯片管脚
XPT2046 是一种典型的逐次逼近型模数转换器(SAR ADC),包含了采样/保持、模数转换、串口数据输出等功能。同时芯片集成有一个 2.5V 的内部参考电压源、温度检测电路,工作时使用外部时钟。XPT2046 可以单电源供电,电源电压范围为 2.7V~5.5V。参考电压值直接决定 ADC 的输入范围,参考电压可以 使用内部参考电压,也可以从外部直接输入 1V~VCC 范围内的参考电压(要求外部参考电压源输出阻抗低)。X、Y、Z、VBAT、Temp 和 AUX 模拟信号经过片内的控制寄存器选择后进入 ADC,ADC 可以配置为单端或差分模式。选择 VBAT、Temp 和 AUX 时应该配置为单端模式;作为触摸屏应用时,应该配置为差分模式,这可有效消除由于驱动开关的寄生电阻及外部的干扰带来的测量误差,提高转换精度。单端和差分模式输入配置如下图所示:
2、XPT2046芯片的读写时序
XPT2046 数据接口是串行接口,其典型工作时序如下图所示,图中展示的信号来自带有基本串行接口的单片机或数据信号处理器。处理器和转换器之间的的通信需要 8 个时钟周期,可采用 SPI、SSI 和 Microwire 等同步串行接口。一 次完整的转换需要 24 个串行同步时钟(DCLK)来完成。
前 8 个时钟用来通过 DIN 引脚输入控制字节。当转换器获取有关下一次转换的足够信息后,接着根据获得的信息设置输入多路选择器和参考源输入,并进 入采样模式,如果需要,将启动触摸面板驱动器。3 个多时钟周期后,控制字节设置完成,转换器进入转换状态。这时,输入采样-保持器进入保持状态,触摸面板驱动器停止工作(单端工作模式)。接着的 12 个时钟周期将完成真正的模数转换。如果是度量比率转换方式(SER/DFR=0),驱动器在转换过程中将一直 工作,第 13 个时钟将输出转换结果的最后一位。剩下的 3 个多时钟周期将用 来完成被转换器忽略的最后字节(DOUT 置低)。
在对 XPT2046 进行控制时,控制字节由 DIN 输入的控制字命令格式如下所示:
硬件原理
从上图中可以看出,该电路是集成的,XPT2046 芯片的控制管脚接至单片机 P3.4~P3.7 管脚上,XPT2046 芯片的 ADC 输入转换通道 AIN 分别接入了 AD1 电位器、 NTC1 热敏传感器、GR1 光敏传感器,还有一个外接通道 AIN3 接在 DAC(PWM)模 块的 J52 端子上供外部模拟信号检测。
注意:上图中 XPT2046 的 DOUT 脚与 DS18B20 温度传感器均连接到单片机的 P3.7,因此该两个外设资源不能同时使用,可以分时复用。文章来源:https://uudwc.com/A/eJMO
软件编写
程序框架如下:文章来源地址https://uudwc.com/A/eJMO
- 编写数码管显示功能
- 编写 ADC 转换函数
- 编写主函数
实验一:数码管上显示 AD 模块采集光敏电阻的AD值
#include <REGX52.H>
#include <intrins.h>
//使用宏定义数码管段码口
#define LED P0
//定义数码管位选信号控制脚
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
//XPT2046芯片管脚定义
sbit DIN=P3^4;
sbit CS=P3^5;
sbit DCLK=P3^6;
sbit DOUT=P3^7;
//共阴极数码管显示0~F的段码数据
unsigned char Smg_Code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void Delay(unsigned int x)
{
while(x--);
}
//动态数码管显示
void Smg_Display(unsigned char Data[],unsigned char Location)
{
unsigned char i=0;
unsigned char temp=Location-1;
for(i=temp;i<8;i++)
{
switch(i) //位选
{
case 0: LSC=1;LSB=1;LSA=1;break;
case 1: LSC=1;LSB=1;LSA=0;break;
case 2: LSC=1;LSB=0;LSA=1;break;
case 3: LSC=1;LSB=0;LSA=0;break;
case 4: LSC=0;LSB=1;LSA=1;break;
case 5: LSC=0;LSB=1;LSA=0;break;
case 6: LSC=0;LSB=0;LSA=1;break;
case 7: LSC=0;LSB=0;LSA=0;break;
}
LED=Data[i-temp]; //段码
Delay(100);
LED=0x00; //消影
}
}
//XPT2046写数据
void XPT2046_Write_Data(unsigned char Data)
{
unsigned char i=0;
DCLK=0;
_nop_();
for(i=0;i<8;i++) //循环8次,每次传输一位,共一个字节
{
DIN=Data>>7; //先传高位再传低位
Data<<=1; //将低位移到高位
DCLK=0; //DCLK由低位到高产生一个上升沿,从而写入数据
_nop_();
DCLK=1;
_nop_();
}
}
//XPT2046读数据
unsigned int XPT2046_Read_Data()
{
unsigned char i=0;
unsigned int Data=0;
DCLK=0;
_nop_();
for(i=0;i<8;i++) //循环12次,每次读取一位
{
Data<<=1;
DCLK=1;
_nop_();
DCLK=0; //DCLK由高到低产生一个下降沿,从而读取数据
_nop_();
Data|=DOUT; //先读取高位,再读取低位
}
return Data;
}
//XPT2036读取AD数据
unsigned int XPT2046(unsigned char Data)
{
unsigned int value=0;
DCLK=0; //先拉低时钟
CS=0; //使能(片选)XPT2046
XPT2046_Write_Data(Data); //发送寄存器命令字
DCLK=1;
_nop_();
DCLK=0; //发送一个时钟,清除BUSY
_nop_();
value=XPT2046_Read_Data();
CS=1; //关闭XPT2046
return value;
}
void main()
{
unsigned int value=0;
unsigned char buf[4];
while(1)
{
value=XPT2046(0xA4); //测量光敏电阻
buf[0]=Smg_Code[value/1000]; //分离四位数的每一位
buf[1]=Smg_Code[value%1000/100];
buf[2]=Smg_Code[value%1000%100/10];
buf[3]=Smg_Code[value%1000%100%10];
Smg_Display(buf,5); //数码管上显示光敏值
}
}
实验二:数码管上显示 AD 模块采集电位器的电压
//只需将实验一的主函数如下代码,其他不变。
void main()
{
unsigned int value=0;
unsigned char buf[3];
float fvalue=0;
while(1)
{
value=XPT2046(0x94); //测量电位器
fvalue=5.0*value/4096; //将读取的AD值转换位电压,见上文分辨率公式
value=fvalue*10; //放大10倍,即保留小数点后一位
buf[0]=Smg_Code[value/10]|0x80; //高位值加小数点
buf[1]=Smg_Code[value%10]; //小数位
buf[2]=0x3e //显示单位 v
Smg_Display(buf,6); //数码管上显示电压值
}
}
实验三:数码管上显示 AD 模块采集热敏电阻的AD值
//只需将实验一的主函数换成如下代码,其他不变。
void main()
{
unsigned int value=0;
unsigned char buf[4];
while(1)
{
value=XPT2046(0xD4); //测量热敏电阻
buf[0]=Smg_Code[value/1000]; //分离四位数的每一位
buf[1]=Smg_Code[value%1000/100];
buf[2]=Smg_Code[value%1000%100/10];
buf[3]=Smg_Code[value%1000%100%10];
Smg_Display(buf,5); //数码管上显示热敏值
}
}