实现目标
1、掌握ADC工作原理
2、掌握单片机驱动XPT2046 芯片
3、具体目标: 1、将单片机采集到的电压值在数码管显示; 2、将单片机采集到的电压值在LCD1602显示;3、将单片机采集到的电压值上传至上位机串口调试助手显示。
一、ADC概述
1.1 什么是ADC?
ADC(Analog to Digital Converter)即模数转换器,用来将模拟信号转换为数字信号。
A/D转换过程
1.2 ADC 的主要技术指标
1.2.1 分辨率
ADC 的分辨率是指对于允许范围内的模拟信号,它能输出离散数字信号值的 个数。这些信号值通常用二进制数来存储,因此分辨率经常用比特作为单位,且这些离散值的个数是 2 的幂指数。 例如:12 位 ADC 的分辨率就是 12 位,或者说分辨率为满刻度的 1/(2^12)。 一个 10V 满刻度的 12 位 ADC 能分辨输入电压变化最小值是 10V×1/(2 12 )=2.4mV。
1.2.2 转换误差
转换误差通常是以输出误差的最大值形式给出。它表示 A/D 转换器实际输出 的数字量和理论上的输出数字量之间的差别。常用最低有效位的倍数表示。例如 给出相对误差≤±LSB/2,这就表明实际输出的数字量和理论上应得到的输出数 字量之间的误差小于最低位的半个字。
1.2.3 转换速率
ADC 的转换速率是能够重复进行数据转换的速度,即每秒转换的次数。而完 成一次 A/D 转换所需的时间(包括稳定时间),则是转换速率的倒数。
1.3 ADC 转换原理
AD 转换器(ADC)将模拟量转换为数字量通常要经过 4 个步骤:采样、保持、 量化和编码。所谓采样即是将一个时间上连续变化的模拟量转换为时间上离散变 化的模拟量。如下图所示:
将采样结果存储起来,直到下次采样,这个过程叫做保持。一般采样器和保 持电路一起总称为采样保持电路。
将采样电平归化为与之接近的离散数字电平, PRECHIN 普中 www.prechin.net 336 这个过程叫做量化。
将量化后的结果按照一定数制形式表示就是编码。
将采样电 平(模拟值)转换为数字值时,主要有两类方法:直接比较型与间接比较型。
- **直接比较型:**就是将输入模拟信号直接与标准的参考电压比较,从而得到 数字量。常见的有并行 ADC 和逐次比较型 ADC。
- **间接比较型:**输入模拟量不是直接与参考电压比较,而是将二者变为中间 的某种物理量在进行比较,然后将比较所得的结果进行数字编码。常见的有双积 分型 ADC。
二、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。XPT2046 采用微小的封装形式:TSSOP-16,QFN-16 和 VFBGA-48。 工作温度范围为-40℃~+85℃。与 ADS7846、TSC2046、AK4182A 完全兼容。
2.1主要特性
①工作电压范围为 1.5V~5.25V
②支持 1.5V~5.25V 的数字 I/O 口
③内建 2.5V 参考电压源
④电源电压测量( 0V~6V)
⑤内建结温测量功能
⑥触摸压力测量
⑦采用 3 线制 SPI 通信接口
⑧具有自动省电功能
2.2 芯片管脚说明
2.3 单端和差分模式输入配置
X、Y、Z、VBAT、Temp 和 AUX 模拟信号经过片内 的控制寄存器选择后进入 ADC,ADC 可以配置为单端或差分模式。选择 VBAT、Temp 和 AUX 时应该配置为单端模式;作为触摸屏应用时,应该配置为差分模式,这可 有效消除由于驱动开关的寄生电阻及外部的干扰带来的测量误差,提高转换精度。
2.4 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 输入转换通道分别接入了 AD1 电位器、 NTC1 热敏传感器、GR1 光敏传感器,还有一个外接通道 AIN3 接在 DAC(PWM)模块的 J52 端子上供外部模拟信号检测。
注意:上图中 XPT2046 的 DOUT 脚与 DS18B20 温度传感器均连接到单片机的 P3.7,因此该两个外设资源不能同时使用,可以分时复用。
四、程序设计
4.1电位器电压采集(数码管显示)
实现的功能是:数码管上显示 AD 模块采集电位器的电压值。 程序框架如下: (1)编写数码管显示功能 (2)编写 ADC 转换函数 (3)编写主函数
(1)public.h 文件
cpp
#ifndef _public_H
#define _public_H
#include "reg52.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
typedef unsigned long u32;
void delay_10us(u16 ten_us);
void delay_ms(u16 ms);
#endif
(2)public.c 文件
cpp
#include "public.h"
/*******************************************************************************
* 函 数 名 : delay_10us
* 函数功能 : 延时函数,ten_us=1时,大约延时10us
* 输 入 : ten_us
* 输 出 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
/*******************************************************************************
* 函 数 名 : delay_ms
* 函数功能 : ms延时函数,ms=1时,大约延时1ms
* 输 入 : ms:ms延时时间
* 输 出 : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
u16 i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
(3)xpt2046.h 文件
cs
#ifndef _xpt2046_H
#define _xpt2046_H
#include "public.h"
//管脚定义
sbit DOUT = P3^7; //输出
sbit CLK = P3^6; //时钟
sbit DIN = P3^4; //输入
sbit CS = P3^5; //片选
//函数声明
u16 xpt2046_read_adc_value(u8 cmd);
#endif
(4)xpt2046.c 文件
cpp
#include "xpt2046.h"
#include "intrins.h"
/*******************************************************************************
* 函 数 名 : xpt2046_wirte_data
* 函数功能 : XPT2046写数据
* 输 入 : dat:写入的数据
* 输 出 : 无
*******************************************************************************/
void xpt2046_wirte_data(u8 dat)
{
u8 i;
CLK = 0;
_nop_();
for(i=0;i<8;i++)//循环8次,每次传输一位,共一个字节
{
DIN = dat >> 7;//先传高位再传低位
dat <<= 1;//将低位移到高位
CLK = 0;//CLK由低到高产生一个上升沿,从而写入数据
_nop_();
CLK = 1;
_nop_();
}
}
/*******************************************************************************
* 函 数 名 : xpt2046_read_data
* 函数功能 : XPT2046读数据
* 输 入 : 无
* 输 出 : XPT2046返回12位数据
*******************************************************************************/
u16 xpt2046_read_data(void)
{
u8 i;
u16 dat=0;
CLK = 0;
_nop_();
for(i=0;i<12;i++)//循环12次,每次读取一位,大于一个字节数,所以返回值类型是u16
{
dat <<= 1;
CLK = 1;
_nop_();
CLK = 0; //CLK由高到低产生一个下降沿,从而读取数据
_nop_();
dat |= DOUT;//先读取高位,再读取低位。
}
return dat;
}
/*******************************************************************************
* 函 数 名 : xpt2046_read_adc_value
* 函数功能 : XPT2046读AD数据
* 输 入 : cmd:指令
* 输 出 : XPT2046返回AD值
*******************************************************************************/
u16 xpt2046_read_adc_value(u8 cmd)
{
u8 i;
u16 adc_value=0;
CLK = 0;//先拉低时钟
CS = 0;//使能XPT2046
xpt2046_wirte_data(cmd);//发送命令字
for(i=6; i>0; i--);//延时等待转换结果
CLK = 1;
_nop_();
CLK = 0;//发送一个时钟,清除BUSY
_nop_();
adc_value=xpt2046_read_data();
CS = 1;//关闭XPT2046
return adc_value;
}
(5)smg.h 文件
cpp
#ifndef _smg_H
#define _smg_H
#include "public.h"
#define SMG_A_DP_PORT P0 //使用宏定义数码管段码口
//定义数码管位选信号控制脚
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
extern u8 gsmg_code[17];
void smg_display(u8 dat[],u8 pos);
#endif
(6)smg.c 文件
cpp
#include "smg.h"
//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
/*******************************************************************************
* 函 数 名 : smg_display
* 函数功能 : 动态数码管显示
* 输 入 : dat:要显示的数据
pos:从左开始第几个位置开始显示,范围1-8
* 输 出 : 无
*******************************************************************************/
void smg_display(u8 dat[],u8 pos)
{
u8 i=0;
u8 pos_temp=pos-1;
for(i=pos_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;
}
SMG_A_DP_PORT=dat[i-pos_temp];//传送段选数据
delay_10us(100);//延时一段时间,等待显示稳定
SMG_A_DP_PORT=0x00;//消音
}
}
(7)main.c 文件
cpp
/**************************************************************************************
实验名称:ADC模数转换实验--电位器电压采集
实验现象:下载程序后,数码管上显示AD模块采集电位器的电压值
***************************************************************************************/
#include "public.h"
#include "smg.h"
#include "xpt2046.h"
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
u16 adc_value=0;
float adc_vol;//ADC电压值
u8 adc_buf[3];
while(1)
{
adc_value=xpt2046_read_adc_value(0x94);//测量电位器
adc_vol=5.0*adc_value/4096;//将读取的AD值转换为电压
adc_value=adc_vol*10;//放大10倍,即保留小数点后一位
adc_buf[0]=gsmg_code[adc_value/10]|0x80;
adc_buf[1]=gsmg_code[adc_value%10];
adc_buf[2]=0x3e;//显示单位V
smg_display(adc_buf,6);
}
}
/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net
PRECHIN
普中
实验名称:ADC模数转换实验--电位器电压采集
接线说明:
实验现象:下载程序后,数码管上显示AD模块采集电位器的电压值
注意事项:
***************************************************************************************/
#include "public.h"
#include "smg.h"
#include "xpt2046.h"
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
u16 adc_value=0;
float adc_vol;//ADC电压值
u8 adc_buf[3];
while(1)
{
adc_value=xpt2046_read_adc_value(0x94);//测量电位器
adc_vol=5.0*adc_value/4096;//将读取的AD值转换为电压
adc_value=adc_vol*10;//放大10倍,即保留小数点后一位
adc_buf[0]=gsmg_code[adc_value/10]|0x80;
adc_buf[1]=gsmg_code[adc_value%10];
adc_buf[2]=0x3e;//显示单位V
smg_display(adc_buf,6);
}
}
4.2 电位器电压采集(LCD1602显示)
实现的功能是:LCD1602上显示 AD 模块采集电位器的电压值。 程序框架如下: (1)编写LCD1602显示功能 (2)编写 ADC 转换函数 (3)编写主函数
4.3 电位器电压采集(串口打印)
实现的功能是:串口打印 AD 模块采集电位器的电压值。 程序框架如下: (1)编写串口打印程序 (2)编写 ADC 转换函数 (3)编写主函数
五、实验效果
5.1 AD采样值数码管显示
说明: 调节电位器 AD1 时,数码管上显示的电压值也将变化